Skip to content

Commit 848f5af

Browse files
Merge remote-tracking branch 'origin/main' into logger_handeled
2 parents 598fb07 + 5a75ad9 commit 848f5af

File tree

10 files changed

+125
-41
lines changed

10 files changed

+125
-41
lines changed

api/auth/user/UserRestHandler.go

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ func (handler UserRestHandlerImpl) CreateUser(w http.ResponseWriter, r *http.Req
191191
}
192192
//RBAC enforcer Ends
193193

194-
res, err := handler.userService.CreateUser(&userInfo, token, handler.CheckManagerAuth)
194+
res, restrictedGroups, err := handler.userService.CreateUser(&userInfo, token, handler.CheckManagerAuth)
195195
if err != nil {
196196
handler.logger.Errorw("service err, CreateUser", "err", err, "payload", userInfo)
197197
if _, ok := err.(*util.ApiError); ok {
@@ -203,7 +203,22 @@ func (handler UserRestHandlerImpl) CreateUser(w http.ResponseWriter, r *http.Req
203203
return
204204
}
205205

206-
common.WriteJsonResp(w, err, res, http.StatusOK)
206+
if len(restrictedGroups) == 0 {
207+
common.WriteJsonResp(w, err, res, http.StatusOK)
208+
} else {
209+
errorMessageForGroupsWithoutSuperAdmin, errorMessageForGroupsWithSuperAdmin := helper.CreateErrorMessageForUserRoleGroups(restrictedGroups)
210+
211+
if len(restrictedGroups) != len(userInfo.UserRoleGroup) {
212+
// warning
213+
message := fmt.Errorf("User permissions added partially. %s%s", errorMessageForGroupsWithoutSuperAdmin, errorMessageForGroupsWithSuperAdmin)
214+
common.WriteJsonResp(w, message, nil, http.StatusExpectationFailed)
215+
216+
} else {
217+
//error
218+
message := fmt.Errorf("Permission could not be added. %s%s", errorMessageForGroupsWithoutSuperAdmin, errorMessageForGroupsWithSuperAdmin)
219+
common.WriteJsonResp(w, message, nil, http.StatusBadRequest)
220+
}
221+
}
207222
}
208223

209224
func (handler UserRestHandlerImpl) UpdateUser(w http.ResponseWriter, r *http.Request) {
@@ -252,16 +267,16 @@ func (handler UserRestHandlerImpl) UpdateUser(w http.ResponseWriter, r *http.Req
252267
if len(restrictedGroups) == 0 {
253268
common.WriteJsonResp(w, err, res, http.StatusOK)
254269
} else {
255-
groups := strings.Join(restrictedGroups, ", ")
270+
errorMessageForGroupsWithoutSuperAdmin, errorMessageForGroupsWithSuperAdmin := helper.CreateErrorMessageForUserRoleGroups(restrictedGroups)
256271

257272
if rolesChanged || groupsModified {
258273
// warning
259-
message := fmt.Errorf("User permissions updated partially. Group(s): " + groups + " could not be added/removed. You do not have manager permission for some or all projects in these groups.")
274+
message := fmt.Errorf("User permissions updated partially. %s%s", errorMessageForGroupsWithoutSuperAdmin, errorMessageForGroupsWithSuperAdmin)
260275
common.WriteJsonResp(w, message, nil, http.StatusExpectationFailed)
261276

262277
} else {
263278
//error
264-
message := fmt.Errorf("Permission could not be added/removed: You do not have manager permission for some or all projects in group(s): " + groups + ".")
279+
message := fmt.Errorf("Permission could not be added/removed. %s%s", errorMessageForGroupsWithoutSuperAdmin, errorMessageForGroupsWithSuperAdmin)
265280
common.WriteJsonResp(w, message, nil, http.StatusBadRequest)
266281
}
267282
}

api/bean/UserRequest.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,11 @@ type RoleGroupListingResponse struct {
131131
TotalCount int `json:"totalCount"`
132132
}
133133

134+
type RestrictedGroup struct {
135+
Group string
136+
HasSuperAdminPermission bool
137+
}
138+
134139
type ListingRequest struct {
135140
SearchKey string `json:"searchKey"`
136141
SortOrder bean.SortOrder `json:"sortOrder"`

pkg/apiToken/ApiTokenService.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ func (impl ApiTokenServiceImpl) CreateApiToken(request *openapi.CreateApiTokenRe
206206
EmailId: email,
207207
UserType: bean.USER_TYPE_API_TOKEN,
208208
}
209-
createUserResponse, err := impl.userService.CreateUser(&createUserRequest, token, managerAuth)
209+
createUserResponse, _, err := impl.userService.CreateUser(&createUserRequest, token, managerAuth)
210210
if err != nil {
211211
impl.logger.Errorw("error while creating user for api-token", "email", email, "error", err)
212212
return nil, err

pkg/auth/user/UserService.go

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ const (
5151
)
5252

5353
type UserService interface {
54-
CreateUser(userInfo *bean.UserInfo, token string, managerAuth func(resource, token string, object string) bool) ([]*bean.UserInfo, error)
54+
CreateUser(userInfo *bean.UserInfo, token string, managerAuth func(resource, token string, object string) bool) ([]*bean.UserInfo, []bean.RestrictedGroup, error)
5555
SelfRegisterUserIfNotExists(userInfo *bean.UserInfo) ([]*bean.UserInfo, error)
56-
UpdateUser(userInfo *bean.UserInfo, token string, managerAuth func(resource, token string, object string) bool) (*bean.UserInfo, bool, bool, []string, error)
56+
UpdateUser(userInfo *bean.UserInfo, token string, managerAuth func(resource, token string, object string) bool) (*bean.UserInfo, bool, bool, []bean.RestrictedGroup, error)
5757
GetById(id int32) (*bean.UserInfo, error)
5858
GetAll() ([]bean.UserInfo, error)
5959
GetAllWithFilters(request *bean.ListingRequest) (*bean.UserListingResponse, error)
@@ -276,33 +276,34 @@ func (impl *UserServiceImpl) saveUser(userInfo *bean.UserInfo, emailId string) (
276276
return userInfo, nil
277277
}
278278

279-
func (impl *UserServiceImpl) CreateUser(userInfo *bean.UserInfo, token string, managerAuth func(resource, token string, object string) bool) ([]*bean.UserInfo, error) {
279+
func (impl *UserServiceImpl) CreateUser(userInfo *bean.UserInfo, token string, managerAuth func(resource, token string, object string) bool) ([]*bean.UserInfo, []bean.RestrictedGroup, error) {
280280

281281
var pass []string
282282
var userResponse []*bean.UserInfo
283+
var restrictedGroups []bean.RestrictedGroup
283284
emailIds := strings.Split(userInfo.EmailId, ",")
284285
for _, emailId := range emailIds {
285286
dbUser, err := impl.userRepository.FetchActiveOrDeletedUserByEmail(emailId)
286287
if err != nil && err != pg.ErrNoRows {
287288
impl.logger.Errorw("error while fetching user from db", "error", err)
288-
return nil, err
289+
return nil, nil, err
289290
}
290291

291292
//if found, update it with new roles
292293
if dbUser != nil && dbUser.Id > 0 {
293294
userInfo, err = impl.updateUserIfExists(userInfo, dbUser, emailId, token, managerAuth)
294295
if err != nil {
295296
impl.logger.Errorw("error while create user if exists in db", "error", err)
296-
return nil, err
297+
return nil, nil, err
297298
}
298299
}
299300

300301
// if not found, create new user
301302
if err == pg.ErrNoRows {
302-
userInfo, err = impl.createUserIfNotExists(userInfo, emailId, token, managerAuth)
303+
userInfo, restrictedGroups, err = impl.createUserIfNotExists(userInfo, emailId, token, managerAuth)
303304
if err != nil {
304305
impl.logger.Errorw("error while create user if not exists in db", "error", err)
305-
return nil, err
306+
return nil, nil, err
306307
}
307308
}
308309

@@ -312,7 +313,7 @@ func (impl *UserServiceImpl) CreateUser(userInfo *bean.UserInfo, token string, m
312313
userResponse = append(userResponse, &bean.UserInfo{Id: userInfo.Id, EmailId: emailId, Groups: userInfo.Groups, RoleFilters: userInfo.RoleFilters, SuperAdmin: userInfo.SuperAdmin, UserRoleGroup: userInfo.UserRoleGroup})
313314
}
314315

315-
return userResponse, nil
316+
return userResponse, restrictedGroups, nil
316317
}
317318

318319
func (impl *UserServiceImpl) updateUserIfExists(userInfo *bean.UserInfo, dbUser *repository.UserModel, emailId string,
@@ -340,20 +341,20 @@ func (impl *UserServiceImpl) updateUserIfExists(userInfo *bean.UserInfo, dbUser
340341
return userInfo, nil
341342
}
342343

343-
func (impl *UserServiceImpl) createUserIfNotExists(userInfo *bean.UserInfo, emailId string, token string, managerAuth func(resource string, token string, object string) bool) (*bean.UserInfo, error) {
344+
func (impl *UserServiceImpl) createUserIfNotExists(userInfo *bean.UserInfo, emailId string, token string, managerAuth func(resource string, token string, object string) bool) (*bean.UserInfo, []bean.RestrictedGroup, error) {
344345
// if not found, create new user
345346
dbConnection := impl.userRepository.GetConnection()
346347
tx, err := dbConnection.Begin()
347348
if err != nil {
348-
return nil, err
349+
return nil, nil, err
349350
}
350351
// Rollback tx on error.
351352
defer tx.Rollback()
352353

353354
_, err = impl.validateUserRequest(userInfo)
354355
if err != nil {
355356
err = &util.ApiError{HttpStatusCode: http.StatusBadRequest, UserMessage: "Invalid request, please provide role filters"}
356-
return nil, err
357+
return nil, nil, err
357358
}
358359

359360
//create new user in our db on d basis of info got from google api or hex. assign a basic role
@@ -375,24 +376,30 @@ func (impl *UserServiceImpl) createUserIfNotExists(userInfo *bean.UserInfo, emai
375376
InternalMessage: "failed to create new user in db",
376377
UserMessage: fmt.Sprintf("requested by %d", userInfo.UserId),
377378
}
378-
return nil, err
379+
return nil, nil, err
379380
}
380381
userInfo.Id = model.Id
381382
//loading policy for safety
382383
casbin2.LoadPolicy()
383384

385+
var restrictedGroups []bean.RestrictedGroup
386+
384387
//Starts Role and Mapping
385388
capacity, mapping := impl.userCommonService.GetCapacityForRoleFilter(userInfo.RoleFilters)
386389
//var policies []casbin2.Policy
387390
var policies = make([]casbin2.Policy, 0, capacity)
388391
if userInfo.SuperAdmin == false {
392+
isActionPerformingUserSuperAdmin, err := impl.IsSuperAdmin(int(userInfo.UserId))
393+
if err != nil {
394+
return nil, nil, err
395+
}
389396
for index, roleFilter := range userInfo.RoleFilters {
390397
impl.logger.Infow("Creating Or updating User Roles for RoleFilter ")
391398
entity := roleFilter.Entity
392399
policiesToBeAdded, _, err := impl.CreateOrUpdateUserRolesForAllTypes(roleFilter, userInfo.UserId, model, nil, token, managerAuth, tx, entity, mapping[index])
393400
if err != nil {
394401
impl.logger.Errorw("error in creating user roles for Alltypes", "err", err)
395-
return nil, err
402+
return nil, nil, err
396403
}
397404
policies = append(policies, policiesToBeAdded...)
398405

@@ -402,29 +409,34 @@ func (impl *UserServiceImpl) createUserIfNotExists(userInfo *bean.UserInfo, emai
402409
for _, item := range userInfo.UserRoleGroup {
403410
userGroup, err := impl.roleGroupRepository.GetRoleGroupByName(item.RoleGroup.Name)
404411
if err != nil {
405-
return nil, err
412+
return nil, nil, err
413+
}
414+
hasAccessToGroup, hasSuperAdminPermission := impl.checkGroupAuth(userGroup.CasbinName, token, managerAuth, isActionPerformingUserSuperAdmin)
415+
if hasAccessToGroup {
416+
policies = append(policies, casbin2.Policy{Type: "g", Sub: casbin2.Subject(userInfo.EmailId), Obj: casbin2.Object(userGroup.CasbinName)})
417+
} else {
418+
restrictedGroup := adapter.CreateRestrictedGroup(item.RoleGroup.Name, hasSuperAdminPermission)
419+
restrictedGroups = append(restrictedGroups, restrictedGroup)
406420
}
407-
//object := "group:" + strings.ReplaceAll(item, " ", "_")
408-
policies = append(policies, casbin2.Policy{Type: "g", Sub: casbin2.Subject(emailId), Obj: casbin2.Object(userGroup.CasbinName)})
409421
}
410422
// END GROUP POLICY
411423
} else if userInfo.SuperAdmin == true {
412424

413425
isSuperAdmin, err := impl.IsSuperAdmin(int(userInfo.UserId))
414426
if err != nil {
415-
return nil, err
427+
return nil, nil, err
416428
}
417429
if isSuperAdmin == false {
418430
err = &util.ApiError{HttpStatusCode: http.StatusForbidden, UserMessage: "Invalid request, not allow to update super admin type user"}
419-
return nil, err
431+
return nil, nil, err
420432
}
421433
flag, err := impl.userAuthRepository.CreateRoleForSuperAdminIfNotExists(tx, userInfo.UserId)
422434
if err != nil || flag == false {
423-
return nil, err
435+
return nil, nil, err
424436
}
425437
roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes("", "", "", "", bean2.SUPER_ADMIN, "", "", "", "", "", "", "", false, "")
426438
if err != nil {
427-
return nil, err
439+
return nil, nil, err
428440
}
429441
if roleModel.Id > 0 {
430442
userRoleModel := &repository.UserRoleModel{UserId: model.Id, RoleId: roleModel.Id, AuditLog: sql.AuditLog{
@@ -435,7 +447,7 @@ func (impl *UserServiceImpl) createUserIfNotExists(userInfo *bean.UserInfo, emai
435447
}}
436448
userRoleModel, err = impl.userAuthRepository.CreateUserRoleMapping(userRoleModel, tx)
437449
if err != nil {
438-
return nil, err
450+
return nil, nil, err
439451
}
440452
policies = append(policies, casbin2.Policy{Type: "g", Sub: casbin2.Subject(model.EmailId), Obj: casbin2.Object(roleModel.Role)})
441453
}
@@ -450,11 +462,11 @@ func (impl *UserServiceImpl) createUserIfNotExists(userInfo *bean.UserInfo, emai
450462
//Ends
451463
err = tx.Commit()
452464
if err != nil {
453-
return nil, err
465+
return nil, nil, err
454466
}
455467
//loading policy for syncing orchestrator to casbin with newly added policies
456468
casbin2.LoadPolicy()
457-
return userInfo, nil
469+
return userInfo, restrictedGroups, nil
458470
}
459471

460472
func (impl *UserServiceImpl) CreateOrUpdateUserRolesForAllTypes(roleFilter bean.RoleFilter, userId int32, model *repository.UserModel, existingRoles map[int]repository.UserRoleModel, token string, managerAuth func(resource string, token string, object string) bool, tx *pg.Tx, entity string, capacity int) ([]casbin2.Policy, bool, error) {
@@ -634,7 +646,7 @@ func (impl UserServiceImpl) mergeUserRoleGroup(oldUserRoleGroups []bean.UserRole
634646
return finalUserRoleGroups
635647
}
636648

637-
func (impl *UserServiceImpl) UpdateUser(userInfo *bean.UserInfo, token string, managerAuth func(resource, token string, object string) bool) (*bean.UserInfo, bool, bool, []string, error) {
649+
func (impl *UserServiceImpl) UpdateUser(userInfo *bean.UserInfo, token string, managerAuth func(resource, token string, object string) bool) (*bean.UserInfo, bool, bool, []bean.RestrictedGroup, error) {
638650
//checking if request for same user is being processed
639651
isLocked := impl.getUserReqLockStateById(userInfo.Id)
640652
if isLocked {
@@ -698,7 +710,7 @@ func (impl *UserServiceImpl) UpdateUser(userInfo *bean.UserInfo, token string, m
698710
var eliminatedPolicies []casbin2.Policy
699711
capacity, mapping := impl.userCommonService.GetCapacityForRoleFilter(userInfo.RoleFilters)
700712
var addedPolicies = make([]casbin2.Policy, 0, capacity)
701-
restrictedGroups := []string{}
713+
restrictedGroups := []bean.RestrictedGroup{}
702714
rolesChanged := false
703715
groupsModified := false
704716
//loading policy for safety
@@ -767,13 +779,13 @@ func (impl *UserServiceImpl) UpdateUser(userInfo *bean.UserInfo, token string, m
767779
newGroupMap[userGroup.CasbinName] = userGroup.CasbinName
768780
if _, ok := oldGroupMap[userGroup.CasbinName]; !ok {
769781
//check permission for new group which is going to add
770-
hasAccessToGroup := impl.checkGroupAuth(userGroup.CasbinName, token, managerAuth, isActionPerformingUserSuperAdmin)
782+
hasAccessToGroup, hasSuperAdminPermission := impl.checkGroupAuth(userGroup.CasbinName, token, managerAuth, isActionPerformingUserSuperAdmin)
771783
if hasAccessToGroup {
772784
groupsModified = true
773785
addedPolicies = append(addedPolicies, casbin2.Policy{Type: "g", Sub: casbin2.Subject(userInfo.EmailId), Obj: casbin2.Object(userGroup.CasbinName)})
774786
} else {
775-
trimmedGroup := strings.TrimPrefix(item.RoleGroup.Name, "group:")
776-
restrictedGroups = append(restrictedGroups, trimmedGroup)
787+
restrictedGroup := adapter.CreateRestrictedGroup(item.RoleGroup.Name, hasSuperAdminPermission)
788+
restrictedGroups = append(restrictedGroups, restrictedGroup)
777789
}
778790
}
779791
}
@@ -783,15 +795,15 @@ func (impl *UserServiceImpl) UpdateUser(userInfo *bean.UserInfo, token string, m
783795
if item != bean.SUPERADMIN {
784796
//check permission for group which is going to eliminate
785797
if strings.HasPrefix(item, "group:") {
786-
hasAccessToGroup := impl.checkGroupAuth(item, token, managerAuth, isActionPerformingUserSuperAdmin)
798+
hasAccessToGroup, hasSuperAdminPermission := impl.checkGroupAuth(item, token, managerAuth, isActionPerformingUserSuperAdmin)
787799
if hasAccessToGroup {
788800
if strings.HasPrefix(item, "group:") {
789801
groupsModified = true
790802
}
791803
eliminatedPolicies = append(eliminatedPolicies, casbin2.Policy{Type: "g", Sub: casbin2.Subject(userInfo.EmailId), Obj: casbin2.Object(item)})
792804
} else {
793-
trimmedGroup := strings.TrimPrefix(item, "group:")
794-
restrictedGroups = append(restrictedGroups, trimmedGroup)
805+
restrictedGroup := adapter.CreateRestrictedGroup(item, hasSuperAdminPermission)
806+
restrictedGroups = append(restrictedGroups, restrictedGroup)
795807
}
796808
}
797809
}
@@ -1672,15 +1684,20 @@ func (impl *UserServiceImpl) saveUserAudit(r *http.Request, userId int32) {
16721684
impl.userAuditService.Save(userAudit)
16731685
}
16741686

1675-
func (impl *UserServiceImpl) checkGroupAuth(groupName string, token string, managerAuth func(resource, token string, object string) bool, isActionUserSuperAdmin bool) bool {
1687+
func (impl *UserServiceImpl) checkGroupAuth(groupName string, token string, managerAuth func(resource, token string, object string) bool, isActionUserSuperAdmin bool) (bool, bool) {
16761688
//check permission for group which is going to add/eliminate
16771689
roles, err := impl.roleGroupRepository.GetRolesByGroupCasbinName(groupName)
16781690
if err != nil && err != pg.ErrNoRows {
16791691
impl.logger.Errorw("error while fetching user from db", "error", err)
1680-
return false
1692+
return false, false
16811693
}
16821694
hasAccessToGroup := true
1695+
hasSuperAdminPermission := false
16831696
for _, role := range roles {
1697+
if role.Role == bean.SUPERADMIN && !isActionUserSuperAdmin {
1698+
hasAccessToGroup = false
1699+
hasSuperAdminPermission = true
1700+
}
16841701
if role.AccessType == bean.APP_ACCESS_TYPE_HELM && !isActionUserSuperAdmin {
16851702
hasAccessToGroup = false
16861703
}
@@ -1699,7 +1716,7 @@ func (impl *UserServiceImpl) checkGroupAuth(groupName string, token string, mana
16991716
}
17001717

17011718
}
1702-
return hasAccessToGroup
1719+
return hasAccessToGroup, hasSuperAdminPermission
17031720
}
17041721

17051722
func (impl *UserServiceImpl) GetRoleFiltersByUserRoleGroups(userRoleGroups []bean.UserRoleGroup) ([]bean.RoleFilter, error) {

pkg/auth/user/adapter/adapter.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package adapter
22

33
import (
4+
"github.com/devtron-labs/devtron/api/bean"
45
"github.com/devtron-labs/devtron/pkg/auth/user/repository"
6+
"strings"
57
"time"
68
)
79

@@ -12,3 +14,11 @@ func GetLastLoginTime(model repository.UserModel) time.Time {
1214
}
1315
return lastLoginTime
1416
}
17+
18+
func CreateRestrictedGroup(roleGroupName string, hasSuperAdminPermission bool) bean.RestrictedGroup {
19+
trimmedGroup := strings.TrimPrefix(roleGroupName, "group:")
20+
return bean.RestrictedGroup{
21+
Group: trimmedGroup,
22+
HasSuperAdminPermission: hasSuperAdminPermission,
23+
}
24+
}

0 commit comments

Comments
 (0)