From 0e7001536df812139974c600978f55475555f086 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 3 Nov 2023 14:07:46 +0530 Subject: [PATCH 01/76] jobs rbac create update user and role group flow --- api/bean/UserRequest.go | 1 + pkg/user/RoleGroupService.go | 266 +++++++++++------- pkg/user/UserCommonService.go | 202 +++++++------- pkg/user/UserFlows_test.go | 2 +- pkg/user/UserService.go | 281 ++++++++++++++------ pkg/user/bean/bean.go | 3 +- pkg/user/repository/RbacDataCacheFactory.go | 1 + pkg/user/repository/UserAuthRepository.go | 29 +- pkg/user/repository/bean.go | 2 + 9 files changed, 515 insertions(+), 272 deletions(-) diff --git a/api/bean/UserRequest.go b/api/bean/UserRequest.go index 2ad7046141..f8b47d2636 100644 --- a/api/bean/UserRequest.go +++ b/api/bean/UserRequest.go @@ -66,6 +66,7 @@ type RoleFilter struct { Group string `json:"group"` Kind string `json:"kind"` Resource string `json:"resource"` + Workflow string `json:"workflow"` } type Role struct { diff --git a/pkg/user/RoleGroupService.go b/pkg/user/RoleGroupService.go index 78456b0faa..63e57af46a 100644 --- a/pkg/user/RoleGroupService.go +++ b/pkg/user/RoleGroupService.go @@ -126,58 +126,26 @@ func (impl RoleGroupServiceImpl) CreateRoleGroup(request *bean.RoleGroup) (*bean for index, roleFilter := range request.RoleFilters { roleFilter = impl.userCommonService.ReplacePlaceHolderForEmptyEntriesInRoleFilter(roleFilter) entity := roleFilter.Entity - if roleFilter.Entity == bean.CLUSTER_ENTITIY { + if entity == bean.CLUSTER_ENTITIY { policiesToBeAdded, err := impl.CreateOrUpdateRoleGroupForClusterEntity(roleFilter, request.UserId, model, nil, "", nil, tx, mapping[index]) policies = append(policies, policiesToBeAdded...) if err != nil { + // making it non-blocking as it is being done for multiple Role filters and does not want this to be blocking. impl.logger.Errorw("error in creating updating role group for cluster entity", "err", err, "roleFilter", roleFilter) } + } else if entity == bean2.EntityJobs { + policiesToBeAdded, err := impl.CreateOrUpdateRoleGroupForJobsEntity(roleFilter, request.UserId, model, nil, "", nil, tx, mapping[index]) + policies = append(policies, policiesToBeAdded...) + if err != nil { + // making it non-blocking as it is being done for multiple Role filters and does not want this to be blocking. + impl.logger.Errorw("error in creating updating role group for jobs entity", "err", err, "roleFilter", roleFilter) + } } else { - actionType := roleFilter.Action - accessType := roleFilter.AccessType - entityNames := strings.Split(roleFilter.EntityName, ",") - environments := strings.Split(roleFilter.Environment, ",") - for _, environment := range environments { - for _, entityName := range entityNames { - entityName = impl.userCommonService.RemovePlaceHolderInRoleFilterField(entityName) - environment = impl.userCommonService.RemovePlaceHolderInRoleFilterField(environment) - roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", "", false) - if err != nil { - impl.logger.Errorw("error in getting new role model") - return nil, err - } - if roleModel.Id == 0 { - if roleFilter.Entity == bean2.ENTITY_APPS || roleFilter.Entity == bean.CHART_GROUP_ENTITY { - flag, err, policiesAdded := impl.userCommonService.CreateDefaultPoliciesForAllTypes(roleFilter.Team, entityName, environment, entity, "", "", "", "", "", actionType, accessType, request.UserId) - if err != nil || flag == false { - return nil, err - } - policies = append(policies, policiesAdded...) - roleModel, err = impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", "", false) - if err != nil { - return nil, err - } - if roleModel.Id == 0 { - request.Status = bean2.RoleNotFoundStatusPrefix + roleFilter.Team + "," + environment + "," + entityName + "," + actionType - continue - } - } else { - continue - } - } - if roleModel.Id > 0 { - roleGroupMappingModel := &repository2.RoleGroupRoleMapping{RoleGroupId: model.Id, RoleId: roleModel.Id} - roleGroupMappingModel.CreatedBy = request.UserId - roleGroupMappingModel.UpdatedBy = request.UserId - roleGroupMappingModel.CreatedOn = time.Now() - roleGroupMappingModel.UpdatedOn = time.Now() - roleGroupMappingModel, err = impl.roleGroupRepository.CreateRoleGroupRoleMapping(roleGroupMappingModel, tx) - if err != nil { - return nil, err - } - policies = append(policies, casbin2.Policy{Type: "g", Sub: casbin2.Subject(model.CasbinName), Obj: casbin2.Object(roleModel.Role)}) - } - } + policiesToBeAdded, err := impl.CreateOrUpdateRoleGroupForOtherEntity(roleFilter, request, model, nil, "", nil, tx, mapping[index]) + policies = append(policies, policiesToBeAdded...) + if err != nil { + // making it non-blocking as it is being done for multiple Role filters and does not want this to be blocking. + impl.logger.Errorw("error in creating updating role group for apps entity", "err", err, "roleFilter", roleFilter) } } } @@ -221,18 +189,18 @@ func (impl RoleGroupServiceImpl) CreateOrUpdateRoleGroupForClusterEntity(roleFil continue } } - roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, "", "", "", "", accessType, roleFilter.Cluster, namespace, group, kind, resource, actionType, false) + roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, "", "", "", "", accessType, roleFilter.Cluster, namespace, group, kind, resource, actionType, false, "") if err != nil { impl.logger.Errorw("error in getting new role model by filter") return policiesToBeAdded, err } if roleModel.Id == 0 { - flag, err, policiesAdded := impl.userCommonService.CreateDefaultPoliciesForAllTypes("", "", "", entity, roleFilter.Cluster, namespace, group, kind, resource, actionType, accessType, userId) + flag, err, policiesAdded := impl.userCommonService.CreateDefaultPoliciesForAllTypes("", "", "", entity, roleFilter.Cluster, namespace, group, kind, resource, actionType, accessType, "", userId) if err != nil || flag == false { return policiesToBeAdded, err } policiesToBeAdded = append(policiesToBeAdded, policiesAdded...) - roleModel, err = impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, "", "", "", "", accessType, roleFilter.Cluster, namespace, group, kind, resource, actionType, false) + roleModel, err = impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, "", "", "", "", accessType, roleFilter.Cluster, namespace, group, kind, resource, actionType, false, "") if err != nil { return policiesToBeAdded, err } @@ -265,6 +233,120 @@ func (impl RoleGroupServiceImpl) CreateOrUpdateRoleGroupForClusterEntity(roleFil return policiesToBeAdded, nil } +func (impl RoleGroupServiceImpl) CreateOrUpdateRoleGroupForOtherEntity(roleFilter bean.RoleFilter, request *bean.RoleGroup, model *repository2.RoleGroup, existingRoles map[int]*repository2.RoleGroupRoleMapping, token string, managerAuth func(resource string, token string, object string) bool, tx *pg.Tx, capacity int) ([]casbin2.Policy, error) { + actionType := roleFilter.Action + accessType := roleFilter.AccessType + entity := roleFilter.Entity + entityNames := strings.Split(roleFilter.EntityName, ",") + environments := strings.Split(roleFilter.Environment, ",") + var policiesToBeAdded = make([]casbin2.Policy, 0, capacity) + for _, environment := range environments { + for _, entityName := range entityNames { + entityName = impl.userCommonService.RemovePlaceHolderInRoleFilterField(entityName) + environment = impl.userCommonService.RemovePlaceHolderInRoleFilterField(environment) + roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", "", false, "") + if err != nil { + impl.logger.Errorw("error in getting new role model") + return nil, err + } + if roleModel.Id == 0 { + request.Status = bean2.RoleNotFoundStatusPrefix + roleFilter.Team + "," + environment + "," + entityName + "," + actionType + if roleFilter.Entity == bean2.ENTITY_APPS || roleFilter.Entity == bean.CHART_GROUP_ENTITY { + flag, err, policiesAdded := impl.userCommonService.CreateDefaultPoliciesForAllTypes(roleFilter.Team, entityName, environment, entity, "", "", "", "", "", actionType, accessType, "", request.UserId) + if err != nil || flag == false { + return nil, err + } + policiesToBeAdded = append(policiesToBeAdded, policiesAdded...) + roleModel, err = impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", "", false, "") + if err != nil { + return nil, err + } + if roleModel.Id == 0 { + request.Status = bean2.RoleNotFoundStatusPrefix + roleFilter.Team + "," + environment + "," + entityName + "," + actionType + continue + } + } else { + continue + } + } + if _, ok := existingRoles[roleModel.Id]; ok { + //Adding policies which are removed + policiesToBeAdded = append(policiesToBeAdded, casbin2.Policy{Type: "g", Sub: casbin2.Subject(model.CasbinName), Obj: casbin2.Object(roleModel.Role)}) + } else { + if roleModel.Id > 0 { + roleGroupMappingModel := &repository2.RoleGroupRoleMapping{RoleGroupId: model.Id, RoleId: roleModel.Id} + roleGroupMappingModel.CreatedBy = request.UserId + roleGroupMappingModel.UpdatedBy = request.UserId + roleGroupMappingModel.CreatedOn = time.Now() + roleGroupMappingModel.UpdatedOn = time.Now() + roleGroupMappingModel, err = impl.roleGroupRepository.CreateRoleGroupRoleMapping(roleGroupMappingModel, tx) + if err != nil { + return nil, err + } + policiesToBeAdded = append(policiesToBeAdded, casbin2.Policy{Type: "g", Sub: casbin2.Subject(model.CasbinName), Obj: casbin2.Object(roleModel.Role)}) + } + } + } + } + return policiesToBeAdded, nil +} + +func (impl RoleGroupServiceImpl) CreateOrUpdateRoleGroupForJobsEntity(roleFilter bean.RoleFilter, userId int32, model *repository2.RoleGroup, existingRoles map[int]*repository2.RoleGroupRoleMapping, token string, managerAuth func(resource string, token string, object string) bool, tx *pg.Tx, capacity int) ([]casbin2.Policy, error) { + actionType := roleFilter.Action + accessType := roleFilter.AccessType + entity := roleFilter.Entity + entityNames := strings.Split(roleFilter.EntityName, ",") + environments := strings.Split(roleFilter.Environment, ",") + workflows := strings.Split(roleFilter.Workflow, ",") + var policiesToBeAdded = make([]casbin2.Policy, 0, capacity) + for _, environment := range environments { + for _, entityName := range entityNames { + for _, workflow := range workflows { + entityName = impl.userCommonService.RemovePlaceHolderInRoleFilterField(entityName) + environment = impl.userCommonService.RemovePlaceHolderInRoleFilterField(environment) + workflow = impl.userCommonService.RemovePlaceHolderInRoleFilterField(workflow) + roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", "", false, workflow) + if err != nil { + impl.logger.Errorw("error in getting new role model") + return nil, err + } + if roleModel.Id == 0 { + flag, err, policiesAdded := impl.userCommonService.CreateDefaultPoliciesForAllTypes(roleFilter.Team, entityName, environment, entity, "", "", "", "", "", actionType, accessType, workflow, userId) + if err != nil || flag == false { + return nil, err + } + policiesToBeAdded = append(policiesToBeAdded, policiesAdded...) + roleModel, err = impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", "", false, workflow) + if err != nil { + return nil, err + } + if roleModel.Id == 0 { + continue + } + } + if _, ok := existingRoles[roleModel.Id]; ok { + //Adding policies which are removed + policiesToBeAdded = append(policiesToBeAdded, casbin2.Policy{Type: "g", Sub: casbin2.Subject(model.CasbinName), Obj: casbin2.Object(roleModel.Role)}) + } else { + if roleModel.Id > 0 { + roleGroupMappingModel := &repository2.RoleGroupRoleMapping{RoleGroupId: model.Id, RoleId: roleModel.Id} + roleGroupMappingModel.CreatedBy = userId + roleGroupMappingModel.UpdatedBy = userId + roleGroupMappingModel.CreatedOn = time.Now() + roleGroupMappingModel.UpdatedOn = time.Now() + roleGroupMappingModel, err = impl.roleGroupRepository.CreateRoleGroupRoleMapping(roleGroupMappingModel, tx) + if err != nil { + return nil, err + } + policiesToBeAdded = append(policiesToBeAdded, casbin2.Policy{Type: "g", Sub: casbin2.Subject(model.CasbinName), Obj: casbin2.Object(roleModel.Role)}) + } + } + } + } + } + return policiesToBeAdded, nil +} + func (impl RoleGroupServiceImpl) UpdateRoleGroup(request *bean.RoleGroup, token string, managerAuth func(resource, token string, object string) bool) (*bean.RoleGroup, error) { dbConnection := impl.roleGroupRepository.GetConnection() tx, err := dbConnection.Begin() @@ -339,57 +421,21 @@ func (impl RoleGroupServiceImpl) UpdateRoleGroup(request *bean.RoleGroup, token continue } } - - actionType := roleFilter.Action - accessType := roleFilter.AccessType - entity := roleFilter.Entity - entityNames := strings.Split(roleFilter.EntityName, ",") - environments := strings.Split(roleFilter.Environment, ",") - for _, environment := range environments { - for _, entityName := range entityNames { - entityName = impl.userCommonService.RemovePlaceHolderInRoleFilterField(entityName) - environment = impl.userCommonService.RemovePlaceHolderInRoleFilterField(environment) - roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", "", false) + switch roleFilter.Entity { + case bean2.EntityJobs: + { + policiesToBeAdded, err := impl.CreateOrUpdateRoleGroupForJobsEntity(roleFilter, request.UserId, roleGroup, existingRoles, token, managerAuth, tx, mapping[index]) + policies = append(policies, policiesToBeAdded...) if err != nil { - return nil, err - } - if roleModel.Id == 0 { - request.Status = bean2.RoleNotFoundStatusPrefix + roleFilter.Team + "," + environment + "," + entityName + "," + actionType - if roleFilter.Entity == bean2.ENTITY_APPS || roleFilter.Entity == bean.CHART_GROUP_ENTITY { - flag, err, policiesAdded := impl.userCommonService.CreateDefaultPoliciesForAllTypes(roleFilter.Team, entityName, environment, entity, "", "", "", "", "", actionType, accessType, request.UserId) - policies = append(policies, policiesAdded...) - if err != nil || flag == false { - return nil, err - } - roleModel, err = impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", "", false) - if err != nil { - return nil, err - } - if roleModel.Id == 0 { - request.Status = bean2.RoleNotFoundStatusPrefix + roleFilter.Team + "," + environment + "," + entityName + "," + actionType - continue - } - } else { - continue - } + impl.logger.Errorw("error in creating updating role group for jobs entity", "err", err, "roleFilter", roleFilter) } - if _, ok := existingRoles[roleModel.Id]; ok { - //Adding policies which is removed - policies = append(policies, casbin2.Policy{Type: "g", Sub: casbin2.Subject(roleGroup.CasbinName), Obj: casbin2.Object(roleModel.Role)}) - } else { - if roleModel.Id > 0 { - //new role ids in new array, add it - roleGroupMappingModel := &repository2.RoleGroupRoleMapping{RoleGroupId: request.Id, RoleId: roleModel.Id} - roleGroupMappingModel.CreatedBy = request.UserId - roleGroupMappingModel.UpdatedBy = request.UserId - roleGroupMappingModel.CreatedOn = time.Now() - roleGroupMappingModel.UpdatedOn = time.Now() - roleGroupMappingModel, err = impl.roleGroupRepository.CreateRoleGroupRoleMapping(roleGroupMappingModel, tx) - if err != nil { - return nil, err - } - policies = append(policies, casbin2.Policy{Type: "g", Sub: casbin2.Subject(roleGroup.CasbinName), Obj: casbin2.Object(roleModel.Role)}) - } + } + default: + { + policiesToBeAdded, err := impl.CreateOrUpdateRoleGroupForOtherEntity(roleFilter, request, roleGroup, existingRoles, token, managerAuth, tx, mapping[index]) + policies = append(policies, policiesToBeAdded...) + if err != nil { + impl.logger.Errorw("error in creating updating role group for other entity", "err", err, "roleFilter", roleFilter) } } } @@ -417,6 +463,7 @@ const ( AllGroup string = "" AllKind string = "" AllResource string = "" + AllWorkflow string = "" ) func (impl RoleGroupServiceImpl) FetchRoleGroupsById(id int32) (*bean.RoleGroup, error) { @@ -445,8 +492,10 @@ func (impl RoleGroupServiceImpl) getRoleGroupMetadata(roleGroup *repository2.Rol roleFilterMap := make(map[string]*bean.RoleFilter) for _, role := range roles { key := "" - if len(role.Team) > 0 { + if len(role.Team) > 0 && role.Entity != bean2.EntityJobs { key = fmt.Sprintf("%s_%s_%s", role.Team, role.Action, role.AccessType) + } else if role.Entity == bean2.EntityJobs { + key = fmt.Sprintf("%s_%s_%s_%s", role.Team, role.Action, role.AccessType, role.Workflow) } else if len(role.Entity) > 0 { if role.Entity == bean.CLUSTER_ENTITIY { key = fmt.Sprintf("%s_%s_%s_%s_%s_%s", role.Entity, role.Action, role.Cluster, @@ -481,6 +530,23 @@ func (impl RoleGroupServiceImpl) getRoleGroupMetadata(roleGroup *repository2.Rol } else if !containsArr(resourceArr, role.Resource) { roleFilterMap[key].Resource = fmt.Sprintf("%s,%s", roleFilterMap[key].Resource, role.Resource) } + } else if role.Entity == bean2.EntityJobs { + envArr := strings.Split(roleFilterMap[key].Environment, ",") + if containsArr(envArr, AllEnvironment) { + roleFilterMap[key].Environment = AllEnvironment + } else if !containsArr(envArr, role.Environment) { + roleFilterMap[key].Environment = fmt.Sprintf("%s,%s", roleFilterMap[key].Environment, role.Environment) + } + entityArr := strings.Split(roleFilterMap[key].EntityName, ",") + if !containsArr(entityArr, role.EntityName) { + roleFilterMap[key].EntityName = fmt.Sprintf("%s,%s", roleFilterMap[key].EntityName, role.EntityName) + } + workflowArr := strings.Split(roleFilterMap[key].Workflow, ",") + if containsArr(workflowArr, AllWorkflow) { + roleFilterMap[key].Workflow = AllWorkflow + } else if !containsArr(workflowArr, role.Workflow) { + roleFilterMap[key].Workflow = fmt.Sprintf("%s,%s", roleFilterMap[key].Workflow, role.Workflow) + } } else { envArr := strings.Split(roleFilterMap[key].Environment, ",") if containsArr(envArr, AllEnvironment) { @@ -506,6 +572,7 @@ func (impl RoleGroupServiceImpl) getRoleGroupMetadata(roleGroup *repository2.Rol Group: role.Group, Kind: role.Kind, Resource: role.Resource, + Workflow: role.Workflow, } } } @@ -710,6 +777,7 @@ func (impl RoleGroupServiceImpl) FetchRolesForGroups(groupNames []string) ([]*be Group: role.Group, Kind: role.Kind, Resource: role.Resource, + Workflow: role.Workflow, } list = append(list, bean) } diff --git a/pkg/user/UserCommonService.go b/pkg/user/UserCommonService.go index 2fd6b2a3ec..c880a66eea 100644 --- a/pkg/user/UserCommonService.go +++ b/pkg/user/UserCommonService.go @@ -18,7 +18,7 @@ import ( ) type UserCommonService interface { - CreateDefaultPoliciesForAllTypes(team, entityName, env, entity, cluster, namespace, group, kind, resource, actionType, accessType string, userId int32) (bool, error, []casbin.Policy) + CreateDefaultPoliciesForAllTypes(team, entityName, env, entity, cluster, namespace, group, kind, resource, actionType, accessType, workflow string, userId int32) (bool, error, []casbin.Policy) RemoveRolesAndReturnEliminatedPolicies(userInfo *bean.UserInfo, existingRoleIds map[int]repository2.UserRoleModel, eliminatedRoleIds map[int]*repository2.UserRoleModel, tx *pg.Tx, token string, managerAuth func(resource, token, object string) bool) ([]casbin.Policy, error) RemoveRolesAndReturnEliminatedPoliciesForGroups(request *bean.RoleGroup, existingRoles map[int]*repository2.RoleGroupRoleMapping, eliminatedRoles map[int]*repository2.RoleGroupRoleMapping, tx *pg.Tx, token string, managerAuth func(resource string, token string, object string) bool) ([]casbin.Policy, error) CheckRbacForClusterEntity(cluster, namespace, group, kind, resource, token string, managerAuth func(resource, token, object string) bool) bool @@ -64,23 +64,23 @@ func NewUserCommonServiceImpl(userAuthRepository repository2.UserAuthRepository, } type UserRbacConfig struct { - UseRbacCreationV2 bool `env:"USE_RBAC_CREATION_V2" envDefault:"false"` + UseRbacCreationV2 bool `env:"USE_RBAC_CREATION_V2" envDefault:"true"` } -func (impl UserCommonServiceImpl) CreateDefaultPoliciesForAllTypes(team, entityName, env, entity, cluster, namespace, group, kind, resource, actionType, accessType string, userId int32) (bool, error, []casbin.Policy) { +func (impl UserCommonServiceImpl) CreateDefaultPoliciesForAllTypes(team, entityName, env, entity, cluster, namespace, group, kind, resource, actionType, accessType, workflow string, userId int32) (bool, error, []casbin.Policy) { if impl.userRbacConfig.UseRbacCreationV2 { impl.logger.Debugw("using rbac creation v2 for creating default policies") - return impl.CreateDefaultPoliciesForAllTypesV2(team, entityName, env, entity, cluster, namespace, group, kind, resource, actionType, accessType) + return impl.CreateDefaultPoliciesForAllTypesV2(team, entityName, env, entity, cluster, namespace, group, kind, resource, actionType, accessType, workflow) } else { return impl.userAuthRepository.CreateDefaultPoliciesForAllTypes(team, entityName, env, entity, cluster, namespace, group, kind, resource, actionType, accessType, userId) } } -func (impl UserCommonServiceImpl) CreateDefaultPoliciesForAllTypesV2(team, entityName, env, entity, cluster, namespace, group, kind, resource, actionType, accessType string) (bool, error, []casbin.Policy) { +func (impl UserCommonServiceImpl) CreateDefaultPoliciesForAllTypesV2(team, entityName, env, entity, cluster, namespace, group, kind, resource, actionType, accessType, workflow string) (bool, error, []casbin.Policy) { //TODO: below txn is making this process slow, need to do bulk operation for role creation. //For detail - https://github.com/devtron-labs/devtron/blob/main/pkg/user/benchmarking-results - renderedRole, renderedPolicyDetails, err := impl.getRenderedRoleAndPolicy(team, entityName, env, entity, cluster, namespace, group, kind, resource, actionType, accessType) + renderedRole, renderedPolicyDetails, err := impl.getRenderedRoleAndPolicy(team, entityName, env, entity, cluster, namespace, group, kind, resource, actionType, accessType, workflow) if err != nil { return false, err, nil } @@ -91,9 +91,9 @@ func (impl UserCommonServiceImpl) CreateDefaultPoliciesForAllTypesV2(team, entit return true, nil, renderedPolicyDetails } -func (impl UserCommonServiceImpl) getRenderedRoleAndPolicy(team, entityName, env, entity, cluster, namespace, group, kind, resource, actionType, accessType string) (*repository2.RoleModel, []casbin.Policy, error) { +func (impl UserCommonServiceImpl) getRenderedRoleAndPolicy(team, entityName, env, entity, cluster, namespace, group, kind, resource, actionType, accessType, workflow string) (*repository2.RoleModel, []casbin.Policy, error) { //getting map of values to be used for rendering - pValUpdateMap := getPValUpdateMap(team, entityName, env, entity, cluster, namespace, group, kind, resource) + pValUpdateMap := getPValUpdateMap(team, entityName, env, entity, cluster, namespace, group, kind, resource, workflow) //getting default role data and policy defaultRoleData, defaultPolicy, err := impl.getDefaultRbacRoleAndPolicyByRoleFilter(entity, accessType, actionType) @@ -127,6 +127,7 @@ func getRenderedRoleData(defaultRoleData repository2.RoleCacheDetailObj, pValUpd Group: getResolvedValueFromPValDetailObject(defaultRoleData.Group, pValUpdateMap), Kind: getResolvedValueFromPValDetailObject(defaultRoleData.Kind, pValUpdateMap), Resource: getResolvedValueFromPValDetailObject(defaultRoleData.Resource, pValUpdateMap), + Workflow: getResolvedValueFromPValDetailObject(defaultRoleData.Workflow, pValUpdateMap), AuditLog: sql.AuditLog{ //not storing user information because this role can be mapped to other users in future and hence can lead to confusion CreatedOn: time.Now(), UpdatedOn: time.Now(), @@ -173,8 +174,7 @@ func getResolvedValueFromPValDetailObject(pValDetailObj repository2.PValDetailOb return string(resolvedValueInBytes) } -func getPValUpdateMap(team, entityName, env, entity, cluster, - namespace, group, kind, resource string) map[repository2.PValUpdateKey]string { +func getPValUpdateMap(team, entityName, env, entity, cluster, namespace, group, kind, resource, workflow string) map[repository2.PValUpdateKey]string { pValUpdateMap := make(map[repository2.PValUpdateKey]string) pValUpdateMap[repository2.EntityPValUpdateKey] = entity if entity == bean.CLUSTER_ENTITIY { @@ -196,6 +196,10 @@ func getPValUpdateMap(team, entityName, env, entity, cluster, pValUpdateMap[repository2.TeamObjPValUpdateKey] = getResolvedPValMapValue(team) pValUpdateMap[repository2.AppObjPValUpdateKey] = getResolvedPValMapValue(entityName) pValUpdateMap[repository2.EnvObjPValUpdateKey] = getResolvedPValMapValue(env) + if entity == bean2.EntityJobs { + pValUpdateMap[repository2.WorkflowPValUpdateKey] = workflow + pValUpdateMap[repository2.WorkflowObjPValUpdateKey] = getResolvedPValMapValue(workflow) + } } return pValUpdateMap } @@ -214,19 +218,8 @@ func (impl UserCommonServiceImpl) RemoveRolesAndReturnEliminatedPolicies(userInf var eliminatedPolicies []casbin.Policy // DELETE Removed Items for _, roleFilter := range userInfo.RoleFilters { + roleFilter = impl.ReplacePlaceHolderForEmptyEntriesInRoleFilter(roleFilter) if roleFilter.Entity == bean.CLUSTER_ENTITIY { - if roleFilter.Namespace == "" { - roleFilter.Namespace = "NONE" - } - if roleFilter.Group == "" { - roleFilter.Group = "NONE" - } - if roleFilter.Kind == "" { - roleFilter.Kind = "NONE" - } - if roleFilter.Resource == "" { - roleFilter.Resource = "NONE" - } namespaces := strings.Split(roleFilter.Namespace, ",") groups := strings.Split(roleFilter.Group, ",") kinds := strings.Split(roleFilter.Kind, ",") @@ -237,23 +230,15 @@ func (impl UserCommonServiceImpl) RemoveRolesAndReturnEliminatedPolicies(userInf for _, group := range groups { for _, kind := range kinds { for _, resource := range resources { - if namespace == "NONE" { - namespace = "" - } - if group == "NONE" { - group = "" - } - if kind == "NONE" { - kind = "" - } - if resource == "NONE" { - resource = "" - } + namespace = impl.RemovePlaceHolderInRoleFilterField(namespace) + group = impl.RemovePlaceHolderInRoleFilterField(group) + kind = impl.RemovePlaceHolderInRoleFilterField(kind) + resource = impl.RemovePlaceHolderInRoleFilterField(resource) isValidAuth := impl.CheckRbacForClusterEntity(roleFilter.Cluster, namespace, group, kind, resource, token, managerAuth) if !isValidAuth { continue } - roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(roleFilter.Entity, "", "", "", "", accessType, roleFilter.Cluster, namespace, group, kind, resource, actionType, false) + roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(roleFilter.Entity, "", "", "", "", accessType, roleFilter.Cluster, namespace, group, kind, resource, actionType, false, "") if err != nil { impl.logger.Errorw("Error in fetching roles by filter", "roleFilter", roleFilter) return nil, err @@ -269,7 +254,7 @@ func (impl UserCommonServiceImpl) RemoveRolesAndReturnEliminatedPolicies(userInf } } } - } else { + } else if roleFilter.Entity == bean2.EntityJobs { if len(roleFilter.Team) > 0 { // check auth only for apps permission, skip for chart group rbacObject := fmt.Sprintf("%s", strings.ToLower(roleFilter.Team)) isValidAuth := managerAuth(casbin.ResourceUser, token, rbacObject) @@ -277,12 +262,40 @@ func (impl UserCommonServiceImpl) RemoveRolesAndReturnEliminatedPolicies(userInf continue } } - - if roleFilter.EntityName == "" { - roleFilter.EntityName = "NONE" + entityNames := strings.Split(roleFilter.EntityName, ",") + environments := strings.Split(roleFilter.Environment, ",") + workflows := strings.Split(roleFilter.Workflow, ",") + actionType := roleFilter.Action + accessType := roleFilter.AccessType + for _, environment := range environments { + for _, entityName := range entityNames { + for _, workflow := range workflows { + entityName = impl.RemovePlaceHolderInRoleFilterField(entityName) + environment = impl.RemovePlaceHolderInRoleFilterField(environment) + workflow = impl.RemovePlaceHolderInRoleFilterField(workflow) + roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(roleFilter.Entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", actionType, false, workflow) + if err != nil { + impl.logger.Errorw("Error in fetching roles by filter", "user", userInfo) + return nil, err + } + if roleModel.Id == 0 { + impl.logger.Debugw("no role found for given filter", "filter", roleFilter) + userInfo.Status = "role not fount for any given filter: " + roleFilter.Team + "," + environment + "," + entityName + "," + roleFilter.Action + continue + } + if _, ok := existingRoleIds[roleModel.Id]; ok { + delete(eliminatedRoleIds, roleModel.Id) + } + } + } } - if roleFilter.Environment == "" { - roleFilter.Environment = "NONE" + } else { + if len(roleFilter.Team) > 0 { // check auth only for apps permission, skip for chart group + rbacObject := fmt.Sprintf("%s", strings.ToLower(roleFilter.Team)) + isValidAuth := managerAuth(casbin.ResourceUser, token, rbacObject) + if !isValidAuth { + continue + } } entityNames := strings.Split(roleFilter.EntityName, ",") environments := strings.Split(roleFilter.Environment, ",") @@ -290,18 +303,14 @@ func (impl UserCommonServiceImpl) RemoveRolesAndReturnEliminatedPolicies(userInf accessType := roleFilter.AccessType for _, environment := range environments { for _, entityName := range entityNames { - if entityName == "NONE" { - entityName = "" - } - if environment == "NONE" { - environment = "" - } - roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(roleFilter.Entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", actionType, false) + entityName = impl.RemovePlaceHolderInRoleFilterField(entityName) + environment = impl.RemovePlaceHolderInRoleFilterField(environment) + roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(roleFilter.Entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", actionType, false, "") if err != nil { impl.logger.Errorw("Error in fetching roles by filter", "user", userInfo) return nil, err } - oldRoleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(roleFilter.Entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", actionType, true) + oldRoleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(roleFilter.Entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", actionType, true, "") if err != nil { return nil, err } @@ -360,52 +369,33 @@ func (impl UserCommonServiceImpl) RemoveRolesAndReturnEliminatedPoliciesForGroup // Filter out removed items in current request //var policies []casbin.Policy for _, roleFilter := range request.RoleFilters { - if roleFilter.Entity == bean.CLUSTER_ENTITIY { - if roleFilter.Namespace == "" { - roleFilter.Namespace = "NONE" - } - if roleFilter.Group == "" { - roleFilter.Group = "NONE" - } - if roleFilter.Kind == "" { - roleFilter.Kind = "NONE" - } - if roleFilter.Resource == "" { - roleFilter.Resource = "NONE" - } + roleFilter = impl.ReplacePlaceHolderForEmptyEntriesInRoleFilter(roleFilter) + entity := roleFilter.Entity + if entity == bean.CLUSTER_ENTITIY { namespaces := strings.Split(roleFilter.Namespace, ",") groups := strings.Split(roleFilter.Group, ",") kinds := strings.Split(roleFilter.Kind, ",") resources := strings.Split(roleFilter.Resource, ",") - entity := roleFilter.Entity actionType := roleFilter.Action accessType := roleFilter.AccessType for _, namespace := range namespaces { for _, group := range groups { for _, kind := range kinds { for _, resource := range resources { - if namespace == "NONE" { - namespace = "" - } - if group == "NONE" { - group = "" - } - if kind == "NONE" { - kind = "" - } - if resource == "NONE" { - resource = "" - } + namespace = impl.RemovePlaceHolderInRoleFilterField(namespace) + group = impl.RemovePlaceHolderInRoleFilterField(group) + kind = impl.RemovePlaceHolderInRoleFilterField(kind) + resource = impl.RemovePlaceHolderInRoleFilterField(resource) isValidAuth := impl.CheckRbacForClusterEntity(roleFilter.Cluster, namespace, group, kind, resource, token, managerAuth) if !isValidAuth { continue } - roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, "", "", "", "", accessType, roleFilter.Cluster, namespace, group, kind, resource, actionType, false) + roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, "", "", "", "", accessType, roleFilter.Cluster, namespace, group, kind, resource, actionType, false, "") if err != nil { impl.logger.Errorw("Error in fetching roles by filter", "user", request) return nil, err } - oldRoleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, "", "", "", "", accessType, roleFilter.Cluster, namespace, group, kind, resource, actionType, true) + oldRoleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, "", "", "", "", accessType, roleFilter.Cluster, namespace, group, kind, resource, actionType, true, "") if err != nil { impl.logger.Errorw("Error in fetching roles by filter", "user", request) return nil, err @@ -425,7 +415,7 @@ func (impl UserCommonServiceImpl) RemoveRolesAndReturnEliminatedPoliciesForGroup } } } - } else { + } else if entity == bean2.EntityJobs { if len(roleFilter.Team) > 0 { // check auth only for apps permission, skip for chart group rbacObject := fmt.Sprintf("%s", strings.ToLower(roleFilter.Team)) isValidAuth := managerAuth(casbin.ResourceUser, token, rbacObject) @@ -433,12 +423,40 @@ func (impl UserCommonServiceImpl) RemoveRolesAndReturnEliminatedPoliciesForGroup continue } } - - if roleFilter.EntityName == "" { - roleFilter.EntityName = "NONE" + entityNames := strings.Split(roleFilter.EntityName, ",") + environments := strings.Split(roleFilter.Environment, ",") + workflows := strings.Split(roleFilter.Workflow, ",") + accessType := roleFilter.AccessType + actionType := roleFilter.Action + for _, environment := range environments { + for _, entityName := range entityNames { + for _, workflow := range workflows { + entityName = impl.RemovePlaceHolderInRoleFilterField(entityName) + environment = impl.RemovePlaceHolderInRoleFilterField(environment) + workflow = impl.RemovePlaceHolderInRoleFilterField(workflow) + roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(roleFilter.Entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", "", false, workflow) + if err != nil { + impl.logger.Errorw("Error in fetching roles by filter", "user", request) + return nil, err + } + if roleModel.Id == 0 { + impl.logger.Warnw("no role found for given filter", "filter", roleFilter) + request.Status = "role not fount for any given filter: " + roleFilter.Team + "," + environment + "," + entityName + "," + actionType + continue + } + if _, ok := existingRoles[roleModel.Id]; ok { + delete(eliminatedRoles, roleModel.Id) + } + } + } } - if roleFilter.Environment == "" { - roleFilter.Environment = "NONE" + } else { + if len(roleFilter.Team) > 0 { // check auth only for apps permission, skip for chart group + rbacObject := fmt.Sprintf("%s", strings.ToLower(roleFilter.Team)) + isValidAuth := managerAuth(casbin.ResourceUser, token, rbacObject) + if !isValidAuth { + continue + } } entityNames := strings.Split(roleFilter.EntityName, ",") environments := strings.Split(roleFilter.Environment, ",") @@ -446,18 +464,14 @@ func (impl UserCommonServiceImpl) RemoveRolesAndReturnEliminatedPoliciesForGroup actionType := roleFilter.Action for _, environment := range environments { for _, entityName := range entityNames { - if entityName == "NONE" { - entityName = "" - } - if environment == "NONE" { - environment = "" - } - roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(roleFilter.Entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", "", false) + entityName = impl.RemovePlaceHolderInRoleFilterField(entityName) + environment = impl.RemovePlaceHolderInRoleFilterField(environment) + roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(roleFilter.Entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", "", false, "") if err != nil { impl.logger.Errorw("Error in fetching roles by filter", "user", request) return nil, err } - oldRoleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(roleFilter.Entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", "", true) + oldRoleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(roleFilter.Entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", "", true, "") if err != nil { impl.logger.Errorw("Error in fetching roles by filter by old values", "user", request) return nil, err @@ -584,6 +598,9 @@ func (impl UserCommonServiceImpl) ReplacePlaceHolderForEmptyEntriesInRoleFilter( if roleFilter.Resource == "" { roleFilter.Resource = bean2.EMPTY_ROLEFILTER_ENTRY_PLACEHOLDER } + if roleFilter.Workflow == "" { + roleFilter.Workflow = bean2.EMPTY_ROLEFILTER_ENTRY_PLACEHOLDER + } return roleFilter } @@ -605,7 +622,8 @@ func (impl UserCommonServiceImpl) GetCapacityForRoleFilter(roleFilters []bean.Ro resources := strings.Split(roleFilter.Resource, ",") entityNames := strings.Split(roleFilter.EntityName, ",") environments := strings.Split(roleFilter.Environment, ",") - value := math.Max(float64(len(namespaces)*len(groups)*len(kinds)*len(resources)*2), float64(len(entityNames)*len(environments)*6)) + workflows := strings.Split(roleFilter.Workflow, ",") + value := math.Max(float64(len(namespaces)*len(groups)*len(kinds)*len(resources)*2), float64(len(entityNames)*len(environments)*len(workflows)*8)) m[index] = int(value) capacity += int(value) } diff --git a/pkg/user/UserFlows_test.go b/pkg/user/UserFlows_test.go index 7dc889e791..d67f2c095e 100644 --- a/pkg/user/UserFlows_test.go +++ b/pkg/user/UserFlows_test.go @@ -41,7 +41,7 @@ func BenchmarkCreateDefaultPoliciesForAllTypesV2(b *testing.B) { action := fmt.Sprintf("manager") b.Run(fmt.Sprintf("BenchmarkCreateDefaultPoliciesForAllTypesV2"), func(b *testing.B) { for i := 0; i < b.N; i++ { - userCommonService.CreateDefaultPoliciesForAllTypesV2(teams[i], apps[i], envs[i], entity, "", "", "", "", "", action, accessType) + userCommonService.CreateDefaultPoliciesForAllTypesV2(teams[i], apps[i], envs[i], entity, "", "", "", "", "", action, accessType, "") } }) } diff --git a/pkg/user/UserService.go b/pkg/user/UserService.go index c64d4c0a39..80a74e614b 100644 --- a/pkg/user/UserService.go +++ b/pkg/user/UserService.go @@ -411,7 +411,7 @@ func (impl *UserServiceImpl) createUserIfNotExists(userInfo *bean.UserInfo, emai if err != nil || flag == false { return nil, err } - roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes("", "", "", "", bean2.SUPER_ADMIN, "", "", "", "", "", "", "", false) + roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes("", "", "", "", bean2.SUPER_ADMIN, "", "", "", "", "", "", "", false, "") if err != nil { return nil, err } @@ -457,64 +457,15 @@ func (impl *UserServiceImpl) CreateOrUpdateUserRolesForAllTypes(roleFilter bean. if err != nil { return nil, false, err } + } else if entity == bean2.EntityJobs { + policiesToBeAdded, rolesChanged, err = impl.createOrUpdateUserRolesForJobsEntity(roleFilter, userId, model, existingRoles, token, managerAuth, tx, entity, capacity) + if err != nil { + return nil, false, err + } } else { - actionType := roleFilter.Action - accessType := roleFilter.AccessType - entityNames := strings.Split(roleFilter.EntityName, ",") - environments := strings.Split(roleFilter.Environment, ",") - for _, environment := range environments { - for _, entityName := range entityNames { - if managerAuth != nil { - // check auth only for apps permission, skip for chart group - rbacObject := fmt.Sprintf("%s", strings.ToLower(roleFilter.Team)) - isValidAuth := managerAuth(casbin2.ResourceUser, token, rbacObject) - if !isValidAuth { - continue - } - } - entityName = impl.userCommonService.RemovePlaceHolderInRoleFilterField(entityName) - environment = impl.userCommonService.RemovePlaceHolderInRoleFilterField(environment) - roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", actionType, false) - if err != nil { - impl.logger.Errorw("error in getting role by all type", "err", err, "roleFilter", roleFilter) - return policiesToBeAdded, rolesChanged, err - } - if roleModel.Id == 0 { - impl.logger.Debugw("no role found for given filter", "filter", "roleFilter", roleFilter) - flag, err, policiesAdded := impl.userCommonService.CreateDefaultPoliciesForAllTypes(roleFilter.Team, entityName, environment, entity, "", "", "", "", "", actionType, accessType, userId) - if err != nil || flag == false { - return policiesToBeAdded, rolesChanged, err - } - policiesToBeAdded = append(policiesToBeAdded, policiesAdded...) - roleModel, err = impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", actionType, false) - if err != nil { - return policiesToBeAdded, rolesChanged, err - } - if roleModel.Id == 0 { - continue - } - } - if _, ok := existingRoles[roleModel.Id]; ok { - //Adding policies which is removed - policiesToBeAdded = append(policiesToBeAdded, casbin2.Policy{Type: "g", Sub: casbin2.Subject(model.EmailId), Obj: casbin2.Object(roleModel.Role)}) - } else if roleModel.Id > 0 { - rolesChanged = true - userRoleModel := &repository2.UserRoleModel{ - UserId: model.Id, - RoleId: roleModel.Id, - AuditLog: sql.AuditLog{ - CreatedBy: userId, - CreatedOn: time.Now(), - UpdatedBy: userId, - UpdatedOn: time.Now(), - }} - userRoleModel, err = impl.userAuthRepository.CreateUserRoleMapping(userRoleModel, tx) - if err != nil { - return nil, rolesChanged, err - } - policiesToBeAdded = append(policiesToBeAdded, casbin2.Policy{Type: "g", Sub: casbin2.Subject(model.EmailId), Obj: casbin2.Object(roleModel.Role)}) - } - } + policiesToBeAdded, rolesChanged, err = impl.createOrUpdateUserRolesForOtherEntity(roleFilter, userId, model, existingRoles, token, managerAuth, tx, entity, capacity) + if err != nil { + return nil, false, err } } return policiesToBeAdded, rolesChanged, nil @@ -548,19 +499,19 @@ func (impl *UserServiceImpl) createOrUpdateUserRolesForClusterEntity(roleFilter } } impl.logger.Infow("Getting Role by filter for cluster") - roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, "", "", "", "", accessType, roleFilter.Cluster, namespace, group, kind, resource, actionType, false) + roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, "", "", "", "", accessType, roleFilter.Cluster, namespace, group, kind, resource, actionType, false, "") if err != nil { return policiesToBeAdded, rolesChanged, err } if roleModel.Id == 0 { impl.logger.Infow("Creating Polices for cluster", resource, kind, namespace, group) - flag, err, policiesAdded := impl.userCommonService.CreateDefaultPoliciesForAllTypes("", "", "", entity, roleFilter.Cluster, namespace, group, kind, resource, actionType, accessType, userId) + flag, err, policiesAdded := impl.userCommonService.CreateDefaultPoliciesForAllTypes("", "", "", entity, roleFilter.Cluster, namespace, group, kind, resource, actionType, accessType, "", userId) if err != nil || flag == false { return policiesToBeAdded, rolesChanged, err } policiesToBeAdded = append(policiesToBeAdded, policiesAdded...) impl.logger.Infow("getting role again for cluster") - roleModel, err = impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, "", "", "", "", accessType, roleFilter.Cluster, namespace, group, kind, resource, actionType, false) + roleModel, err = impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, "", "", "", "", accessType, roleFilter.Cluster, namespace, group, kind, resource, actionType, false, "") if err != nil { return policiesToBeAdded, rolesChanged, err } @@ -613,14 +564,15 @@ func (impl *UserServiceImpl) mergeRoleFilter(oldR []bean.RoleFilter, newR []bean Group: role.Group, Kind: role.Kind, Resource: role.Resource, + Workflow: role.Workflow, }) - key := fmt.Sprintf("%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s", role.Entity, role.Team, role.Environment, - role.EntityName, role.Action, role.AccessType, role.Cluster, role.Namespace, role.Group, role.Kind, role.Resource) + key := fmt.Sprintf("%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s", role.Entity, role.Team, role.Environment, + role.EntityName, role.Action, role.AccessType, role.Cluster, role.Namespace, role.Group, role.Kind, role.Resource, role.Workflow) keysMap[key] = true } for _, role := range newR { - key := fmt.Sprintf("%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s", role.Entity, role.Team, role.Environment, - role.EntityName, role.Action, role.AccessType, role.Cluster, role.Namespace, role.Group, role.Kind, role.Resource) + key := fmt.Sprintf("%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s", role.Entity, role.Team, role.Environment, + role.EntityName, role.Action, role.AccessType, role.Cluster, role.Namespace, role.Group, role.Kind, role.Resource, role.Workflow) if _, ok := keysMap[key]; !ok { roleFilters = append(roleFilters, bean.RoleFilter{ Entity: role.Entity, @@ -634,6 +586,7 @@ func (impl *UserServiceImpl) mergeRoleFilter(oldR []bean.RoleFilter, newR []bean Group: role.Group, Kind: role.Kind, Resource: role.Resource, + Workflow: role.Workflow, }) } } @@ -805,15 +758,17 @@ func (impl *UserServiceImpl) UpdateUser(userInfo *bean.UserInfo, token string, m if _, ok := newGroupMap[item]; !ok { if item != bean.SUPERADMIN { //check permission for group which is going to eliminate - hasAccessToGroup := impl.checkGroupAuth(item, token, managerAuth, isActionPerformingUserSuperAdmin) - if hasAccessToGroup { - if strings.HasPrefix(item, "group:") { - groupsModified = true + if strings.HasPrefix(item, "group:") { + hasAccessToGroup := impl.checkGroupAuth(item, token, managerAuth, isActionPerformingUserSuperAdmin) + if hasAccessToGroup { + if strings.HasPrefix(item, "group:") { + groupsModified = true + } + eliminatedPolicies = append(eliminatedPolicies, casbin2.Policy{Type: "g", Sub: casbin2.Subject(userInfo.EmailId), Obj: casbin2.Object(item)}) + } else { + trimmedGroup := strings.TrimPrefix(item, "group:") + restrictedGroups = append(restrictedGroups, trimmedGroup) } - eliminatedPolicies = append(eliminatedPolicies, casbin2.Policy{Type: "g", Sub: casbin2.Subject(userInfo.EmailId), Obj: casbin2.Object(item)}) - } else { - trimmedGroup := strings.TrimPrefix(item, "group:") - restrictedGroups = append(restrictedGroups, trimmedGroup) } } } @@ -825,7 +780,7 @@ func (impl *UserServiceImpl) UpdateUser(userInfo *bean.UserInfo, token string, m if err != nil || flag == false { return nil, false, false, nil, err } - roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes("", "", "", "", bean2.SUPER_ADMIN, "", "", "", "", "", "", "", false) + roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes("", "", "", "", bean2.SUPER_ADMIN, "", "", "", "", "", "", "", false, "") if err != nil { return nil, false, false, nil, err } @@ -906,8 +861,10 @@ func (impl *UserServiceImpl) getUserMetadata(model *repository2.UserModel) (bool roleFilterMap := make(map[string]*bean.RoleFilter) for _, role := range roles { key := "" - if len(role.Team) > 0 { + if len(role.Team) > 0 && role.Entity != bean2.EntityJobs { key = fmt.Sprintf("%s_%s_%s", role.Team, role.Action, role.AccessType) + } else if role.Entity == bean2.EntityJobs { + key = fmt.Sprintf("%s_%s_%s_%s", role.Team, role.Action, role.AccessType, role.Workflow) } else if len(role.Entity) > 0 { if role.Entity == bean.CLUSTER_ENTITIY { key = fmt.Sprintf("%s_%s_%s_%s_%s_%s", role.Entity, role.Action, role.Cluster, @@ -942,6 +899,23 @@ func (impl *UserServiceImpl) getUserMetadata(model *repository2.UserModel) (bool } else if !containsArr(resourceArr, role.Resource) { roleFilterMap[key].Resource = fmt.Sprintf("%s,%s", roleFilterMap[key].Resource, role.Resource) } + } else if role.Entity == bean2.EntityJobs { + envArr := strings.Split(roleFilterMap[key].Environment, ",") + if containsArr(envArr, AllEnvironment) { + roleFilterMap[key].Environment = AllEnvironment + } else if !containsArr(envArr, role.Environment) { + roleFilterMap[key].Environment = fmt.Sprintf("%s,%s", roleFilterMap[key].Environment, role.Environment) + } + entityArr := strings.Split(roleFilterMap[key].EntityName, ",") + if !containsArr(entityArr, role.EntityName) { + roleFilterMap[key].EntityName = fmt.Sprintf("%s,%s", roleFilterMap[key].EntityName, role.EntityName) + } + workflowArr := strings.Split(roleFilterMap[key].Workflow, ",") + if containsArr(workflowArr, AllWorkflow) { + roleFilterMap[key].Workflow = AllWorkflow + } else if !containsArr(workflowArr, role.Workflow) { + roleFilterMap[key].Workflow = fmt.Sprintf("%s,%s", roleFilterMap[key].Workflow, role.Workflow) + } } else { envArr := strings.Split(roleFilterMap[key].Environment, ",") if containsArr(envArr, AllEnvironment) { @@ -967,6 +941,7 @@ func (impl *UserServiceImpl) getUserMetadata(model *repository2.UserModel) (bool Group: role.Group, Kind: role.Kind, Resource: role.Resource, + Workflow: role.Workflow, } } @@ -1129,6 +1104,7 @@ func (impl *UserServiceImpl) GetUserByEmail(emailId string) (*bean.UserInfo, err Group: role.Group, Kind: role.Kind, Resource: role.Resource, + Workflow: role.Workflow, }) } @@ -1426,8 +1402,10 @@ func (impl *UserServiceImpl) GetRoleFiltersByGroupNames(groupNames []string) ([] roleFilterMap := make(map[string]*bean.RoleFilter) for _, role := range roles { key := "" - if len(role.Team) > 0 { + if len(role.Team) > 0 && role.Entity != bean2.EntityJobs { key = fmt.Sprintf("%s_%s_%s", role.Team, role.Action, role.AccessType) + } else if role.Entity == bean2.EntityJobs { + key = fmt.Sprintf("%s_%s_%s_%s", role.Team, role.Action, role.AccessType, role.Workflow) } else if len(role.Entity) > 0 { if role.Entity == bean.CLUSTER_ENTITIY { key = fmt.Sprintf("%s_%s_%s_%s_%s_%s", role.Entity, role.Action, role.Cluster, @@ -1462,6 +1440,23 @@ func (impl *UserServiceImpl) GetRoleFiltersByGroupNames(groupNames []string) ([] } else if !containsArr(resourceArr, role.Resource) { roleFilterMap[key].Resource = fmt.Sprintf("%s,%s", roleFilterMap[key].Resource, role.Resource) } + } else if role.Entity == bean2.EntityJobs { + envArr := strings.Split(roleFilterMap[key].Environment, ",") + if containsArr(envArr, AllEnvironment) { + roleFilterMap[key].Environment = AllEnvironment + } else if !containsArr(envArr, role.Environment) { + roleFilterMap[key].Environment = fmt.Sprintf("%s,%s", roleFilterMap[key].Environment, role.Environment) + } + entityArr := strings.Split(roleFilterMap[key].EntityName, ",") + if !containsArr(entityArr, role.EntityName) { + roleFilterMap[key].EntityName = fmt.Sprintf("%s,%s", roleFilterMap[key].EntityName, role.EntityName) + } + workflowArr := strings.Split(roleFilterMap[key].Workflow, ",") + if containsArr(workflowArr, AllWorkflow) { + roleFilterMap[key].Workflow = AllWorkflow + } else if !containsArr(workflowArr, role.Workflow) { + roleFilterMap[key].Workflow = fmt.Sprintf("%s,%s", roleFilterMap[key].Workflow, role.Workflow) + } } else { envArr := strings.Split(roleFilterMap[key].Environment, ",") if containsArr(envArr, AllEnvironment) { @@ -1487,6 +1482,7 @@ func (impl *UserServiceImpl) GetRoleFiltersByGroupNames(groupNames []string) ([] Group: role.Group, Kind: role.Kind, Resource: role.Resource, + Workflow: role.Workflow, } } @@ -1507,3 +1503,136 @@ func (impl *UserServiceImpl) GetRoleFiltersByGroupNames(groupNames []string) ([] } return roleFilters, nil } + +func (impl *UserServiceImpl) createOrUpdateUserRolesForOtherEntity(roleFilter bean.RoleFilter, userId int32, model *repository2.UserModel, existingRoles map[int]repository2.UserRoleModel, token string, managerAuth func(resource string, token string, object string) bool, tx *pg.Tx, entity string, capacity int) ([]casbin2.Policy, bool, error) { + rolesChanged := false + var policiesToBeAdded = make([]casbin2.Policy, 0, capacity) + actionType := roleFilter.Action + accessType := roleFilter.AccessType + entityNames := strings.Split(roleFilter.EntityName, ",") + environments := strings.Split(roleFilter.Environment, ",") + for _, environment := range environments { + for _, entityName := range entityNames { + if managerAuth != nil { + // check auth only for apps permission, skip for chart group + rbacObject := fmt.Sprintf("%s", strings.ToLower(roleFilter.Team)) + isValidAuth := managerAuth(casbin2.ResourceUser, token, rbacObject) + if !isValidAuth { + continue + } + } + entityName = impl.userCommonService.RemovePlaceHolderInRoleFilterField(entityName) + environment = impl.userCommonService.RemovePlaceHolderInRoleFilterField(environment) + roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", actionType, false, "") + if err != nil { + impl.logger.Errorw("error in getting role by all type", "err", err, "roleFilter", roleFilter) + return policiesToBeAdded, rolesChanged, err + } + if roleModel.Id == 0 { + impl.logger.Debugw("no role found for given filter", "filter", "roleFilter", roleFilter) + flag, err, policiesAdded := impl.userCommonService.CreateDefaultPoliciesForAllTypes(roleFilter.Team, entityName, environment, entity, "", "", "", "", "", actionType, accessType, "", userId) + if err != nil || flag == false { + return policiesToBeAdded, rolesChanged, err + } + policiesToBeAdded = append(policiesToBeAdded, policiesAdded...) + roleModel, err = impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", actionType, false, "") + if err != nil { + return policiesToBeAdded, rolesChanged, err + } + if roleModel.Id == 0 { + continue + } + } + if _, ok := existingRoles[roleModel.Id]; ok { + //Adding policies which is removed + policiesToBeAdded = append(policiesToBeAdded, casbin2.Policy{Type: "g", Sub: casbin2.Subject(model.EmailId), Obj: casbin2.Object(roleModel.Role)}) + } else if roleModel.Id > 0 { + rolesChanged = true + userRoleModel := &repository2.UserRoleModel{ + UserId: model.Id, + RoleId: roleModel.Id, + AuditLog: sql.AuditLog{ + CreatedBy: userId, + CreatedOn: time.Now(), + UpdatedBy: userId, + UpdatedOn: time.Now(), + }} + userRoleModel, err = impl.userAuthRepository.CreateUserRoleMapping(userRoleModel, tx) + if err != nil { + return nil, rolesChanged, err + } + policiesToBeAdded = append(policiesToBeAdded, casbin2.Policy{Type: "g", Sub: casbin2.Subject(model.EmailId), Obj: casbin2.Object(roleModel.Role)}) + } + } + } + return policiesToBeAdded, rolesChanged, nil +} + +func (impl *UserServiceImpl) createOrUpdateUserRolesForJobsEntity(roleFilter bean.RoleFilter, userId int32, model *repository2.UserModel, existingRoles map[int]repository2.UserRoleModel, token string, managerAuth func(resource string, token string, object string) bool, tx *pg.Tx, entity string, capacity int) ([]casbin2.Policy, bool, error) { + + rolesChanged := false + actionType := roleFilter.Action + accessType := roleFilter.AccessType + var policiesToBeAdded = make([]casbin2.Policy, 0, capacity) + entityNames := strings.Split(roleFilter.EntityName, ",") + environments := strings.Split(roleFilter.Environment, ",") + workflows := strings.Split(roleFilter.Workflow, ",") + for _, environment := range environments { + for _, entityName := range entityNames { + for _, workflow := range workflows { + if managerAuth != nil { + // check auth only for apps permission, skip for chart group + rbacObject := fmt.Sprintf("%s", strings.ToLower(roleFilter.Team)) + isValidAuth := managerAuth(casbin2.ResourceUser, token, rbacObject) + if !isValidAuth { + continue + } + } + entityName = impl.userCommonService.RemovePlaceHolderInRoleFilterField(entityName) + environment = impl.userCommonService.RemovePlaceHolderInRoleFilterField(environment) + workflow = impl.userCommonService.RemovePlaceHolderInRoleFilterField(workflow) + roleModel, err := impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", actionType, false, workflow) + if err != nil { + impl.logger.Errorw("error in getting role by all type", "err", err, "roleFilter", roleFilter) + return policiesToBeAdded, rolesChanged, err + } + if roleModel.Id == 0 { + impl.logger.Debugw("no role found for given filter", "filter", "roleFilter", roleFilter) + flag, err, policiesAdded := impl.userCommonService.CreateDefaultPoliciesForAllTypes(roleFilter.Team, entityName, environment, entity, "", "", "", "", "", actionType, accessType, workflow, userId) + if err != nil || flag == false { + return policiesToBeAdded, rolesChanged, err + } + policiesToBeAdded = append(policiesToBeAdded, policiesAdded...) + roleModel, err = impl.userAuthRepository.GetRoleByFilterForAllTypes(entity, roleFilter.Team, entityName, environment, actionType, accessType, "", "", "", "", "", actionType, false, workflow) + if err != nil { + return policiesToBeAdded, rolesChanged, err + } + if roleModel.Id == 0 { + continue + } + } + if _, ok := existingRoles[roleModel.Id]; ok { + //Adding policies which is removed + policiesToBeAdded = append(policiesToBeAdded, casbin2.Policy{Type: "g", Sub: casbin2.Subject(model.EmailId), Obj: casbin2.Object(roleModel.Role)}) + } else if roleModel.Id > 0 { + rolesChanged = true + userRoleModel := &repository2.UserRoleModel{ + UserId: model.Id, + RoleId: roleModel.Id, + AuditLog: sql.AuditLog{ + CreatedBy: userId, + CreatedOn: time.Now(), + UpdatedBy: userId, + UpdatedOn: time.Now(), + }} + userRoleModel, err = impl.userAuthRepository.CreateUserRoleMapping(userRoleModel, tx) + if err != nil { + return nil, rolesChanged, err + } + policiesToBeAdded = append(policiesToBeAdded, casbin2.Policy{Type: "g", Sub: casbin2.Subject(model.EmailId), Obj: casbin2.Object(roleModel.Role)}) + } + } + } + } + return policiesToBeAdded, rolesChanged, nil +} diff --git a/pkg/user/bean/bean.go b/pkg/user/bean/bean.go index d965548b5a..a82a3f4931 100644 --- a/pkg/user/bean/bean.go +++ b/pkg/user/bean/bean.go @@ -30,6 +30,7 @@ const ( ENTITY_APPS = "apps" EMPTY_ROLEFILTER_ENTRY_PLACEHOLDER = "NONE" RoleNotFoundStatusPrefix = "role not fount for any given filter: " + EntityJobs = "jobs" ) type RbacRoleDto struct { @@ -41,6 +42,6 @@ type RbacRoleDto struct { } type RbacPolicyEntityGroupDto struct { - Entity string `json:"entity" validate:"oneof=apps cluster chart-group"` + Entity string `json:"entity" validate:"oneof=apps cluster chart-group jobs"` AccessType string `json:"accessType,omitempty"` } diff --git a/pkg/user/repository/RbacDataCacheFactory.go b/pkg/user/repository/RbacDataCacheFactory.go index 3a5ea3f2a5..1bbc8861bb 100644 --- a/pkg/user/repository/RbacDataCacheFactory.go +++ b/pkg/user/repository/RbacDataCacheFactory.go @@ -41,6 +41,7 @@ type RoleCacheDetailObj struct { Group PValDetailObj `json:"group"` Kind PValDetailObj `json:"kind"` Resource PValDetailObj `json:"resource"` + Workflow PValDetailObj `json:"workflow"` } type ResActObj struct { diff --git a/pkg/user/repository/UserAuthRepository.go b/pkg/user/repository/UserAuthRepository.go index b20fcdbad5..065170e12b 100644 --- a/pkg/user/repository/UserAuthRepository.go +++ b/pkg/user/repository/UserAuthRepository.go @@ -44,7 +44,7 @@ type UserAuthRepository interface { GetRolesByGroupId(userId int32) ([]*RoleModel, error) GetAllRole() ([]RoleModel, error) GetRolesByActionAndAccessType(action string, accessType string) ([]RoleModel, error) - GetRoleByFilterForAllTypes(entity, team, app, env, act, accessType, cluster, namespace, group, kind, resource, action string, oldValues bool) (RoleModel, error) + GetRoleByFilterForAllTypes(entity, team, app, env, act, accessType, cluster, namespace, group, kind, resource, action string, oldValues bool, workflow string) (RoleModel, error) CreateUserRoleMapping(userRoleModel *UserRoleModel, tx *pg.Tx) (*UserRoleModel, error) GetUserRoleMappingByUserId(userId int32) ([]*UserRoleModel, error) DeleteUserRoleMapping(userRoleModel *UserRoleModel, tx *pg.Tx) (bool, error) @@ -96,6 +96,7 @@ type RoleModel struct { Group string `sql:"group"` Kind string `sql:"kind"` Resource string `sql:"resource"` + Workflow string `sql:"workflow"` sql.AuditLog } @@ -245,7 +246,7 @@ func (impl UserAuthRepositoryImpl) GetRolesByActionAndAccessType(action string, return models, nil } -func (impl UserAuthRepositoryImpl) GetRoleByFilterForAllTypes(entity, team, app, env, act, accessType, cluster, namespace, group, kind, resource, action string, oldValues bool) (RoleModel, error) { +func (impl UserAuthRepositoryImpl) GetRoleByFilterForAllTypes(entity, team, app, env, act, accessType, cluster, namespace, group, kind, resource, action string, oldValues bool, workflow string) (RoleModel, error) { var model RoleModel if entity == bean2.CLUSTER { @@ -313,6 +314,28 @@ func (impl UserAuthRepositoryImpl) GetRoleByFilterForAllTypes(entity, team, app, query += " and role.access_type='" + accessType + "'" } _, err = impl.dbConnection.Query(&model, query, entity, act) + } else if entity == bean2.EntityJobs { + if len(team) > 0 && len(act) > 0 { + query := "SELECT role.* FROM roles role WHERE role.team = ? AND role.action=? " + if len(env) == 0 { + query = query + " AND role.environment is NULL" + } else { + query += "AND role.environment='" + env + "'" + } + if len(app) == 0 { + query = query + " AND role.entity_name is NULL" + } else { + query += " AND role.entity_name='" + app + "'" + } + if len(workflow) == 0 { + query = query + " AND role.workflow is NULL;" + } else { + query += " AND role.workflow='" + workflow + "';" + } + _, err = impl.dbConnection.Query(&model, query, team, act) + } else { + return model, nil + } } else { if len(team) > 0 && len(app) > 0 && len(env) > 0 && len(act) > 0 { @@ -558,7 +581,7 @@ func (impl UserAuthRepositoryImpl) CreateRoleForSuperAdminIfNotExists(tx *pg.Tx, } //Creating ROLES - roleModel, err := impl.GetRoleByFilterForAllTypes("", "", "", "", bean2.SUPER_ADMIN, "", "", "", "", "", "", "", false) + roleModel, err := impl.GetRoleByFilterForAllTypes("", "", "", "", bean2.SUPER_ADMIN, "", "", "", "", "", "", "", false, "") if err != nil && err != pg.ErrNoRows { return false, err } diff --git a/pkg/user/repository/bean.go b/pkg/user/repository/bean.go index d1bb587fdc..d76ad3f3f1 100644 --- a/pkg/user/repository/bean.go +++ b/pkg/user/repository/bean.go @@ -21,4 +21,6 @@ const ( GroupObjPValUpdateKey PValUpdateKey = "GroupObj" KindObjPValUpdateKey PValUpdateKey = "KindObj" ResourceObjPValUpdateKey PValUpdateKey = "ResourceObj" + WorkflowPValUpdateKey PValUpdateKey = "Workflow" + WorkflowObjPValUpdateKey PValUpdateKey = "WorkflowObj" ) From f09576042b5011666c2a66e6460990d2eb9040d0 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 3 Nov 2023 15:53:28 +0530 Subject: [PATCH 02/76] sql-scripts --- scripts/sql/184_jobs_rbac.down.sql | 8 + scripts/sql/184_jobs_rbac.up.sql | 550 +++++++++++++++++++++++++++++ 2 files changed, 558 insertions(+) create mode 100644 scripts/sql/184_jobs_rbac.down.sql create mode 100644 scripts/sql/184_jobs_rbac.up.sql diff --git a/scripts/sql/184_jobs_rbac.down.sql b/scripts/sql/184_jobs_rbac.down.sql new file mode 100644 index 0000000000..95e2a8fe60 --- /dev/null +++ b/scripts/sql/184_jobs_rbac.down.sql @@ -0,0 +1,8 @@ +ALTER TABLE roles DROP COLUMN workflow; +DELETE from rbac_role_resource_detail where resource='workflow'; +UPDATE rbac_policy_resource_detail set eligible_entity_access_types = ARRAY['apps/devtron-app','apps/helm-app'] where resource='project' OR resource ='global-environment' OR resource='terminal'; +UPDATE rbac_role_resource_detail set eligible_entity_access_types = ARRAY['apps/devtron-app','apps/helm-app'] where resource ='project' OR resource ='environment'; +DELETE FROM rbac_policy_resource_detail where resource='jobEnv'; +DELETE FROM rbac_policy_resource_detail where resource='workflow'; +DELETE FROM "public"."rbac_role_data" where entity='jobs'; +DELETE FROM "public"."rbac_policy_data" where entity='jobs'; diff --git a/scripts/sql/184_jobs_rbac.up.sql b/scripts/sql/184_jobs_rbac.up.sql new file mode 100644 index 0000000000..d26286c4eb --- /dev/null +++ b/scripts/sql/184_jobs_rbac.up.sql @@ -0,0 +1,550 @@ +INSERT INTO "public"."rbac_policy_data" ("entity", "access_type", "role", "policy_data", "created_on", "created_by", + "updated_on", "updated_by", "is_preset_role", "deleted") +VALUES ('jobs', '', 'admin', '{ + "type": { + "value": "p", + "indexKeyMap": {} + }, + "sub": { + "value": "jobs:admin_%_%_%_%", + "indexKeyMap": { + "11": "Team", + "13": "Env", + "15": "App", + "17": "Workflow" + } + }, + "resActObjSet": [ + { + "res": { + "value": "jobs", + "indexKeyMap": {} + }, + "act": { + "value": "*", + "indexKeyMap": {} + }, + "obj": { + "value": "%/%", + "indexKeyMap": { + "0": "TeamObj", + "2": "AppObj" + } + } + }, + { + "res": { + "value": "jobEnv", + "indexKeyMap": {} + }, + "act": { + "value": "*", + "indexKeyMap": {} + }, + "obj": { + "value": "%/%/%", + "indexKeyMap": { + "0": "TeamObj", + "2": "EnvObj", + "4": "AppObj" + } + } + }, + { + "res": { + "value": "team", + "indexKeyMap": {} + }, + "act": { + "value": "get", + "indexKeyMap": {} + }, + "obj": { + "value": "%", + "indexKeyMap": { + "0": "TeamObj" + } + } + }, + { + "res": { + "value": "global-environment", + "indexKeyMap": {} + }, + "act": { + "value": "get", + "indexKeyMap": {} + }, + "obj": { + "value": "%", + "indexKeyMap": { + "0": "EnvObj" + } + } + }, + { + "res": { + "value": "workflow", + "indexKeyMap": {} + }, + "act": { + "value": "*", + "indexKeyMap": {} + }, + "obj": { + "value": "%/%/%", + "indexKeyMap": { + "0": "TeamObj", + "2": "AppObj", + "4": "WorkflowObj" + } + } + } + ] + }', 'now()', '1', 'now()', '1', true, false), + ('jobs', '', 'trigger', '{ + "type": { + "value": "p", + "indexKeyMap": {} + }, + "sub": { + "value": "jobs:trigger_%_%_%_%", + "indexKeyMap": { + "13": "Team", + "15": "Env", + "17": "App", + "19": "Workflow" + } + }, + "resActObjSet": [ + { + "res": { + "value": "jobs", + "indexKeyMap": {} + }, + "act": { + "value": "get", + "indexKeyMap": {} + }, + "obj": { + "value": "%/%", + "indexKeyMap": { + "0": "TeamObj", + "2": "AppObj" + } + } + }, + { + "res": { + "value": "jobs", + "indexKeyMap": {} + }, + "act": { + "value": "trigger", + "indexKeyMap": {} + }, + "obj": { + "value": "%/%", + "indexKeyMap": { + "0": "TeamObj", + "2": "AppObj" + } + } + }, + { + "res": { + "value": "jobEnv", + "indexKeyMap": {} + }, + "act": { + "value": "get", + "indexKeyMap": {} + }, + "obj": { + "value": "%/%/%", + "indexKeyMap": { + "0": "TeamObj", + "2": "EnvObj", + "4": "AppObj" + } + } + }, + { + "res": { + "value": "jobEnv", + "indexKeyMap": {} + }, + "act": { + "value": "trigger", + "indexKeyMap": {} + }, + "obj": { + "value": "%/%/%", + "indexKeyMap": { + "0": "TeamObj", + "2": "EnvObj", + "4": "AppObj" + } + } + }, + { + "res": { + "value": "team", + "indexKeyMap": {} + }, + "act": { + "value": "get", + "indexKeyMap": {} + }, + "obj": { + "value": "%", + "indexKeyMap": { + "0": "TeamObj" + } + } + }, + { + "res": { + "value": "global-environment", + "indexKeyMap": {} + }, + "act": { + "value": "get", + "indexKeyMap": {} + }, + "obj": { + "value": "%", + "indexKeyMap": { + "0": "EnvObj" + } + } + }, + { + "res": { + "value": "workflow", + "indexKeyMap": {} + }, + "act": { + "value": "get", + "indexKeyMap": {} + }, + "obj": { + "value": "%/%/%", + "indexKeyMap": { + "0": "TeamObj", + "2": "AppObj", + "4": "WorkflowObj" + } + } + }, + { + "res": { + "value": "workflow", + "indexKeyMap": {} + }, + "act": { + "value": "trigger", + "indexKeyMap": {} + }, + "obj": { + "value": "%/%/%", + "indexKeyMap": { + "0": "TeamObj", + "2": "AppObj", + "4": "WorkflowObj" + } + } + } + ] + }', 'now()', '1', 'now()', '1', true, false), + ('jobs', '', 'view', '{ + "type": { + "value": "p", + "indexKeyMap": {} + }, + "sub": { + "value": "jobs:view_%_%_%_%", + "indexKeyMap": { + "10": "Team", + "12": "Env", + "14": "App", + "16": "Workflow" + } + }, + "resActObjSet": [ + { + "res": { + "value": "jobs", + "indexKeyMap": {} + }, + "act": { + "value": "get", + "indexKeyMap": {} + }, + "obj": { + "value": "%/%", + "indexKeyMap": { + "0": "TeamObj", + "2": "AppObj" + } + } + }, + { + "res": { + "value": "jobEnv", + "indexKeyMap": {} + }, + "act": { + "value": "get", + "indexKeyMap": {} + }, + "obj": { + "value": "%/%/%", + "indexKeyMap": { + "0": "TeamObj", + "2": "EnvObj", + "4": "AppObj" + } + } + }, + { + "res": { + "value": "team", + "indexKeyMap": {} + }, + "act": { + "value": "get", + "indexKeyMap": {} + }, + "obj": { + "value": "%", + "indexKeyMap": { + "0": "TeamObj" + } + } + }, + { + "res": { + "value": "global-environment", + "indexKeyMap": {} + }, + "act": { + "value": "get", + "indexKeyMap": {} + }, + "obj": { + "value": "%", + "indexKeyMap": { + "0": "EnvObj" + } + } + }, + { + "res": { + "value": "workflow", + "indexKeyMap": {} + }, + "act": { + "value": "get", + "indexKeyMap": {} + }, + "obj": { + "value": "%/%/%", + "indexKeyMap": { + "0": "TeamObj", + "2": "AppObj", + "4": "WorkflowObj" + } + } + } + ] + }', 'now()', '1', 'now()', '1', true, false); + + + + + + + + + +INSERT INTO "public"."rbac_role_data" ("entity", "access_type", "role", "role_display_name", "role_description", + "role_data", "created_on", "created_by", "updated_on", "updated_by", + "is_preset_role", "deleted") +VALUES ('jobs', '', 'admin', 'Admin', 'Can view, run and edit jobs in selected scope', '{ + "role": { + "value": "jobs:admin_%_%_%_%", + "indexKeyMap": { + "11": "Team", + "13": "Env", + "15": "App", + "17": "Workflow" + } + }, + "team": { + "value": "%", + "indexKeyMap": { + "0": "Team" + } + }, + "entityName": { + "value": "%", + "indexKeyMap": { + "0": "App" + } + }, + "environment": { + "value": "%", + "indexKeyMap": { + "0": "Env" + } + }, + "workflow": { + "value": "%", + "indexKeyMap": { + "0": "Workflow" + } + }, + "action": { + "value": "admin", + "indexKeyMap": {} + }, + "entity": { + "value": "%", + "indexKeyMap": { + "0": "Entity" + } + }, + "accessType": { + "value": "", + "indexKeyMap": {} + } + }', 'now()', '1', 'now()', '1', true, false), + ('jobs', '', 'trigger', 'Run job', 'Can run jobs in selected scope build', '{ + "role": { + "value": "jobs:trigger_%_%_%_%", + "indexKeyMap": { + "13": "Team", + "15": "Env", + "17": "App", + "19": "Workflow" + } + }, + "team": { + "value": "%", + "indexKeyMap": { + "0": "Team" + } + }, + "entityName": { + "value": "%", + "indexKeyMap": { + "0": "App" + } + }, + "environment": { + "value": "%", + "indexKeyMap": { + "0": "Env" + } + }, + "workflow": { + "value": "%", + "indexKeyMap": { + "0": "Workflow" + } + }, + "action": { + "value": "trigger", + "indexKeyMap": {} + }, + "entity": { + "value": "%", + "indexKeyMap": { + "0": "Entity" + } + }, + "accessType": { + "value": "", + "indexKeyMap": {} + } + }', 'now()', '1', 'now()', '1', true, false), + ('jobs', '', 'view', 'View only', 'Can view selected jobs', '{ + "role": { + "value": "jobs:view_%_%_%_%", + "indexKeyMap": { + "10": "Team", + "12": "Env", + "14": "App", + "16": "Workflow" + } + }, + "team": { + "value": "%", + "indexKeyMap": { + "0": "Team" + } + }, + "entityName": { + "value": "%", + "indexKeyMap": { + "0": "App" + } + }, + "environment": { + "value": "%", + "indexKeyMap": { + "0": "Env" + } + }, + "workflow": { + "value": "%", + "indexKeyMap": { + "0": "Workflow" + } + }, + "action": { + "value": "view", + "indexKeyMap": {} + }, + "entity": { + "value": "%", + "indexKeyMap": { + "0": "Entity" + } + }, + "accessType": { + "value": "", + "indexKeyMap": {} + } + }', 'now()', '1', 'now()', '1', true, false); + + + + + +INSERT INTO rbac_policy_resource_detail ("resource", "policy_resource_value", "allowed_actions", + "resource_object", "eligible_entity_access_types", "deleted", "created_on", + "created_by", "updated_on", "updated_by") +VALUES ('jobEnv', '{ "value": "jobEnv", "indexKeyMap": {}}', ARRAY['get','update','create','delete','trigger'],'{"value": "%/%/%","indexKeyMap": {"0": "TeamObj","2": "EnvObj","4": "AppObj"}}', ARRAY['jobs'],'f','now()', '1', 'now()', '1'); + +INSERT INTO rbac_policy_resource_detail ("resource", "policy_resource_value", "allowed_actions", + "resource_object", "eligible_entity_access_types", "deleted", "created_on", + "created_by", "updated_on", "updated_by") +VALUES ('workflow', '{ "value": "workflow", "indexKeyMap": {}}', ARRAY['get','update','create','delete','trigger'],'{"value": "%/%/%","indexKeyMap": {"0": "TeamObj","2": "AppObj","4": "WorkflowObj"}}', ARRAY['jobs'],'f','now()', '1', 'now()', '1'); + + + + +UPDATE rbac_policy_resource_detail set eligible_entity_access_types = ARRAY['apps/devtron-app','apps/helm-app','jobs'] where resource='project' OR resource ='global-environment' OR resource='terminal'; + +UPDATE rbac_role_resource_detail set eligible_entity_access_types = ARRAY['apps/devtron-app','apps/helm-app','jobs'] where resource ='project' OR resource ='environment'; + +INSERT INTO rbac_role_resource_detail ("resource", "role_resource_key", "role_resource_update_key", + "eligible_entity_access_types", "deleted", "created_on", "created_by", + "updated_on", "updated_by") +VALUES ('workflow', 'Workflow', 'Workflow', ARRAY ['jobs'], false, now(), 1, now(), 1); + +Alter table roles add column IF NOT EXISTS workflow text; + + From d2f06c2cd77b22cbf70dc166d4c36328557c36ed Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 3 Nov 2023 18:28:45 +0530 Subject: [PATCH 03/76] capacity update --- pkg/user/UserCommonService.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/user/UserCommonService.go b/pkg/user/UserCommonService.go index c880a66eea..a0cb495f94 100644 --- a/pkg/user/UserCommonService.go +++ b/pkg/user/UserCommonService.go @@ -623,7 +623,7 @@ func (impl UserCommonServiceImpl) GetCapacityForRoleFilter(roleFilters []bean.Ro entityNames := strings.Split(roleFilter.EntityName, ",") environments := strings.Split(roleFilter.Environment, ",") workflows := strings.Split(roleFilter.Workflow, ",") - value := math.Max(float64(len(namespaces)*len(groups)*len(kinds)*len(resources)*2), float64(len(entityNames)*len(environments)*len(workflows)*8)) + value := math.Max(float64(len(namespaces)*len(groups)*len(kinds)*len(resources)*2), math.Max(float64(len(entityNames)*len(environments)*6), float64(len(entityNames)*len(environments)*len(workflows)*8))) m[index] = int(value) capacity += int(value) } From 7ecd961eeb3ff6c48dc4c5d1d63f5db365c7778f Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 3 Nov 2023 19:30:18 +0530 Subject: [PATCH 04/76] logs wip --- pkg/user/RoleGroupService.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pkg/user/RoleGroupService.go b/pkg/user/RoleGroupService.go index b7cfbf6d29..f732e941d6 100644 --- a/pkg/user/RoleGroupService.go +++ b/pkg/user/RoleGroupService.go @@ -401,8 +401,10 @@ func (impl RoleGroupServiceImpl) UpdateRoleGroup(request *bean.RoleGroup, token return nil, err } eliminatedPolicies = append(eliminatedPolicies, items...) + impl.logger.Infow("eliminated policies", "eliminatedPolicies", eliminatedPolicies) if len(eliminatedPolicies) > 0 { pRes := casbin2.RemovePolicy(eliminatedPolicies) + impl.logger.Infow("pRes : failed policies 1", "pRes", &pRes) println(pRes) } // DELETE PROCESS ENDS @@ -447,10 +449,12 @@ func (impl RoleGroupServiceImpl) UpdateRoleGroup(request *bean.RoleGroup, token } } } - + impl.logger.Infow("policies", "policies", policies) //updating in casbin if len(policies) > 0 { - casbin2.AddPolicy(policies) + pRes := casbin2.AddPolicy(policies) + impl.logger.Infow("pres failed policies on add policy", "pres", &pRes) + println(pRes) } //loading policy for syncing orchestrator to casbin with newly added policies //(not calling this method in above if condition because we are also removing policies in this update service) From d3c82bd9ff034fc6421421f713966c6359171fd9 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Tue, 7 Nov 2023 14:03:39 +0530 Subject: [PATCH 05/76] script number change --- scripts/sql/{184_jobs_rbac.down.sql => 188_jobs_rbac.down.sql} | 0 scripts/sql/{184_jobs_rbac.up.sql => 188_jobs_rbac.up.sql} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename scripts/sql/{184_jobs_rbac.down.sql => 188_jobs_rbac.down.sql} (100%) rename scripts/sql/{184_jobs_rbac.up.sql => 188_jobs_rbac.up.sql} (100%) diff --git a/scripts/sql/184_jobs_rbac.down.sql b/scripts/sql/188_jobs_rbac.down.sql similarity index 100% rename from scripts/sql/184_jobs_rbac.down.sql rename to scripts/sql/188_jobs_rbac.down.sql diff --git a/scripts/sql/184_jobs_rbac.up.sql b/scripts/sql/188_jobs_rbac.up.sql similarity index 100% rename from scripts/sql/184_jobs_rbac.up.sql rename to scripts/sql/188_jobs_rbac.up.sql From aa182c6d5edc870c3e14c970cdd2d76ae59c0a21 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Wed, 8 Nov 2023 15:07:30 +0530 Subject: [PATCH 06/76] fetch all workflows --- api/restHandler/AppWorkflowRestHandler.go | 35 +++++++++++++++++++++++ api/router/PipelineConfigRouter.go | 3 ++ pkg/appWorkflow/AppWorkflowService.go | 28 ++++++++++++++++-- 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/api/restHandler/AppWorkflowRestHandler.go b/api/restHandler/AppWorkflowRestHandler.go index d3ee55aa76..883eebed5e 100644 --- a/api/restHandler/AppWorkflowRestHandler.go +++ b/api/restHandler/AppWorkflowRestHandler.go @@ -47,6 +47,7 @@ type AppWorkflowRestHandler interface { FindAllWorkflows(w http.ResponseWriter, r *http.Request) FindAppWorkflowByEnvironment(w http.ResponseWriter, r *http.Request) GetWorkflowsViewData(w http.ResponseWriter, r *http.Request) + FindAllWorkflowsForApps(w http.ResponseWriter, r *http.Request) } type AppWorkflowRestHandlerImpl struct { @@ -258,6 +259,40 @@ func (impl AppWorkflowRestHandlerImpl) FindAllWorkflows(w http.ResponseWriter, r common.WriteJsonResp(w, nil, resp, http.StatusOK) } +func (impl AppWorkflowRestHandlerImpl) FindAllWorkflowsForApps(w http.ResponseWriter, r *http.Request) { + decoder := json.NewDecoder(r.Body) + userId, err := impl.userAuthService.GetLoggedInUser(r) + if userId == 0 || err != nil { + common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + return + } + // RBAC enforcer applying + isSuperAdmin, err := impl.userAuthService.IsSuperAdmin(int(userId)) + if !isSuperAdmin || err != nil { + if err != nil { + impl.Logger.Errorw("request err, CheckSuperAdmin", "err", isSuperAdmin, "isSuperAdmin", isSuperAdmin) + } + common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) + return + } + //RBAC enforcer Ends + var request appWorkflow.WorkflowNamesRequest + err = decoder.Decode(&request) + if err != nil { + impl.Logger.Errorw("decode err", "err", err) + common.WriteJsonResp(w, err, nil, http.StatusBadRequest) + return + } + + resp, err := impl.appWorkflowService.FindAllWorkflowsForApps(request) + if err != nil { + impl.Logger.Errorw("error in getting all wf component details by appId", "err", err, "request", request) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } + common.WriteJsonResp(w, nil, resp, http.StatusOK) +} + func (impl AppWorkflowRestHandlerImpl) FindAppWorkflowByEnvironment(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) userId, err := impl.userAuthService.GetLoggedInUser(r) diff --git a/api/router/PipelineConfigRouter.go b/api/router/PipelineConfigRouter.go index e09d34cf5d..92b79ad8fc 100644 --- a/api/router/PipelineConfigRouter.go +++ b/api/router/PipelineConfigRouter.go @@ -152,6 +152,9 @@ func (router PipelineConfigRouterImpl) initPipelineConfigRouter(configRouter *mu configRouter.Path("/wf/all/component-names/{appId}"). HandlerFunc(router.appWorkflowRestHandler.FindAllWorkflows).Methods("GET") + configRouter.Path("/app-wf/all"). + HandlerFunc(router.appWorkflowRestHandler.FindAllWorkflowsForApps).Methods("POST") + configRouter.Path("/cd-pipeline/workflow/history/{appId}/{environmentId}/{pipelineId}").HandlerFunc(router.restHandler.ListDeploymentHistory).Methods("GET") configRouter.Path("/cd-pipeline/workflow/logs/{appId}/{environmentId}/{pipelineId}/{workflowId}").HandlerFunc(router.restHandler.GetPrePostDeploymentLogs).Methods("GET") configRouter.Path("/cd-pipeline/workflow/trigger-info/{appId}/{environmentId}/{pipelineId}/{workflowRunnerId}").HandlerFunc(router.restHandler.FetchCdWorkflowDetails).Methods("GET") diff --git a/pkg/appWorkflow/AppWorkflowService.go b/pkg/appWorkflow/AppWorkflowService.go index b4ceedb2f7..dd7ff3547b 100644 --- a/pkg/appWorkflow/AppWorkflowService.go +++ b/pkg/appWorkflow/AppWorkflowService.go @@ -54,7 +54,7 @@ type AppWorkflowService interface { FindAllWorkflowsComponentDetails(appId int) (*AllAppWorkflowComponentDetails, error) FindAppWorkflowsByEnvironmentId(request resourceGroup2.ResourceGroupingRequest) ([]*AppWorkflowDto, error) - + FindAllWorkflowsForApps(request WorkflowNamesRequest) (*WorkflowNamesResponse, error) FilterWorkflows(triggerViewConfig *TriggerViewWorkflowConfig, envIds []int) (*TriggerViewWorkflowConfig, error) FindCdPipelinesByAppId(appId int) (*bean.CdPipelines, error) } @@ -123,6 +123,14 @@ type WorkflowComponentNamesDto struct { CdPipelines []string `json:"cdPipelines"` } +type WorkflowNamesResponse struct { + WorkflowNames []string `json:"workflowNames"` +} + +type WorkflowNamesRequest struct { + AppIds []int `json:"appIds"` +} + type WorkflowCloneRequest struct { WorkflowName string `json:"workflowName,omitempty"` AppId int `json:"appId,omitempty"` @@ -571,7 +579,7 @@ func (impl AppWorkflowServiceImpl) FindAppWorkflowsByEnvironmentId(request resou if err != nil { return nil, err } - //override appIds if already provided app group id in request. + //override AppIds if already provided app group id in request. request.ResourceIds = appIds } var pipelines []*pipelineConfig.Pipeline @@ -649,6 +657,22 @@ func (impl AppWorkflowServiceImpl) FindAppWorkflowsByEnvironmentId(request resou return workflows, err } +func (impl AppWorkflowServiceImpl) FindAllWorkflowsForApps(request WorkflowNamesRequest) (*WorkflowNamesResponse, error) { + appWorkflows, err := impl.appWorkflowRepository.FindByAppIds(request.AppIds) + if err != nil && err != pg.ErrNoRows { + impl.Logger.Errorw("error occurred while fetching app workflows", "AppIds", request.AppIds, "err", err) + return nil, err + } + var workflows []string + for _, workflow := range appWorkflows { + workflows = append(workflows, workflow.Name) + } + workflowResp := &WorkflowNamesResponse{ + WorkflowNames: workflows, + } + return workflowResp, err +} + func (impl AppWorkflowServiceImpl) FilterWorkflows(triggerViewConfig *TriggerViewWorkflowConfig, envIds []int) (*TriggerViewWorkflowConfig, error) { cdPipelines := triggerViewConfig.CdPipelines.Pipelines cdPipelineIdsFiltered := mapset.NewSet() From 90404a27ee2ac7befc85bca204d4574d4cfad0f1 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Thu, 9 Nov 2023 13:46:00 +0530 Subject: [PATCH 07/76] rbac in apis --- api/restHandler/AppRestHandler.go | 12 +++++++++-- api/restHandler/ConfigMapRestHandler.go | 12 +++++++++-- .../app/PipelineConfigRestHandler.go | 21 +++++++++---------- pkg/user/casbin/rbacpolicy.go | 4 ++++ util/rbac/EnforcerUtil.go | 9 ++++++++ 5 files changed, 43 insertions(+), 15 deletions(-) diff --git a/api/restHandler/AppRestHandler.go b/api/restHandler/AppRestHandler.go index de0a3ac16f..8e44572b67 100644 --- a/api/restHandler/AppRestHandler.go +++ b/api/restHandler/AppRestHandler.go @@ -207,7 +207,11 @@ func (handler AppRestHandlerImpl) UpdateApp(w http.ResponseWriter, r *http.Reque // check for existing project/app permission object := handler.enforcerUtil.GetAppRBACNameByAppId(request.Id) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionUpdate, object); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionUpdate, object) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionUpdate, object) + } + if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } @@ -372,7 +376,11 @@ func (handler AppRestHandlerImpl) UpdateAppNote(w http.ResponseWriter, r *http.R // check for existing project/app permission object := handler.enforcerUtil.GetAppRBACNameByAppId(bean.Identifier) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionUpdate, object); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionUpdate, object) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionUpdate, object) + } + if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } diff --git a/api/restHandler/ConfigMapRestHandler.go b/api/restHandler/ConfigMapRestHandler.go index adf881c1f0..1e02ae7091 100644 --- a/api/restHandler/ConfigMapRestHandler.go +++ b/api/restHandler/ConfigMapRestHandler.go @@ -112,7 +112,11 @@ func (handler ConfigMapRestHandlerImpl) CMGlobalAddUpdate(w http.ResponseWriter, //RBAC START token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(configMapRequest.AppId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, object); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, object) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionCreate, object) + } + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } @@ -336,7 +340,11 @@ func (handler ConfigMapRestHandlerImpl) CSGlobalAddUpdate(w http.ResponseWriter, //RBAC START token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(configMapRequest.AppId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, object); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, object) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionCreate, object) + } + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } diff --git a/api/restHandler/app/PipelineConfigRestHandler.go b/api/restHandler/app/PipelineConfigRestHandler.go index 2060f5b973..62b32c87e1 100644 --- a/api/restHandler/app/PipelineConfigRestHandler.go +++ b/api/restHandler/app/PipelineConfigRestHandler.go @@ -340,16 +340,6 @@ func (handler PipelineConfigRestHandlerImpl) CreateApp(w http.ResponseWriter, r common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } - if createRequest.AppType == helper.Job { - isSuperAdmin, err := handler.userAuthService.IsSuperAdmin(int(userId)) - if !isSuperAdmin || err != nil { - if err != nil { - handler.Logger.Errorw("request err, CheckSuperAdmin", "err", isSuperAdmin, "isSuperAdmin", isSuperAdmin) - } - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) - return - } - } handler.Logger.Infow("request payload, CreateApp", "CreateApp", createRequest) err = handler.validator.Struct(createRequest) if err != nil { @@ -363,8 +353,17 @@ func (handler PipelineConfigRestHandlerImpl) CreateApp(w http.ResponseWriter, r common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } + isAuthorised := false // with admin roles, you have to access for all the apps of the project to create new app. (admin or manager with specific app permission can't create app.) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, fmt.Sprintf("%s/%s", strings.ToLower(project.Name), "*")); !ok { + if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, fmt.Sprintf("%s/%s", strings.ToLower(project.Name), "*")); ok { + isAuthorised = true + } + if !isAuthorised { + if ok := handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionCreate, fmt.Sprintf("%s/%s", strings.ToLower(project.Name), "*")); ok { + isAuthorised = true + } + } + if !isAuthorised { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } diff --git a/pkg/user/casbin/rbacpolicy.go b/pkg/user/casbin/rbacpolicy.go index 5755a3b2e3..10173054d1 100644 --- a/pkg/user/casbin/rbacpolicy.go +++ b/pkg/user/casbin/rbacpolicy.go @@ -37,6 +37,10 @@ const ( ResourceAutocomplete = "autocomplete" ResourceChartGroup = "chart-group" + ResourceJobs = "jobs" + ResourceJobsEnv = "jobEnv" + ResourceWorkflow = "workflow" + ResourceTeam = "team" ResourceAdmin = "admin" ResourceGlobal = "global-resource" diff --git a/util/rbac/EnforcerUtil.go b/util/rbac/EnforcerUtil.go index 693ad2eb28..48e8dfee57 100644 --- a/util/rbac/EnforcerUtil.go +++ b/util/rbac/EnforcerUtil.go @@ -63,6 +63,7 @@ type EnforcerUtil interface { GetAllActiveTeamNames() ([]string, error) GetRbacObjectsByEnvIdsAndAppId(envIds []int, appId int) (map[int]string, map[string]string) GetAppRBACNameByAppAndProjectName(projectName, appName string) string + GetRbacObjectNameByAppAndWorkflowId(appName, workflowName string) string } type EnforcerUtilImpl struct { @@ -608,3 +609,11 @@ func (impl EnforcerUtilImpl) GetAllActiveTeamNames() ([]string, error) { func (impl EnforcerUtilImpl) GetAppRBACNameByAppAndProjectName(projectName, appName string) string { return fmt.Sprintf("%s/%s", projectName, appName) } + +func (impl EnforcerUtilImpl) GetRbacObjectNameByAppAndWorkflowId(appName, workflowName string) string { + application, err := impl.appRepo.FindAppAndProjectByAppName(appName) + if err != nil { + return fmt.Sprintf("%s/%s/%s", "", appName, workflowName) + } + return fmt.Sprintf("%s/%s/%s", application.Team.Name, appName, workflowName) +} From 2edc613d99c1a6fd69fffa4258f407b929e26d63 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 10 Nov 2023 11:02:17 +0530 Subject: [PATCH 08/76] workflow-api-change --- pkg/appWorkflow/AppWorkflowService.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/pkg/appWorkflow/AppWorkflowService.go b/pkg/appWorkflow/AppWorkflowService.go index dd7ff3547b..7abc024619 100644 --- a/pkg/appWorkflow/AppWorkflowService.go +++ b/pkg/appWorkflow/AppWorkflowService.go @@ -124,7 +124,7 @@ type WorkflowComponentNamesDto struct { } type WorkflowNamesResponse struct { - WorkflowNames []string `json:"workflowNames"` + AppIdWorkflowNamesMapping map[int][]string `json:"appIdWorkflowNamesMapping"` } type WorkflowNamesRequest struct { @@ -663,12 +663,18 @@ func (impl AppWorkflowServiceImpl) FindAllWorkflowsForApps(request WorkflowNames impl.Logger.Errorw("error occurred while fetching app workflows", "AppIds", request.AppIds, "err", err) return nil, err } - var workflows []string + appIdWorkflowMap := make(map[int][]string) for _, workflow := range appWorkflows { - workflows = append(workflows, workflow.Name) + if workflows, ok := appIdWorkflowMap[workflow.AppId]; ok { + workflows = append(workflows, workflow.Name) + appIdWorkflowMap[workflow.AppId] = workflows + } else { + appIdWorkflowMap[workflow.AppId] = []string{workflow.Name} + + } } workflowResp := &WorkflowNamesResponse{ - WorkflowNames: workflows, + AppIdWorkflowNamesMapping: appIdWorkflowMap, } return workflowResp, err } From 019010d50ebe20df207af552425c14e4fad4a051 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 10 Nov 2023 11:23:06 +0530 Subject: [PATCH 09/76] casbin-script --- scripts/casbin/7_jobs_rbac.up.sql | 5 +++++ scripts/casbin/8_jobs_rbac.down.sql | 3 +++ 2 files changed, 8 insertions(+) create mode 100644 scripts/casbin/7_jobs_rbac.up.sql create mode 100644 scripts/casbin/8_jobs_rbac.down.sql diff --git a/scripts/casbin/7_jobs_rbac.up.sql b/scripts/casbin/7_jobs_rbac.up.sql new file mode 100644 index 0000000000..8dd138c046 --- /dev/null +++ b/scripts/casbin/7_jobs_rbac.up.sql @@ -0,0 +1,5 @@ +INSERT INTO "public"."casbin_rule" ("p_type", "v0", "v1", "v2", "v3", "v4", "v5") VALUES +('p','role:super-admin___','jobs','*','*','allow',''), +('p','role:super-admin___','jobEnv','*','*','allow',''), +('p','role:super-admin___','workflow','*','*','allow',''); + diff --git a/scripts/casbin/8_jobs_rbac.down.sql b/scripts/casbin/8_jobs_rbac.down.sql new file mode 100644 index 0000000000..c79dcb39af --- /dev/null +++ b/scripts/casbin/8_jobs_rbac.down.sql @@ -0,0 +1,3 @@ +DELETE FROM casbin_rule where v0='role:super-admin___' and v1='jobs'; +DELETE FROM casbin_rule where v0='role:super-admin___' and v1='jobEnv'; +DELETE FROM casbin_rule where v0='role:super-admin___' and v1='workflow'; \ No newline at end of file From 8d2ea1b14e4aec80661559ca092640698fa7b5e6 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 10 Nov 2023 11:32:08 +0530 Subject: [PATCH 10/76] rbac-enforcement --- api/restHandler/AppListingRestHandler.go | 37 ++++++++- api/restHandler/AppRestHandler.go | 3 +- api/restHandler/BulkUpdateRestHandler.go | 3 +- .../app/BuildPipelineRestHandler.go | 83 +++++++++---------- internal/sql/repository/app/AppRepository.go | 6 +- pkg/commonService/CommonService.go | 3 +- util/rbac/EnforcerUtil.go | 9 +- 7 files changed, 87 insertions(+), 57 deletions(-) diff --git a/api/restHandler/AppListingRestHandler.go b/api/restHandler/AppListingRestHandler.go index d0d644f723..02ce0a1534 100644 --- a/api/restHandler/AppListingRestHandler.go +++ b/api/restHandler/AppListingRestHandler.go @@ -212,6 +212,11 @@ func (handler AppListingRestHandlerImpl) FetchJobs(w http.ResponseWriter, r *htt common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) return } + user, err := handler.userService.GetById(userId) + if userId == 0 || err != nil { + common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + return + } isSuperAdmin, err := handler.userService.IsSuperAdmin(int(userId)) if !isSuperAdmin || err != nil { if err != nil { @@ -220,6 +225,34 @@ func (handler AppListingRestHandlerImpl) FetchJobs(w http.ResponseWriter, r *htt common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } + validAppIds := make([]int, 0) + //for non super admin users + if !isSuperAdmin { + userEmailId := strings.ToLower(user.EmailId) + rbacObjectsForAllAppsMap := handler.enforcerUtil.GetRbacObjectsForAllApps(helper.Job) + rbacObjectToAppIdMap := make(map[string]int) + rbacObjects := make([]string, len(rbacObjectsForAllAppsMap)) + itr := 0 + for appId, object := range rbacObjectsForAllAppsMap { + rbacObjects[itr] = object + rbacObjectToAppIdMap[object] = appId + itr++ + } + + result := handler.enforcer.EnforceByEmailInBatch(userEmailId, casbin.ResourceJobs, casbin.ActionGet, rbacObjects) + //O(n) loop, n = len(rbacObjectsForAllAppsMap) + for object, ok := range result { + if ok { + validAppIds = append(validAppIds, rbacObjectToAppIdMap[object]) + } + } + + if len(validAppIds) == 0 { + handler.logger.Infow("user doesn't have access to any app", "userId", userId) + common.WriteJsonResp(w, err, bean.JobContainerResponse{}, http.StatusOK) + return + } + } var fetchJobListingRequest app.FetchAppListingRequest decoder := json.NewDecoder(r.Body) err = decoder.Decode(&fetchJobListingRequest) @@ -228,6 +261,8 @@ func (handler AppListingRestHandlerImpl) FetchJobs(w http.ResponseWriter, r *htt common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } + // fetching only those jobs whose access user has by setting valid app Ids. + fetchJobListingRequest.AppIds = validAppIds jobs, err := handler.appListingService.FetchJobs(fetchJobListingRequest) if err != nil { handler.logger.Errorw("service err, FetchJobs", "err", err, "payload", fetchJobListingRequest) @@ -718,7 +753,7 @@ func (handler AppListingRestHandlerImpl) FetchAppsByEnvironmentV2(w http.Respons //for non super admin users if !isActionUserSuperAdmin { userEmailId := strings.ToLower(user.EmailId) - rbacObjectsForAllAppsMap := handler.enforcerUtil.GetRbacObjectsForAllApps() + rbacObjectsForAllAppsMap := handler.enforcerUtil.GetRbacObjectsForAllApps(helper.CustomApp) rbacObjectToAppIdMap := make(map[string]int) rbacObjects := make([]string, len(rbacObjectsForAllAppsMap)) itr := 0 diff --git a/api/restHandler/AppRestHandler.go b/api/restHandler/AppRestHandler.go index 8e44572b67..3dc2f0e2b0 100644 --- a/api/restHandler/AppRestHandler.go +++ b/api/restHandler/AppRestHandler.go @@ -21,6 +21,7 @@ import ( "encoding/json" client "github.com/devtron-labs/devtron/api/helm-app" "github.com/devtron-labs/devtron/api/restHandler/common" + "github.com/devtron-labs/devtron/internal/sql/repository/helper" "github.com/devtron-labs/devtron/pkg/app" "github.com/devtron-labs/devtron/pkg/bean" "github.com/devtron-labs/devtron/pkg/genericNotes" @@ -90,7 +91,7 @@ func (handler AppRestHandlerImpl) GetAllLabels(w http.ResponseWriter, r *http.Re common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) return } - objects := handler.enforcerUtil.GetRbacObjectsForAllApps() + objects := handler.enforcerUtil.GetRbacObjectsForAllApps(helper.CustomApp) for _, label := range labels { object := objects[label.AppId] if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); ok { diff --git a/api/restHandler/BulkUpdateRestHandler.go b/api/restHandler/BulkUpdateRestHandler.go index 1ce3fb268e..462020eeeb 100644 --- a/api/restHandler/BulkUpdateRestHandler.go +++ b/api/restHandler/BulkUpdateRestHandler.go @@ -7,6 +7,7 @@ import ( "github.com/devtron-labs/devtron/api/restHandler/common" "github.com/devtron-labs/devtron/client/argocdServer/application" "github.com/devtron-labs/devtron/client/gitSensor" + "github.com/devtron-labs/devtron/internal/sql/repository/helper" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig" "github.com/devtron-labs/devtron/internal/sql/repository/security" "github.com/devtron-labs/devtron/pkg/appClone" @@ -228,7 +229,7 @@ func (handler BulkUpdateRestHandlerImpl) BulkUpdate(w http.ResponseWriter, r *ht common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) return } - rbacObjects := handler.enforcerUtil.GetRbacObjectsForAllApps() + rbacObjects := handler.enforcerUtil.GetRbacObjectsForAllApps(helper.CustomApp) for _, deploymentTemplateImpactedApp := range impactedApps.DeploymentTemplate { ok := handler.CheckAuthForBulkUpdate(deploymentTemplateImpactedApp.AppId, deploymentTemplateImpactedApp.EnvId, deploymentTemplateImpactedApp.AppName, rbacObjects, token) if !ok { diff --git a/api/restHandler/app/BuildPipelineRestHandler.go b/api/restHandler/app/BuildPipelineRestHandler.go index 225fef0dcc..1d2ea9795c 100644 --- a/api/restHandler/app/BuildPipelineRestHandler.go +++ b/api/restHandler/app/BuildPipelineRestHandler.go @@ -355,11 +355,11 @@ func (handler PipelineConfigRestHandlerImpl) PatchCiPipelines(w http.ResponseWri common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) return } - isSuperAdmin, err := handler.userAuthService.IsSuperAdmin(int(userId)) - if err != nil { - common.WriteJsonResp(w, err, "failed to check if user is super admin", http.StatusInternalServerError) - return - } + //isSuperAdmin, err := handler.userAuthService.IsSuperAdmin(int(userId)) + //if err != nil { + // common.WriteJsonResp(w, err, "failed to check if user is super admin", http.StatusInternalServerError) + // return + //} var patchRequest bean.CiPatchRequest err = decoder.Decode(&patchRequest) patchRequest.UserId = userId @@ -382,13 +382,18 @@ func (handler PipelineConfigRestHandlerImpl) PatchCiPipelines(w http.ResponseWri common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } - + appWorkflow, err := handler.appWorkflowService.FindAppWorkflowById(patchRequest.AppWorkflowId, app.Id) + if err != nil { + handler.Logger.Errorw("error in getting app workflow", "err", err, "workflowId", patchRequest.AppWorkflowId, "appId", app.Id) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } resourceName := handler.enforcerUtil.GetAppRBACName(app.AppName) + workflowResourceName := handler.enforcerUtil.GetRbacObjectNameByAppAndWorkflowId(app.AppName, appWorkflow.Name) var ok bool - if app.AppType == helper.Job { - ok = isSuperAdmin - } else { - ok = handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, resourceName) + ok = handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, resourceName) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionCreate, resourceName) && handler.enforcer.Enforce(token, casbin.ResourceWorkflow, casbin.ActionCreate, workflowResourceName) } if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) @@ -1141,27 +1146,20 @@ func (handler PipelineConfigRestHandlerImpl) CreateMaterial(w http.ResponseWrite common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } - app, err := handler.pipelineBuilder.GetApp(createMaterialDto.AppId) - if err != nil { - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) - return + isAuthorised := false + resourceObject := handler.enforcerUtil.GetAppRBACNameByAppId(createMaterialDto.AppId) + if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, resourceObject); ok { + isAuthorised = true } - if app.AppType == helper.Job { - isSuperAdmin, err := handler.userAuthService.IsSuperAdmin(int(userId)) - if !isSuperAdmin || err != nil { - if err != nil { - handler.Logger.Errorw("request err, CheckSuperAdmin", "err", isSuperAdmin, "isSuperAdmin", isSuperAdmin) - } - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) - return - } - } else { - resourceObject := handler.enforcerUtil.GetAppRBACNameByAppId(createMaterialDto.AppId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, resourceObject); !ok { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) - return + if !isAuthorised { + if ok := handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionCreate, resourceObject); ok { + isAuthorised = true } } + if !isAuthorised { + common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) + return + } for _, gitMaterial := range createMaterialDto.Material { validationResult, err := handler.ValidateGitMaterialUrl(gitMaterial.GitProviderId, gitMaterial.Url) if err != nil { @@ -1221,27 +1219,20 @@ func (handler PipelineConfigRestHandlerImpl) UpdateMaterial(w http.ResponseWrite return } } - app, err := handler.pipelineBuilder.GetApp(updateMaterialDto.AppId) - if err != nil { - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) - return + isAuthorised := false + resourceObject := handler.enforcerUtil.GetAppRBACNameByAppId(updateMaterialDto.AppId) + if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, resourceObject); ok { + isAuthorised = true } - if app.AppType == helper.Job { - isSuperAdmin, err := handler.userAuthService.IsSuperAdmin(int(userId)) - if !isSuperAdmin || err != nil { - if err != nil { - handler.Logger.Errorw("request err, CheckSuperAdmin", "err", isSuperAdmin, "isSuperAdmin", isSuperAdmin) - } - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) - return - } - } else { - resourceObject := handler.enforcerUtil.GetAppRBACNameByAppId(updateMaterialDto.AppId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, resourceObject); !ok { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) - return + if !isAuthorised { + if ok := handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionCreate, resourceObject); ok { + isAuthorised = true } } + if !isAuthorised { + common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) + return + } createResp, err := handler.pipelineBuilder.UpdateMaterialsForApp(&updateMaterialDto) if err != nil { diff --git a/internal/sql/repository/app/AppRepository.go b/internal/sql/repository/app/AppRepository.go index 650980ecb1..2ed65be8db 100644 --- a/internal/sql/repository/app/AppRepository.go +++ b/internal/sql/repository/app/AppRepository.go @@ -57,7 +57,7 @@ type AppRepository interface { FindAppsByTeamName(teamName string) ([]App, error) FindAll() ([]*App, error) FindAppsByEnvironmentId(environmentId int) ([]App, error) - FindAllActiveAppsWithTeam() ([]*App, error) + FindAllActiveAppsWithTeam(appType helper.AppType) ([]*App, error) FindAllActiveAppsWithTeamWithTeamId(teamID int) ([]*App, error) CheckAppExists(appNames []string) ([]*App, error) @@ -229,10 +229,10 @@ func (repo AppRepositoryImpl) FindAppsByEnvironmentId(environmentId int) ([]App, return apps, err } -func (repo AppRepositoryImpl) FindAllActiveAppsWithTeam() ([]*App, error) { +func (repo AppRepositoryImpl) FindAllActiveAppsWithTeam(appType helper.AppType) ([]*App, error) { var apps []*App err := repo.dbConnection.Model(&apps).Column("Team"). - Where("app.active = ?", true).Where("app.app_type = ?", 0). + Where("app.active = ?", true).Where("app.app_type = ?", appType). Select() return apps, err } diff --git a/pkg/commonService/CommonService.go b/pkg/commonService/CommonService.go index 57011e11dd..c60e37d0de 100644 --- a/pkg/commonService/CommonService.go +++ b/pkg/commonService/CommonService.go @@ -22,6 +22,7 @@ import ( "github.com/devtron-labs/devtron/internal/sql/repository/app" "github.com/devtron-labs/devtron/internal/sql/repository/chartConfig" dockerRegistryRepository "github.com/devtron-labs/devtron/internal/sql/repository/dockerRegistry" + helper2 "github.com/devtron-labs/devtron/internal/sql/repository/helper" "github.com/devtron-labs/devtron/pkg/attributes" chartRepoRepository "github.com/devtron-labs/devtron/pkg/chartRepo/repository" repository3 "github.com/devtron-labs/devtron/pkg/cluster/repository" @@ -191,7 +192,7 @@ func (impl *CommonServiceImpl) GlobalChecklist() (*GlobalChecklist, error) { ChartChecklist: chartChecklist, } - apps, err := impl.appRepository.FindAllActiveAppsWithTeam() + apps, err := impl.appRepository.FindAllActiveAppsWithTeam(helper2.CustomApp) if err != nil && err != pg.ErrNoRows { impl.logger.Errorw("GlobalChecklist, error while getting error", "err", err) return nil, err diff --git a/util/rbac/EnforcerUtil.go b/util/rbac/EnforcerUtil.go index 48e8dfee57..2b2905fe26 100644 --- a/util/rbac/EnforcerUtil.go +++ b/util/rbac/EnforcerUtil.go @@ -20,6 +20,7 @@ package rbac import ( "fmt" "github.com/devtron-labs/common-lib/utils/k8s" + "github.com/devtron-labs/devtron/internal/sql/repository/helper" "github.com/devtron-labs/devtron/util" "github.com/devtron-labs/devtron/internal/sql/repository/app" @@ -34,7 +35,7 @@ import ( type EnforcerUtil interface { GetAppRBACName(appName string) string - GetRbacObjectsForAllApps() map[int]string + GetRbacObjectsForAllApps(appType helper.AppType) map[int]string GetRbacObjectsForAllAppsWithTeamID(teamID int) map[int]string GetAppRBACNameByAppId(appId int) string GetAppRBACByAppNameAndEnvId(appName string, envId int) string @@ -153,9 +154,9 @@ func (impl EnforcerUtilImpl) GetProjectAdminRBACNameBYAppName(appName string) st return fmt.Sprintf("%s/%s", application.Team.Name, "*") } -func (impl EnforcerUtilImpl) GetRbacObjectsForAllApps() map[int]string { +func (impl EnforcerUtilImpl) GetRbacObjectsForAllApps(appType helper.AppType) map[int]string { objects := make(map[int]string) - result, err := impl.appRepo.FindAllActiveAppsWithTeam() + result, err := impl.appRepo.FindAllActiveAppsWithTeam(appType) if err != nil { return objects } @@ -321,7 +322,7 @@ func (impl EnforcerUtilImpl) GetTeamAndEnvironmentRbacObjectByCDPipelineId(pipel func (impl EnforcerUtilImpl) GetRbacObjectsForAllAppsAndEnvironments() (map[int]string, map[string]string) { appObjects := make(map[int]string) envObjects := make(map[string]string) - apps, err := impl.appRepo.FindAllActiveAppsWithTeam() + apps, err := impl.appRepo.FindAllActiveAppsWithTeam(helper.CustomApp) if err != nil { impl.logger.Errorw("exception while fetching all active apps for rbac objects", "err", err) return appObjects, envObjects From c22d0070f215ac969e996e71ca85759e8dac2e2e Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 10 Nov 2023 13:09:07 +0530 Subject: [PATCH 11/76] appids null --- pkg/appWorkflow/AppWorkflowService.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/appWorkflow/AppWorkflowService.go b/pkg/appWorkflow/AppWorkflowService.go index 7abc024619..0bb3265cc7 100644 --- a/pkg/appWorkflow/AppWorkflowService.go +++ b/pkg/appWorkflow/AppWorkflowService.go @@ -658,6 +658,9 @@ func (impl AppWorkflowServiceImpl) FindAppWorkflowsByEnvironmentId(request resou } func (impl AppWorkflowServiceImpl) FindAllWorkflowsForApps(request WorkflowNamesRequest) (*WorkflowNamesResponse, error) { + if len(request.AppIds) == 0 { + return &WorkflowNamesResponse{}, nil + } appWorkflows, err := impl.appWorkflowRepository.FindByAppIds(request.AppIds) if err != nil && err != pg.ErrNoRows { impl.Logger.Errorw("error occurred while fetching app workflows", "AppIds", request.AppIds, "err", err) From 92a69777d5733eb1e88ae171b8e4e4b1e5e2138b Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 10 Nov 2023 13:10:15 +0530 Subject: [PATCH 12/76] workflow app ids len --- pkg/appWorkflow/AppWorkflowService.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/appWorkflow/AppWorkflowService.go b/pkg/appWorkflow/AppWorkflowService.go index 7abc024619..0bb3265cc7 100644 --- a/pkg/appWorkflow/AppWorkflowService.go +++ b/pkg/appWorkflow/AppWorkflowService.go @@ -658,6 +658,9 @@ func (impl AppWorkflowServiceImpl) FindAppWorkflowsByEnvironmentId(request resou } func (impl AppWorkflowServiceImpl) FindAllWorkflowsForApps(request WorkflowNamesRequest) (*WorkflowNamesResponse, error) { + if len(request.AppIds) == 0 { + return &WorkflowNamesResponse{}, nil + } appWorkflows, err := impl.appWorkflowRepository.FindByAppIds(request.AppIds) if err != nil && err != pg.ErrNoRows { impl.Logger.Errorw("error occurred while fetching app workflows", "AppIds", request.AppIds, "err", err) From c373c96eac0436e069aabe2179b03942afacdc0d Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 10 Nov 2023 16:25:27 +0530 Subject: [PATCH 13/76] rbac enforcement --- api/restHandler/AppListingRestHandler.go | 22 +++++---- api/restHandler/AppRestHandler.go | 6 ++- api/restHandler/AppWorkflowRestHandler.go | 13 ++++- api/restHandler/ConfigMapRestHandler.go | 46 +++++++++++------ .../app/BuildPipelineRestHandler.go | 49 +++++++++++++++++-- .../app/PipelineConfigRestHandler.go | 27 +++------- .../appWorkflow/AppWorkflowRepository.go | 11 +++++ pkg/appWorkflow/AppWorkflowService.go | 11 +++++ util/rbac/EnforcerUtil.go | 41 +++++++++++++++- 9 files changed, 171 insertions(+), 55 deletions(-) diff --git a/api/restHandler/AppListingRestHandler.go b/api/restHandler/AppListingRestHandler.go index 02ce0a1534..57b4b4189d 100644 --- a/api/restHandler/AppListingRestHandler.go +++ b/api/restHandler/AppListingRestHandler.go @@ -261,8 +261,10 @@ func (handler AppListingRestHandlerImpl) FetchJobs(w http.ResponseWriter, r *htt common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } - // fetching only those jobs whose access user has by setting valid app Ids. - fetchJobListingRequest.AppIds = validAppIds + if !isSuperAdmin { + // fetching only those jobs whose access user has by setting valid app Ids. + fetchJobListingRequest.AppIds = validAppIds + } jobs, err := handler.appListingService.FetchJobs(fetchJobListingRequest) if err != nil { handler.logger.Errorw("service err, FetchJobs", "err", err, "payload", fetchJobListingRequest) @@ -294,14 +296,6 @@ func (handler AppListingRestHandlerImpl) FetchJobOverviewCiPipelines(w http.Resp common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) return } - isSuperAdmin, err := handler.userService.IsSuperAdmin(int(userId)) - if !isSuperAdmin || err != nil { - if err != nil { - handler.logger.Errorw("request err, CheckSuperAdmin", "err", isSuperAdmin, "isSuperAdmin", isSuperAdmin) - } - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) - return - } vars := mux.Vars(r) jobId, err := strconv.Atoi(vars["jobId"]) if err != nil { @@ -309,6 +303,14 @@ func (handler AppListingRestHandlerImpl) FetchJobOverviewCiPipelines(w http.Resp common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } + //RBAC + token := r.Header.Get("token") + object := handler.enforcerUtil.GetAppRBACNameByAppId(jobId) + if ok := handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object); !ok { + common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) + return + } + //RBAC ENDS job, err := handler.pipeline.GetApp(jobId) if err != nil || job == nil || job.AppType != helper.Job { handler.logger.Errorw("Job with the given Id does not exist", "err", err, "jobId", jobId) diff --git a/api/restHandler/AppRestHandler.go b/api/restHandler/AppRestHandler.go index 3dc2f0e2b0..558de715eb 100644 --- a/api/restHandler/AppRestHandler.go +++ b/api/restHandler/AppRestHandler.go @@ -118,7 +118,11 @@ func (handler AppRestHandlerImpl) GetAppMetaInfo(w http.ResponseWriter, r *http. //rback implementation starts here token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) + } + if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } diff --git a/api/restHandler/AppWorkflowRestHandler.go b/api/restHandler/AppWorkflowRestHandler.go index 883eebed5e..cdc0a9f44e 100644 --- a/api/restHandler/AppWorkflowRestHandler.go +++ b/api/restHandler/AppWorkflowRestHandler.go @@ -131,11 +131,22 @@ func (handler AppWorkflowRestHandlerImpl) DeleteAppWorkflow(w http.ResponseWrite common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } + appWorkflow, err := handler.appWorkflowService.FindAppWorkflowById(appWorkflowId, appId) + if err != nil { + handler.Logger.Errorw("bad request", "err", err) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } token := r.Header.Get("token") //rbac block starts from here resourceName := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionDelete, resourceName); !ok { + workflowResourceName := handler.enforcerUtil.GetRbacObjectNameByAppIdAndWorkflow(appId, appWorkflow.Name) + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionDelete, resourceName) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionDelete, resourceName) && handler.enforcer.Enforce(token, casbin.ResourceWorkflow, casbin.ActionDelete, workflowResourceName) + } + if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } diff --git a/api/restHandler/ConfigMapRestHandler.go b/api/restHandler/ConfigMapRestHandler.go index 1e02ae7091..4d389fbc7f 100644 --- a/api/restHandler/ConfigMapRestHandler.go +++ b/api/restHandler/ConfigMapRestHandler.go @@ -224,7 +224,11 @@ func (handler ConfigMapRestHandlerImpl) CMGlobalFetchForEdit(w http.ResponseWrit } token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) + } + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } @@ -495,7 +499,11 @@ func (handler ConfigMapRestHandlerImpl) CMGlobalDelete(w http.ResponseWriter, r //RBAC START token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionDelete, object); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionDelete, object) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionDelete, object) + } + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), nil, http.StatusForbidden) return } @@ -586,7 +594,11 @@ func (handler ConfigMapRestHandlerImpl) CSGlobalDelete(w http.ResponseWriter, r //RBAC START token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionDelete, object); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionDelete, object) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionDelete, object) + } + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), nil, http.StatusForbidden) return } @@ -677,7 +689,11 @@ func (handler ConfigMapRestHandlerImpl) CSGlobalFetchForEdit(w http.ResponseWrit //RBAC START token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionUpdate, object); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionUpdate, object) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionUpdate, object) + } + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), nil, http.StatusForbidden) return } @@ -796,18 +812,7 @@ func (handler ConfigMapRestHandlerImpl) AddEnvironmentToJob(w http.ResponseWrite common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) return } - - //AUTH - check from casbin db - isSuperAdmin, err := handler.userAuthService.IsSuperAdmin(int(userId)) - if !isSuperAdmin || err != nil { - if err != nil { - handler.Logger.Errorw("request err, CheckSuperAdmin", "err", isSuperAdmin, "isSuperAdmin", isSuperAdmin) - } - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) - return - } - //AUTH - + token := r.Header.Get("token") var envOverrideRequest bean.CreateJobEnvOverridePayload err = decoder.Decode(&envOverrideRequest) if err != nil { @@ -815,6 +820,15 @@ func (handler ConfigMapRestHandlerImpl) AddEnvironmentToJob(w http.ResponseWrite common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } + + // RBAC ENFORCEMENT + resourceObject := handler.enforcerUtil.GetTeamEnvRBACNameByAppId(envOverrideRequest.AppId, envOverrideRequest.EnvId) + if ok := handler.enforcer.Enforce(token, casbin.ResourceJobsEnv, casbin.ActionGet, resourceObject); !ok { + common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) + return + } + // RBAC ENFORCEMENT ENDS + envOverrideRequest.UserId = userId handler.Logger.Infow("request payload, AddEvironmentToJob", "payload", envOverrideRequest) resp, err := handler.configMapService.ConfigSecretEnvironmentCreate(&envOverrideRequest) diff --git a/api/restHandler/app/BuildPipelineRestHandler.go b/api/restHandler/app/BuildPipelineRestHandler.go index 1d2ea9795c..8b19052fcc 100644 --- a/api/restHandler/app/BuildPipelineRestHandler.go +++ b/api/restHandler/app/BuildPipelineRestHandler.go @@ -389,7 +389,7 @@ func (handler PipelineConfigRestHandlerImpl) PatchCiPipelines(w http.ResponseWri return } resourceName := handler.enforcerUtil.GetAppRBACName(app.AppName) - workflowResourceName := handler.enforcerUtil.GetRbacObjectNameByAppAndWorkflowId(app.AppName, appWorkflow.Name) + workflowResourceName := handler.enforcerUtil.GetRbacObjectNameByAppAndWorkflow(app.AppName, appWorkflow.Name) var ok bool ok = handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, resourceName) if !ok { @@ -454,7 +454,11 @@ func (handler PipelineConfigRestHandlerImpl) GetCiPipeline(w http.ResponseWriter return } resourceName := handler.enforcerUtil.GetAppRBACName(app.AppName) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, resourceName); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, resourceName) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, resourceName) + } + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } @@ -571,8 +575,25 @@ func (handler PipelineConfigRestHandlerImpl) TriggerCiPipeline(w http.ResponseWr common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) return } + appWorkflowMapping, err := handler.appWorkflowService.FindAppWorkflowByCiPipelineId(ciTriggerRequest.PipelineId) + if err != nil { + handler.Logger.Errorw("err in finding appWorkflowMapping, TriggerCiPipeline", "err", err, "ciPipelineId", ciTriggerRequest.PipelineId) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } + workflowName := "" + if len(appWorkflowMapping) > 0 { + workflowName = appWorkflowMapping[0].AppWorkflow.Name + } appObject := handler.enforcerUtil.GetAppRBACNameByAppId(ciPipeline.AppId) - if appRbacOk := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionTrigger, appObject); !appRbacOk { + workflowObject := handler.enforcerUtil.GetWorkflowRBACByCiPipelineId(ciTriggerRequest.PipelineId, workflowName) + triggerObject := handler.enforcerUtil.GetTeamEnvRBACNameByCiPipelineIdAndEnvId(ciTriggerRequest.PipelineId, ciTriggerRequest.EnvironmentId) + appRbacOk := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionTrigger, appObject) + if !appRbacOk { + appRbacOk = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionTrigger, appObject) && handler.enforcer.Enforce(token, casbin.ResourceWorkflow, casbin.ActionTrigger, workflowObject) && handler.enforcer.Enforce(token, casbin.ResourceJobsEnv, casbin.ActionTrigger, triggerObject) + } + + if !appRbacOk { handler.Logger.Debug(fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return @@ -923,16 +944,34 @@ func (handler *PipelineConfigRestHandlerImpl) GetBuildHistory(w http.ResponseWri common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) return } + appWorkflowMapping, err := handler.appWorkflowService.FindAppWorkflowByCiPipelineId(pipelineId) + if err != nil { + handler.Logger.Errorw("service err, GetBuildHistory", "err", err, "pipelineId", pipelineId, "offset", offset) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } //RBAC for build history token := r.Header.Get("token") + isAuthorised := false + workflowName := "" + if len(appWorkflowMapping) > 0 { + workflowName = appWorkflowMapping[0].AppWorkflow.Name + } object := handler.enforcerUtil.GetAppRBACNameByAppId(ciPipeline.AppId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { + workflowResourceObject := handler.enforcerUtil.GetWorkflowRBACByCiPipelineId(pipelineId, workflowName) + if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); ok { + isAuthorised = true + } + if !isAuthorised { + isAuthorised = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) && handler.enforcer.Enforce(token, casbin.ResourceWorkflow, casbin.ActionGet, workflowResourceObject) + } + if !isAuthorised { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } //RBAC //RBAC for edit tag access , user should have build permission in current ci-pipeline - triggerAccess := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionTrigger, object) + triggerAccess := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionTrigger, object) || handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionTrigger, object) //RBAC resp := BuildHistoryResponse{} workflowsResp, err := handler.ciHandler.GetBuildHistory(pipelineId, ciPipeline.AppId, offset, limit) diff --git a/api/restHandler/app/PipelineConfigRestHandler.go b/api/restHandler/app/PipelineConfigRestHandler.go index 62b32c87e1..d82ddc9109 100644 --- a/api/restHandler/app/PipelineConfigRestHandler.go +++ b/api/restHandler/app/PipelineConfigRestHandler.go @@ -24,7 +24,6 @@ import ( "fmt" "github.com/devtron-labs/devtron/api/restHandler/common" "github.com/devtron-labs/devtron/client/gitSensor" - "github.com/devtron-labs/devtron/internal/sql/repository/helper" "github.com/devtron-labs/devtron/pkg/chart" "github.com/devtron-labs/devtron/pkg/generateManifest" resourceGroup2 "github.com/devtron-labs/devtron/pkg/resourceGroup" @@ -214,26 +213,14 @@ func (handler PipelineConfigRestHandlerImpl) DeleteApp(w http.ResponseWriter, r common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } - app, err := handler.pipelineBuilder.GetApp(appId) - if err != nil { - common.WriteJsonResp(w, err, nil, http.StatusBadRequest) - return + resourceObject := handler.enforcerUtil.GetAppRBACNameByAppId(appId) + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionDelete, resourceObject) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionDelete, resourceObject) } - if app.AppType == helper.Job { - isSuperAdmin, err := handler.userAuthService.IsSuperAdmin(int(userId)) - if !isSuperAdmin || err != nil { - if err != nil { - handler.Logger.Errorw("request err, CheckSuperAdmin", "err", isSuperAdmin, "isSuperAdmin", isSuperAdmin) - } - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) - return - } - } else { - resourceObject := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionDelete, resourceObject); !ok { - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) - return - } + if !ok { + common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) + return } err = handler.pipelineBuilder.DeleteApp(appId, userId) if err != nil { diff --git a/internal/sql/repository/appWorkflow/AppWorkflowRepository.go b/internal/sql/repository/appWorkflow/AppWorkflowRepository.go index ab9420aa9d..0a1365973b 100644 --- a/internal/sql/repository/appWorkflow/AppWorkflowRepository.go +++ b/internal/sql/repository/appWorkflow/AppWorkflowRepository.go @@ -61,6 +61,7 @@ type AppWorkflowRepository interface { FindByCDPipelineIds(cdPipelineIds []int) ([]*AppWorkflowMapping, error) FindByWorkflowIds(workflowIds []int) ([]*AppWorkflowMapping, error) FindMappingByAppIds(appIds []int) ([]*AppWorkflowMapping, error) + FindByComponentId(componentId int) ([]*AppWorkflowMapping, error) } type AppWorkflowRepositoryImpl struct { @@ -461,3 +462,13 @@ func (impl AppWorkflowRepositoryImpl) FindMappingByAppIds(appIds []int) ([]*AppW Select() return appWorkflowsMapping, err } + +func (impl AppWorkflowRepositoryImpl) FindByComponentId(componentId int) ([]*AppWorkflowMapping, error) { + var appWorkflowsMapping []*AppWorkflowMapping + err := impl.dbConnection.Model(&appWorkflowsMapping).Column("app_workflow_mapping.*", "AppWorkflow"). + Where("app_workflow_mapping.component_id= ?", componentId). + Where("app_workflow.active = ?", true). + Where("app_workflow_mapping.active = ?", true). + Select() + return appWorkflowsMapping, err +} diff --git a/pkg/appWorkflow/AppWorkflowService.go b/pkg/appWorkflow/AppWorkflowService.go index 0bb3265cc7..a5b3339198 100644 --- a/pkg/appWorkflow/AppWorkflowService.go +++ b/pkg/appWorkflow/AppWorkflowService.go @@ -57,6 +57,7 @@ type AppWorkflowService interface { FindAllWorkflowsForApps(request WorkflowNamesRequest) (*WorkflowNamesResponse, error) FilterWorkflows(triggerViewConfig *TriggerViewWorkflowConfig, envIds []int) (*TriggerViewWorkflowConfig, error) FindCdPipelinesByAppId(appId int) (*bean.CdPipelines, error) + FindAppWorkflowByCiPipelineId(ciPipelineId int) ([]*appWorkflow.AppWorkflowMapping, error) } type AppWorkflowServiceImpl struct { @@ -804,3 +805,13 @@ func (impl AppWorkflowServiceImpl) FindCdPipelinesByAppId(appId int) (*bean.CdPi return cdPipelines, nil } + +func (impl AppWorkflowServiceImpl) FindAppWorkflowByCiPipelineId(ciPipelineId int) ([]*appWorkflow.AppWorkflowMapping, error) { + appWorkflowMapping, err := impl.appWorkflowRepository.FindByComponentId(ciPipelineId) + if err != nil { + impl.Logger.Errorw("error in getting app workflow mappings from component id", "err", err, "componentId", ciPipelineId) + return nil, err + } + return appWorkflowMapping, nil + +} diff --git a/util/rbac/EnforcerUtil.go b/util/rbac/EnforcerUtil.go index 2b2905fe26..b798f9082a 100644 --- a/util/rbac/EnforcerUtil.go +++ b/util/rbac/EnforcerUtil.go @@ -64,7 +64,10 @@ type EnforcerUtil interface { GetAllActiveTeamNames() ([]string, error) GetRbacObjectsByEnvIdsAndAppId(envIds []int, appId int) (map[int]string, map[string]string) GetAppRBACNameByAppAndProjectName(projectName, appName string) string - GetRbacObjectNameByAppAndWorkflowId(appName, workflowName string) string + GetRbacObjectNameByAppAndWorkflow(appName, workflowName string) string + GetRbacObjectNameByAppIdAndWorkflow(appId int, workflowName string) string + GetWorkflowRBACByCiPipelineId(pipelineId int, workflowName string) string + GetTeamEnvRBACNameByCiPipelineIdAndEnvId(ciPipelineId int, envId int) string } type EnforcerUtilImpl struct { @@ -611,10 +614,44 @@ func (impl EnforcerUtilImpl) GetAppRBACNameByAppAndProjectName(projectName, appN return fmt.Sprintf("%s/%s", projectName, appName) } -func (impl EnforcerUtilImpl) GetRbacObjectNameByAppAndWorkflowId(appName, workflowName string) string { +func (impl EnforcerUtilImpl) GetRbacObjectNameByAppAndWorkflow(appName, workflowName string) string { application, err := impl.appRepo.FindAppAndProjectByAppName(appName) if err != nil { return fmt.Sprintf("%s/%s/%s", "", appName, workflowName) } return fmt.Sprintf("%s/%s/%s", application.Team.Name, appName, workflowName) } + +func (impl EnforcerUtilImpl) GetRbacObjectNameByAppIdAndWorkflow(appId int, workflowName string) string { + application, err := impl.appRepo.FindAppAndProjectByAppId(appId) + if err != nil { + return fmt.Sprintf("%s/%s/%s", "", "", workflowName) + } + return fmt.Sprintf("%s/%s/%s", application.Team.Name, application.AppName, workflowName) +} + +func (impl EnforcerUtilImpl) GetWorkflowRBACByCiPipelineId(pipelineId int, workflowName string) string { + ciPipeline, err := impl.ciPipelineRepository.FindById(pipelineId) + if err != nil { + impl.logger.Error(err) + return "" + } + return impl.GetRbacObjectNameByAppIdAndWorkflow(ciPipeline.AppId, workflowName) +} + +func (impl EnforcerUtilImpl) GetTeamEnvRBACNameByCiPipelineIdAndEnvId(ciPipelineId int, envId int) string { + ciPipeline, err := impl.ciPipelineRepository.FindById(ciPipelineId) + if err != nil { + return fmt.Sprintf("%s/%s/%s", "", "", "") + } + application, err := impl.appRepo.FindById(ciPipeline.AppId) + if err != nil { + return fmt.Sprintf("%s/%s/%s", "", "", "") + } + appName := application.AppName + env, err := impl.environmentRepository.FindById(envId) + if err != nil { + return fmt.Sprintf("%s/%s/%s", application.Team.Name, "", appName) + } + return fmt.Sprintf("%s/%s/%s", application.Team.Name, env.EnvironmentIdentifier, appName) +} From 01d77b8403c273ce15a0f99e7aa579f449ebd05b Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 10 Nov 2023 16:28:47 +0530 Subject: [PATCH 14/76] script number chnage --- scripts/casbin/{8_jobs_rbac.down.sql => 7_jobs_rbac.down.sql} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename scripts/casbin/{8_jobs_rbac.down.sql => 7_jobs_rbac.down.sql} (100%) diff --git a/scripts/casbin/8_jobs_rbac.down.sql b/scripts/casbin/7_jobs_rbac.down.sql similarity index 100% rename from scripts/casbin/8_jobs_rbac.down.sql rename to scripts/casbin/7_jobs_rbac.down.sql From 973cdba995dc87bef70bf455235578dafecf4e18 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 10 Nov 2023 19:23:54 +0530 Subject: [PATCH 15/76] appnames fetch --- internal/sql/repository/app/AppRepository.go | 16 ++++++++++++++++ .../AppListingRepositoryQueryBuilder.go | 11 +++++++++++ pkg/appWorkflow/AppWorkflowService.go | 19 ++++++++++++++----- wire_gen.go | 2 +- 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/internal/sql/repository/app/AppRepository.go b/internal/sql/repository/app/AppRepository.go index 650980ecb1..c0f078d926 100644 --- a/internal/sql/repository/app/AppRepository.go +++ b/internal/sql/repository/app/AppRepository.go @@ -76,6 +76,7 @@ type AppRepository interface { FetchAppIdsWithFilter(jobListingFilter helper.AppListingFilter) ([]int, error) FindAllActiveAppsWithTeamByAppNameMatch(appNameMatch string) ([]*App, error) FindAppAndProjectByIdsIn(ids []int) ([]*App, error) + FetchAppIdsByDisplaynames(names []string) ([]int, error) } const DevtronApp = "DevtronApp" @@ -442,3 +443,18 @@ func (repo AppRepositoryImpl) FindAppAndProjectByIdsIn(ids []int) ([]*App, error err := repo.dbConnection.Model(&apps).Column("app.*", "Team").Where("app.active = ?", true).Where("app.id in (?)", pg.In(ids)).Select() return apps, err } +func (repo AppRepositoryImpl) FetchAppIdsByDisplaynames(names []string) ([]int, error) { + type AppId struct { + Id int `json:"id"` + } + var jobIds []AppId + whereCondition := " where active = true and app_type = 2 " + whereCondition += " and display_name in (" + helper.GetCommaSepratedStringWithComma(names) + ");" + query := "select id from app " + whereCondition + _, err := repo.dbConnection.Query(&jobIds, query) + appCounts := make([]int, 0) + for _, id := range jobIds { + appCounts = append(appCounts, id.Id) + } + return appCounts, err +} diff --git a/internal/sql/repository/helper/AppListingRepositoryQueryBuilder.go b/internal/sql/repository/helper/AppListingRepositoryQueryBuilder.go index ab566c13de..52374b9dc4 100644 --- a/internal/sql/repository/helper/AppListingRepositoryQueryBuilder.go +++ b/internal/sql/repository/helper/AppListingRepositoryQueryBuilder.go @@ -327,3 +327,14 @@ func GetCommaSepratedString[T int | string](appIds []T) string { } return appIdsString } + +func GetCommaSepratedStringWithComma[T int | string](appIds []T) string { + appIdsString := "" + for i, appId := range appIds { + appIdsString += fmt.Sprintf("'%v'", appId) + if i != len(appIds)-1 { + appIdsString += "," + } + } + return appIdsString +} diff --git a/pkg/appWorkflow/AppWorkflowService.go b/pkg/appWorkflow/AppWorkflowService.go index 0bb3265cc7..c339e04cf0 100644 --- a/pkg/appWorkflow/AppWorkflowService.go +++ b/pkg/appWorkflow/AppWorkflowService.go @@ -20,6 +20,7 @@ package appWorkflow import ( "fmt" mapset "github.com/deckarep/golang-set" + appRepository "github.com/devtron-labs/devtron/internal/sql/repository/app" "github.com/devtron-labs/devtron/internal/sql/repository/appWorkflow" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig" "github.com/devtron-labs/devtron/internal/util" @@ -66,6 +67,7 @@ type AppWorkflowServiceImpl struct { ciPipelineRepository pipelineConfig.CiPipelineRepository pipelineRepository pipelineConfig.PipelineRepository resourceGroupService resourceGroup2.ResourceGroupService + appRepository appRepository.AppRepository enforcerUtil rbac.EnforcerUtil } @@ -128,7 +130,7 @@ type WorkflowNamesResponse struct { } type WorkflowNamesRequest struct { - AppIds []int `json:"appIds"` + AppNames []string `json:"appNames"` } type WorkflowCloneRequest struct { @@ -146,7 +148,8 @@ type PipelineIdentifier struct { func NewAppWorkflowServiceImpl(logger *zap.SugaredLogger, appWorkflowRepository appWorkflow.AppWorkflowRepository, ciCdPipelineOrchestrator pipeline.CiCdPipelineOrchestrator, ciPipelineRepository pipelineConfig.CiPipelineRepository, - pipelineRepository pipelineConfig.PipelineRepository, enforcerUtil rbac.EnforcerUtil, resourceGroupService resourceGroup2.ResourceGroupService) *AppWorkflowServiceImpl { + pipelineRepository pipelineConfig.PipelineRepository, enforcerUtil rbac.EnforcerUtil, resourceGroupService resourceGroup2.ResourceGroupService, + appRepository appRepository.AppRepository) *AppWorkflowServiceImpl { return &AppWorkflowServiceImpl{ Logger: logger, appWorkflowRepository: appWorkflowRepository, @@ -155,6 +158,7 @@ func NewAppWorkflowServiceImpl(logger *zap.SugaredLogger, appWorkflowRepository pipelineRepository: pipelineRepository, enforcerUtil: enforcerUtil, resourceGroupService: resourceGroupService, + appRepository: appRepository, } } @@ -658,12 +662,17 @@ func (impl AppWorkflowServiceImpl) FindAppWorkflowsByEnvironmentId(request resou } func (impl AppWorkflowServiceImpl) FindAllWorkflowsForApps(request WorkflowNamesRequest) (*WorkflowNamesResponse, error) { - if len(request.AppIds) == 0 { + if len(request.AppNames) == 0 { return &WorkflowNamesResponse{}, nil } - appWorkflows, err := impl.appWorkflowRepository.FindByAppIds(request.AppIds) + appIds, err := impl.appRepository.FetchAppIdsByDisplaynames(request.AppNames) + if err != nil { + impl.Logger.Errorw("error in getting apps by appNames", "err", err, "appNames", request.AppNames) + return nil, err + } + appWorkflows, err := impl.appWorkflowRepository.FindByAppIds(appIds) if err != nil && err != pg.ErrNoRows { - impl.Logger.Errorw("error occurred while fetching app workflows", "AppIds", request.AppIds, "err", err) + impl.Logger.Errorw("error occurred while fetching app workflows", "AppIds", appIds, "err", err) return nil, err } appIdWorkflowMap := make(map[int][]string) diff --git a/wire_gen.go b/wire_gen.go index 6c21439635..d3334c920a 100644 --- a/wire_gen.go +++ b/wire_gen.go @@ -519,7 +519,7 @@ func InitializeApp() (*App, error) { appListingServiceImpl := app2.NewAppListingServiceImpl(sugaredLogger, appListingRepositoryImpl, applicationServiceClientImpl, appRepositoryImpl, appListingViewBuilderImpl, pipelineRepositoryImpl, linkoutsRepositoryImpl, appLevelMetricsRepositoryImpl, envLevelAppMetricsRepositoryImpl, cdWorkflowRepositoryImpl, pipelineOverrideRepositoryImpl, environmentRepositoryImpl, argoUserServiceImpl, envConfigOverrideRepositoryImpl, chartRepositoryImpl, ciPipelineRepositoryImpl, dockerRegistryIpsConfigServiceImpl) deploymentEventHandlerImpl := app2.NewDeploymentEventHandlerImpl(sugaredLogger, appListingServiceImpl, eventRESTClientImpl, eventSimpleFactoryImpl) cdHandlerImpl := pipeline.NewCdHandlerImpl(sugaredLogger, userServiceImpl, cdWorkflowRepositoryImpl, ciLogServiceImpl, ciArtifactRepositoryImpl, ciPipelineMaterialRepositoryImpl, pipelineRepositoryImpl, environmentRepositoryImpl, ciWorkflowRepositoryImpl, helmAppServiceImpl, pipelineOverrideRepositoryImpl, workflowDagExecutorImpl, appListingServiceImpl, appListingRepositoryImpl, pipelineStatusTimelineRepositoryImpl, applicationServiceClientImpl, argoUserServiceImpl, deploymentEventHandlerImpl, eventRESTClientImpl, pipelineStatusTimelineResourcesServiceImpl, pipelineStatusSyncDetailServiceImpl, pipelineStatusTimelineServiceImpl, appServiceImpl, appStatusServiceImpl, enforcerUtilImpl, installedAppRepositoryImpl, installedAppVersionHistoryRepositoryImpl, appRepositoryImpl, resourceGroupServiceImpl, imageTaggingServiceImpl, k8sUtil, workflowServiceImpl, clusterServiceImplExtended, blobStorageConfigServiceImpl) - appWorkflowServiceImpl := appWorkflow2.NewAppWorkflowServiceImpl(sugaredLogger, appWorkflowRepositoryImpl, ciCdPipelineOrchestratorImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, enforcerUtilImpl, resourceGroupServiceImpl) + appWorkflowServiceImpl := appWorkflow2.NewAppWorkflowServiceImpl(sugaredLogger, appWorkflowRepositoryImpl, ciCdPipelineOrchestratorImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, enforcerUtilImpl, resourceGroupServiceImpl, appRepositoryImpl) appCloneServiceImpl := appClone.NewAppCloneServiceImpl(sugaredLogger, pipelineBuilderImpl, materialRepositoryImpl, chartServiceImpl, configMapServiceImpl, appWorkflowServiceImpl, appListingServiceImpl, propertiesConfigServiceImpl, ciTemplateOverrideRepositoryImpl, pipelineStageServiceImpl, ciTemplateServiceImpl, appRepositoryImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, appWorkflowRepositoryImpl) deploymentTemplateRepositoryImpl := repository.NewDeploymentTemplateRepositoryImpl(db, sugaredLogger) deploymentTemplateServiceImpl := generateManifest.NewDeploymentTemplateServiceImpl(sugaredLogger, chartServiceImpl, appListingServiceImpl, appListingRepositoryImpl, deploymentTemplateRepositoryImpl, helmAppServiceImpl, chartRepositoryImpl, chartTemplateServiceImpl, helmAppClientImpl, k8sUtil, propertiesConfigServiceImpl, deploymentTemplateHistoryServiceImpl, environmentRepositoryImpl, appRepositoryImpl, scopedVariableManagerImpl) From 8cd19b9b6867fdd72b69b986a750612e7d255612 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Sat, 11 Nov 2023 05:09:15 +0530 Subject: [PATCH 16/76] workflow response --- internal/sql/repository/app/AppRepository.go | 25 +++++++++++--------- pkg/appWorkflow/AppWorkflowService.go | 12 +++++----- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/internal/sql/repository/app/AppRepository.go b/internal/sql/repository/app/AppRepository.go index c0f078d926..29a5c61d88 100644 --- a/internal/sql/repository/app/AppRepository.go +++ b/internal/sql/repository/app/AppRepository.go @@ -76,7 +76,7 @@ type AppRepository interface { FetchAppIdsWithFilter(jobListingFilter helper.AppListingFilter) ([]int, error) FindAllActiveAppsWithTeamByAppNameMatch(appNameMatch string) ([]*App, error) FindAppAndProjectByIdsIn(ids []int) ([]*App, error) - FetchAppIdsByDisplaynames(names []string) ([]int, error) + FetchAppIdsByDisplaynames(names []string) (map[int]string, []int, error) } const DevtronApp = "DevtronApp" @@ -443,18 +443,21 @@ func (repo AppRepositoryImpl) FindAppAndProjectByIdsIn(ids []int) ([]*App, error err := repo.dbConnection.Model(&apps).Column("app.*", "Team").Where("app.active = ?", true).Where("app.id in (?)", pg.In(ids)).Select() return apps, err } -func (repo AppRepositoryImpl) FetchAppIdsByDisplaynames(names []string) ([]int, error) { - type AppId struct { - Id int `json:"id"` +func (repo AppRepositoryImpl) FetchAppIdsByDisplaynames(names []string) (map[int]string, []int, error) { + type App struct { + Id int `json:"id"` + DisplayName string `json:"display_name"` } - var jobIds []AppId + var jobIdName []App whereCondition := " where active = true and app_type = 2 " whereCondition += " and display_name in (" + helper.GetCommaSepratedStringWithComma(names) + ");" - query := "select id from app " + whereCondition - _, err := repo.dbConnection.Query(&jobIds, query) - appCounts := make([]int, 0) - for _, id := range jobIds { - appCounts = append(appCounts, id.Id) + query := "select id, display_name from app " + whereCondition + _, err := repo.dbConnection.Query(&jobIdName, query) + appResp := make(map[int]string) + jobIds := make([]int, 0) + for _, id := range jobIdName { + appResp[id.Id] = id.DisplayName + jobIds = append(jobIds, id.Id) } - return appCounts, err + return appResp, jobIds, err } diff --git a/pkg/appWorkflow/AppWorkflowService.go b/pkg/appWorkflow/AppWorkflowService.go index c339e04cf0..7546bfe17d 100644 --- a/pkg/appWorkflow/AppWorkflowService.go +++ b/pkg/appWorkflow/AppWorkflowService.go @@ -126,7 +126,7 @@ type WorkflowComponentNamesDto struct { } type WorkflowNamesResponse struct { - AppIdWorkflowNamesMapping map[int][]string `json:"appIdWorkflowNamesMapping"` + AppIdWorkflowNamesMapping map[string][]string `json:"appIdWorkflowNamesMapping"` } type WorkflowNamesRequest struct { @@ -665,7 +665,7 @@ func (impl AppWorkflowServiceImpl) FindAllWorkflowsForApps(request WorkflowNames if len(request.AppNames) == 0 { return &WorkflowNamesResponse{}, nil } - appIds, err := impl.appRepository.FetchAppIdsByDisplaynames(request.AppNames) + appIdNameMapping, appIds, err := impl.appRepository.FetchAppIdsByDisplaynames(request.AppNames) if err != nil { impl.Logger.Errorw("error in getting apps by appNames", "err", err, "appNames", request.AppNames) return nil, err @@ -675,13 +675,13 @@ func (impl AppWorkflowServiceImpl) FindAllWorkflowsForApps(request WorkflowNames impl.Logger.Errorw("error occurred while fetching app workflows", "AppIds", appIds, "err", err) return nil, err } - appIdWorkflowMap := make(map[int][]string) + appIdWorkflowMap := make(map[string][]string) for _, workflow := range appWorkflows { - if workflows, ok := appIdWorkflowMap[workflow.AppId]; ok { + if workflows, ok := appIdWorkflowMap[appIdNameMapping[workflow.AppId]]; ok { workflows = append(workflows, workflow.Name) - appIdWorkflowMap[workflow.AppId] = workflows + appIdWorkflowMap[appIdNameMapping[workflow.AppId]] = workflows } else { - appIdWorkflowMap[workflow.AppId] = []string{workflow.Name} + appIdWorkflowMap[appIdNameMapping[workflow.AppId]] = []string{workflow.Name} } } From 6fd44e922347ac889770eea9f59d8f5ec094c224 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Sun, 12 Nov 2023 17:30:06 +0530 Subject: [PATCH 17/76] app-workflow check --- api/restHandler/app/BuildPipelineRestHandler.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/api/restHandler/app/BuildPipelineRestHandler.go b/api/restHandler/app/BuildPipelineRestHandler.go index 8b19052fcc..6a24f59408 100644 --- a/api/restHandler/app/BuildPipelineRestHandler.go +++ b/api/restHandler/app/BuildPipelineRestHandler.go @@ -382,14 +382,18 @@ func (handler PipelineConfigRestHandlerImpl) PatchCiPipelines(w http.ResponseWri common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } - appWorkflow, err := handler.appWorkflowService.FindAppWorkflowById(patchRequest.AppWorkflowId, app.Id) - if err != nil { - handler.Logger.Errorw("error in getting app workflow", "err", err, "workflowId", patchRequest.AppWorkflowId, "appId", app.Id) - common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) - return + appWorkflowName := "" + if patchRequest.AppWorkflowId != 0 { + appWorkflow, err := handler.appWorkflowService.FindAppWorkflowById(patchRequest.AppWorkflowId, app.Id) + if err != nil { + handler.Logger.Errorw("error in getting app workflow", "err", err, "workflowId", patchRequest.AppWorkflowId, "appId", app.Id) + common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) + return + } + appWorkflowName = appWorkflow.Name } resourceName := handler.enforcerUtil.GetAppRBACName(app.AppName) - workflowResourceName := handler.enforcerUtil.GetRbacObjectNameByAppAndWorkflow(app.AppName, appWorkflow.Name) + workflowResourceName := handler.enforcerUtil.GetRbacObjectNameByAppAndWorkflow(app.AppName, appWorkflowName) var ok bool ok = handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, resourceName) if !ok { From 426365a257591a1770192889af380e31c139c9c9 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Sun, 12 Nov 2023 18:43:56 +0530 Subject: [PATCH 18/76] job env change --- pkg/user/casbin/rbacpolicy.go | 2 +- scripts/casbin/7_jobs_rbac.down.sql | 2 +- scripts/casbin/7_jobs_rbac.up.sql | 2 +- scripts/sql/188_jobs_rbac.up.sql | 10 +++++----- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/user/casbin/rbacpolicy.go b/pkg/user/casbin/rbacpolicy.go index 10173054d1..4605dab4b5 100644 --- a/pkg/user/casbin/rbacpolicy.go +++ b/pkg/user/casbin/rbacpolicy.go @@ -38,7 +38,7 @@ const ( ResourceChartGroup = "chart-group" ResourceJobs = "jobs" - ResourceJobsEnv = "jobEnv" + ResourceJobsEnv = "jobenv" ResourceWorkflow = "workflow" ResourceTeam = "team" diff --git a/scripts/casbin/7_jobs_rbac.down.sql b/scripts/casbin/7_jobs_rbac.down.sql index c79dcb39af..5b10351334 100644 --- a/scripts/casbin/7_jobs_rbac.down.sql +++ b/scripts/casbin/7_jobs_rbac.down.sql @@ -1,3 +1,3 @@ DELETE FROM casbin_rule where v0='role:super-admin___' and v1='jobs'; -DELETE FROM casbin_rule where v0='role:super-admin___' and v1='jobEnv'; +DELETE FROM casbin_rule where v0='role:super-admin___' and v1='jobenv'; DELETE FROM casbin_rule where v0='role:super-admin___' and v1='workflow'; \ No newline at end of file diff --git a/scripts/casbin/7_jobs_rbac.up.sql b/scripts/casbin/7_jobs_rbac.up.sql index 8dd138c046..f9aedc835e 100644 --- a/scripts/casbin/7_jobs_rbac.up.sql +++ b/scripts/casbin/7_jobs_rbac.up.sql @@ -1,5 +1,5 @@ INSERT INTO "public"."casbin_rule" ("p_type", "v0", "v1", "v2", "v3", "v4", "v5") VALUES ('p','role:super-admin___','jobs','*','*','allow',''), -('p','role:super-admin___','jobEnv','*','*','allow',''), +('p','role:super-admin___','jobenv','*','*','allow',''), ('p','role:super-admin___','workflow','*','*','allow',''); diff --git a/scripts/sql/188_jobs_rbac.up.sql b/scripts/sql/188_jobs_rbac.up.sql index d26286c4eb..1cf7025677 100644 --- a/scripts/sql/188_jobs_rbac.up.sql +++ b/scripts/sql/188_jobs_rbac.up.sql @@ -34,7 +34,7 @@ VALUES ('jobs', '', 'admin', '{ }, { "res": { - "value": "jobEnv", + "value": "jobenv", "indexKeyMap": {} }, "act": { @@ -153,7 +153,7 @@ VALUES ('jobs', '', 'admin', '{ }, { "res": { - "value": "jobEnv", + "value": "jobenv", "indexKeyMap": {} }, "act": { @@ -171,7 +171,7 @@ VALUES ('jobs', '', 'admin', '{ }, { "res": { - "value": "jobEnv", + "value": "jobenv", "indexKeyMap": {} }, "act": { @@ -291,7 +291,7 @@ VALUES ('jobs', '', 'admin', '{ }, { "res": { - "value": "jobEnv", + "value": "jobenv", "indexKeyMap": {} }, "act": { @@ -526,7 +526,7 @@ VALUES ('jobs', '', 'admin', 'Admin', 'Can view, run and edit jobs in selected s INSERT INTO rbac_policy_resource_detail ("resource", "policy_resource_value", "allowed_actions", "resource_object", "eligible_entity_access_types", "deleted", "created_on", "created_by", "updated_on", "updated_by") -VALUES ('jobEnv', '{ "value": "jobEnv", "indexKeyMap": {}}', ARRAY['get','update','create','delete','trigger'],'{"value": "%/%/%","indexKeyMap": {"0": "TeamObj","2": "EnvObj","4": "AppObj"}}', ARRAY['jobs'],'f','now()', '1', 'now()', '1'); +VALUES ('jobenv', '{ "value": "jobenv", "indexKeyMap": {}}', ARRAY['get','update','create','delete','trigger'],'{"value": "%/%/%","indexKeyMap": {"0": "TeamObj","2": "EnvObj","4": "AppObj"}}', ARRAY['jobs'],'f','now()', '1', 'now()', '1'); INSERT INTO rbac_policy_resource_detail ("resource", "policy_resource_value", "allowed_actions", "resource_object", "eligible_entity_access_types", "deleted", "created_on", From ff7a29ceede64e4ecdd469a25f64de5016711ba8 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Sun, 12 Nov 2023 19:06:48 +0530 Subject: [PATCH 19/76] job actual name --- api/bean/AppView.go | 2 ++ .../sql/repository/helper/AppListingRepositoryQueryBuilder.go | 2 +- pkg/app/AppListingService.go | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/api/bean/AppView.go b/api/bean/AppView.go index 3a12db54a7..883dc640f4 100644 --- a/api/bean/AppView.go +++ b/api/bean/AppView.go @@ -69,6 +69,7 @@ type GenericNoteResponseBean struct { type JobContainer struct { JobId int `json:"jobId"` JobName string `json:"jobName""` + JobActualName string `json:"appName""` Description GenericNoteResponseBean `json:"description"` JobCiPipelines []JobCIPipeline `json:"ciPipelines"'` } @@ -87,6 +88,7 @@ type JobCIPipeline struct { type JobListingContainer struct { JobId int `sql:"job_id" json:"jobId"` JobName string `sql:"job_name" json:"jobName"` + JobActualName string `sql:"app_name" json:"appName"` Description string `sql:"description" json:"description"` CiPipelineID int `sql:"ci_pipeline_id" json:"ciPipelineID"` CiPipelineName string `sql:"ci_pipeline_name" json:"ciPipelineName"` diff --git a/internal/sql/repository/helper/AppListingRepositoryQueryBuilder.go b/internal/sql/repository/helper/AppListingRepositoryQueryBuilder.go index 52374b9dc4..dd686ae16d 100644 --- a/internal/sql/repository/helper/AppListingRepositoryQueryBuilder.go +++ b/internal/sql/repository/helper/AppListingRepositoryQueryBuilder.go @@ -72,7 +72,7 @@ const ( func (impl AppListingRepositoryQueryBuilder) BuildJobListingQuery(appIDs []int, statuses []string, environmentIds []int, sortOrder string) string { query := "select ci_pipeline.name as ci_pipeline_name,ci_pipeline.id as ci_pipeline_id,app.id as job_id,app.display_name " + - "as job_name,app.description,cwr.started_on,cwr.status,cem.environment_id,cwr.environment_id as last_triggered_environment_id from app left join ci_pipeline on" + + "as job_name, app.app_name,app.description,cwr.started_on,cwr.status,cem.environment_id,cwr.environment_id as last_triggered_environment_id from app left join ci_pipeline on" + " app.id = ci_pipeline.app_id and ci_pipeline.active=true left join (select cw.ci_pipeline_id, cw.status, cw.started_on, cw.environment_id " + " from ci_workflow cw inner join (select ci_pipeline_id, MAX(started_on) max_started_on from ci_workflow group by ci_pipeline_id ) " + "cws on cw.ci_pipeline_id = cws.ci_pipeline_id " + diff --git a/pkg/app/AppListingService.go b/pkg/app/AppListingService.go index 794ab72c96..6541c8fd05 100644 --- a/pkg/app/AppListingService.go +++ b/pkg/app/AppListingService.go @@ -516,6 +516,7 @@ func BuildJobListingResponse(jobContainers []*bean.JobListingContainer, JobsLast val = bean.JobContainer{} val.JobId = jobContainer.JobId val.JobName = jobContainer.JobName + val.JobActualName = jobContainer.JobActualName } if len(val.JobCiPipelines) == 0 { From 9a2c8ce942809436fe1e54ef33052ba79055bcc6 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Sun, 12 Nov 2023 19:14:26 +0530 Subject: [PATCH 20/76] job actual name --- api/bean/AppView.go | 2 ++ .../sql/repository/helper/AppListingRepositoryQueryBuilder.go | 2 +- pkg/app/AppListingService.go | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/api/bean/AppView.go b/api/bean/AppView.go index 3a12db54a7..883dc640f4 100644 --- a/api/bean/AppView.go +++ b/api/bean/AppView.go @@ -69,6 +69,7 @@ type GenericNoteResponseBean struct { type JobContainer struct { JobId int `json:"jobId"` JobName string `json:"jobName""` + JobActualName string `json:"appName""` Description GenericNoteResponseBean `json:"description"` JobCiPipelines []JobCIPipeline `json:"ciPipelines"'` } @@ -87,6 +88,7 @@ type JobCIPipeline struct { type JobListingContainer struct { JobId int `sql:"job_id" json:"jobId"` JobName string `sql:"job_name" json:"jobName"` + JobActualName string `sql:"app_name" json:"appName"` Description string `sql:"description" json:"description"` CiPipelineID int `sql:"ci_pipeline_id" json:"ciPipelineID"` CiPipelineName string `sql:"ci_pipeline_name" json:"ciPipelineName"` diff --git a/internal/sql/repository/helper/AppListingRepositoryQueryBuilder.go b/internal/sql/repository/helper/AppListingRepositoryQueryBuilder.go index 52374b9dc4..dd686ae16d 100644 --- a/internal/sql/repository/helper/AppListingRepositoryQueryBuilder.go +++ b/internal/sql/repository/helper/AppListingRepositoryQueryBuilder.go @@ -72,7 +72,7 @@ const ( func (impl AppListingRepositoryQueryBuilder) BuildJobListingQuery(appIDs []int, statuses []string, environmentIds []int, sortOrder string) string { query := "select ci_pipeline.name as ci_pipeline_name,ci_pipeline.id as ci_pipeline_id,app.id as job_id,app.display_name " + - "as job_name,app.description,cwr.started_on,cwr.status,cem.environment_id,cwr.environment_id as last_triggered_environment_id from app left join ci_pipeline on" + + "as job_name, app.app_name,app.description,cwr.started_on,cwr.status,cem.environment_id,cwr.environment_id as last_triggered_environment_id from app left join ci_pipeline on" + " app.id = ci_pipeline.app_id and ci_pipeline.active=true left join (select cw.ci_pipeline_id, cw.status, cw.started_on, cw.environment_id " + " from ci_workflow cw inner join (select ci_pipeline_id, MAX(started_on) max_started_on from ci_workflow group by ci_pipeline_id ) " + "cws on cw.ci_pipeline_id = cws.ci_pipeline_id " + diff --git a/pkg/app/AppListingService.go b/pkg/app/AppListingService.go index 794ab72c96..6541c8fd05 100644 --- a/pkg/app/AppListingService.go +++ b/pkg/app/AppListingService.go @@ -516,6 +516,7 @@ func BuildJobListingResponse(jobContainers []*bean.JobListingContainer, JobsLast val = bean.JobContainer{} val.JobId = jobContainer.JobId val.JobName = jobContainer.JobName + val.JobActualName = jobContainer.JobActualName } if len(val.JobCiPipelines) == 0 { From 4d733d8705f4f97b49024c1b5b70e7d7770db921 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Wed, 15 Nov 2023 08:45:59 +0530 Subject: [PATCH 21/76] get api changes --- pkg/user/RoleGroupService.go | 2 +- pkg/user/UserService.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/user/RoleGroupService.go b/pkg/user/RoleGroupService.go index f732e941d6..3237e06a85 100644 --- a/pkg/user/RoleGroupService.go +++ b/pkg/user/RoleGroupService.go @@ -505,7 +505,7 @@ func (impl RoleGroupServiceImpl) getRoleGroupMetadata(roleGroup *repository2.Rol if len(role.Team) > 0 && role.Entity != bean2.EntityJobs { key = fmt.Sprintf("%s_%s_%s", role.Team, role.Action, role.AccessType) } else if role.Entity == bean2.EntityJobs { - key = fmt.Sprintf("%s_%s_%s_%s", role.Team, role.Action, role.AccessType, role.Workflow) + key = fmt.Sprintf("%s_%s_%s_%s", role.Team, role.Action, role.AccessType, role.Entity) } else if len(role.Entity) > 0 { if role.Entity == bean.CLUSTER_ENTITIY { key = fmt.Sprintf("%s_%s_%s_%s_%s_%s", role.Entity, role.Action, role.Cluster, diff --git a/pkg/user/UserService.go b/pkg/user/UserService.go index 80a74e614b..bfba817f46 100644 --- a/pkg/user/UserService.go +++ b/pkg/user/UserService.go @@ -864,7 +864,7 @@ func (impl *UserServiceImpl) getUserMetadata(model *repository2.UserModel) (bool if len(role.Team) > 0 && role.Entity != bean2.EntityJobs { key = fmt.Sprintf("%s_%s_%s", role.Team, role.Action, role.AccessType) } else if role.Entity == bean2.EntityJobs { - key = fmt.Sprintf("%s_%s_%s_%s", role.Team, role.Action, role.AccessType, role.Workflow) + key = fmt.Sprintf("%s_%s_%s_%s", role.Team, role.Action, role.AccessType, role.Entity) } else if len(role.Entity) > 0 { if role.Entity == bean.CLUSTER_ENTITIY { key = fmt.Sprintf("%s_%s_%s_%s_%s_%s", role.Entity, role.Action, role.Cluster, @@ -1405,7 +1405,7 @@ func (impl *UserServiceImpl) GetRoleFiltersByGroupNames(groupNames []string) ([] if len(role.Team) > 0 && role.Entity != bean2.EntityJobs { key = fmt.Sprintf("%s_%s_%s", role.Team, role.Action, role.AccessType) } else if role.Entity == bean2.EntityJobs { - key = fmt.Sprintf("%s_%s_%s_%s", role.Team, role.Action, role.AccessType, role.Workflow) + key = fmt.Sprintf("%s_%s_%s_%s", role.Team, role.Action, role.AccessType, role.Entity) } else if len(role.Entity) > 0 { if role.Entity == bean.CLUSTER_ENTITIY { key = fmt.Sprintf("%s_%s_%s_%s_%s_%s", role.Entity, role.Action, role.Cluster, From a71a5b09a17373e5ffe60f4f0b47db3014cd153b Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Wed, 15 Nov 2023 19:28:02 +0530 Subject: [PATCH 22/76] number change --- scripts/sql/{188_jobs_rbac.down.sql => 189_jobs_rbac.down.sql} | 0 scripts/sql/{188_jobs_rbac.up.sql => 189_jobs_rbac.up.sql} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename scripts/sql/{188_jobs_rbac.down.sql => 189_jobs_rbac.down.sql} (100%) rename scripts/sql/{188_jobs_rbac.up.sql => 189_jobs_rbac.up.sql} (100%) diff --git a/scripts/sql/188_jobs_rbac.down.sql b/scripts/sql/189_jobs_rbac.down.sql similarity index 100% rename from scripts/sql/188_jobs_rbac.down.sql rename to scripts/sql/189_jobs_rbac.down.sql diff --git a/scripts/sql/188_jobs_rbac.up.sql b/scripts/sql/189_jobs_rbac.up.sql similarity index 100% rename from scripts/sql/188_jobs_rbac.up.sql rename to scripts/sql/189_jobs_rbac.up.sql From 592cfcfdddb7b73c66be54302f8fda4102f56d22 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Thu, 16 Nov 2023 10:38:36 +0530 Subject: [PATCH 23/76] env rbac --- api/restHandler/app/BuildPipelineRestHandler.go | 6 +++++- util/rbac/EnforcerUtil.go | 9 ++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/api/restHandler/app/BuildPipelineRestHandler.go b/api/restHandler/app/BuildPipelineRestHandler.go index 6a24f59408..529cc47fac 100644 --- a/api/restHandler/app/BuildPipelineRestHandler.go +++ b/api/restHandler/app/BuildPipelineRestHandler.go @@ -589,9 +589,13 @@ func (handler PipelineConfigRestHandlerImpl) TriggerCiPipeline(w http.ResponseWr if len(appWorkflowMapping) > 0 { workflowName = appWorkflowMapping[0].AppWorkflow.Name } + envName := "" + if ciTriggerRequest.EnvironmentId == 0 { + envName = pipeline.DefaultCiWorkflowNamespace + } appObject := handler.enforcerUtil.GetAppRBACNameByAppId(ciPipeline.AppId) workflowObject := handler.enforcerUtil.GetWorkflowRBACByCiPipelineId(ciTriggerRequest.PipelineId, workflowName) - triggerObject := handler.enforcerUtil.GetTeamEnvRBACNameByCiPipelineIdAndEnvId(ciTriggerRequest.PipelineId, ciTriggerRequest.EnvironmentId) + triggerObject := handler.enforcerUtil.GetTeamEnvRBACNameByCiPipelineIdAndEnvIdOrName(ciTriggerRequest.PipelineId, ciTriggerRequest.EnvironmentId, envName) appRbacOk := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionTrigger, appObject) if !appRbacOk { appRbacOk = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionTrigger, appObject) && handler.enforcer.Enforce(token, casbin.ResourceWorkflow, casbin.ActionTrigger, workflowObject) && handler.enforcer.Enforce(token, casbin.ResourceJobsEnv, casbin.ActionTrigger, triggerObject) diff --git a/util/rbac/EnforcerUtil.go b/util/rbac/EnforcerUtil.go index b798f9082a..414093462a 100644 --- a/util/rbac/EnforcerUtil.go +++ b/util/rbac/EnforcerUtil.go @@ -67,7 +67,7 @@ type EnforcerUtil interface { GetRbacObjectNameByAppAndWorkflow(appName, workflowName string) string GetRbacObjectNameByAppIdAndWorkflow(appId int, workflowName string) string GetWorkflowRBACByCiPipelineId(pipelineId int, workflowName string) string - GetTeamEnvRBACNameByCiPipelineIdAndEnvId(ciPipelineId int, envId int) string + GetTeamEnvRBACNameByCiPipelineIdAndEnvIdOrName(ciPipelineId int, envId int, envName string) string } type EnforcerUtilImpl struct { @@ -639,16 +639,19 @@ func (impl EnforcerUtilImpl) GetWorkflowRBACByCiPipelineId(pipelineId int, workf return impl.GetRbacObjectNameByAppIdAndWorkflow(ciPipeline.AppId, workflowName) } -func (impl EnforcerUtilImpl) GetTeamEnvRBACNameByCiPipelineIdAndEnvId(ciPipelineId int, envId int) string { +func (impl EnforcerUtilImpl) GetTeamEnvRBACNameByCiPipelineIdAndEnvIdOrName(ciPipelineId int, envId int, envName string) string { ciPipeline, err := impl.ciPipelineRepository.FindById(ciPipelineId) if err != nil { return fmt.Sprintf("%s/%s/%s", "", "", "") } - application, err := impl.appRepo.FindById(ciPipeline.AppId) + application, err := impl.appRepo.FindAppAndProjectByAppId(ciPipeline.AppId) if err != nil { return fmt.Sprintf("%s/%s/%s", "", "", "") } appName := application.AppName + if len(envName) != 0 { + return fmt.Sprintf("%s/%s/%s", application.Team.Name, envName, appName) + } env, err := impl.environmentRepository.FindById(envId) if err != nil { return fmt.Sprintf("%s/%s/%s", application.Team.Name, "", appName) From a1c7c7f710c1281336699a11a21a69496ab5f1fa Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Thu, 16 Nov 2023 12:06:29 +0530 Subject: [PATCH 24/76] fetch jobs --- api/restHandler/AppListingRestHandler.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/api/restHandler/AppListingRestHandler.go b/api/restHandler/AppListingRestHandler.go index 57b4b4189d..31bf31482c 100644 --- a/api/restHandler/AppListingRestHandler.go +++ b/api/restHandler/AppListingRestHandler.go @@ -218,10 +218,8 @@ func (handler AppListingRestHandlerImpl) FetchJobs(w http.ResponseWriter, r *htt return } isSuperAdmin, err := handler.userService.IsSuperAdmin(int(userId)) - if !isSuperAdmin || err != nil { - if err != nil { - handler.logger.Errorw("request err, CheckSuperAdmin", "err", isSuperAdmin, "isSuperAdmin", isSuperAdmin) - } + if err != nil { + handler.logger.Errorw("request err, CheckSuperAdmin", "err", isSuperAdmin, "isSuperAdmin", isSuperAdmin) common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } From 800466cbf7b3bcf894af2ae4cb9fbedf71647a17 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Thu, 16 Nov 2023 14:38:06 +0530 Subject: [PATCH 25/76] fetch jobs --- api/restHandler/AppListingRestHandler.go | 10 +++++----- internal/sql/repository/app/AppRepository.go | 3 +++ pkg/app/AppListingService.go | 1 + util/rbac/EnforcerUtil.go | 3 ++- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/api/restHandler/AppListingRestHandler.go b/api/restHandler/AppListingRestHandler.go index 31bf31482c..8652e7402b 100644 --- a/api/restHandler/AppListingRestHandler.go +++ b/api/restHandler/AppListingRestHandler.go @@ -223,7 +223,7 @@ func (handler AppListingRestHandlerImpl) FetchJobs(w http.ResponseWriter, r *htt common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } - validAppIds := make([]int, 0) + var validAppIds []int //for non super admin users if !isSuperAdmin { userEmailId := strings.ToLower(user.EmailId) @@ -259,10 +259,10 @@ func (handler AppListingRestHandlerImpl) FetchJobs(w http.ResponseWriter, r *htt common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } - if !isSuperAdmin { - // fetching only those jobs whose access user has by setting valid app Ids. - fetchJobListingRequest.AppIds = validAppIds - } + + // fetching only those jobs whose access user has by setting valid app Ids. + fetchJobListingRequest.AppIds = validAppIds + jobs, err := handler.appListingService.FetchJobs(fetchJobListingRequest) if err != nil { handler.logger.Errorw("service err, FetchJobs", "err", err, "payload", fetchJobListingRequest) diff --git a/internal/sql/repository/app/AppRepository.go b/internal/sql/repository/app/AppRepository.go index 66d5154a2b..02929b5f8c 100644 --- a/internal/sql/repository/app/AppRepository.go +++ b/internal/sql/repository/app/AppRepository.go @@ -420,6 +420,9 @@ func (repo AppRepositoryImpl) FetchAppIdsWithFilter(jobListingFilter helper.AppL if len(jobListingFilter.Teams) > 0 { whereCondition += " and team_id in (" + helper.GetCommaSepratedString(jobListingFilter.Teams) + ")" } + if len(jobListingFilter.AppIds) > 0 { + whereCondition += " and id in (" + helper.GetCommaSepratedString(jobListingFilter.AppIds) + ")" + } if len(jobListingFilter.AppNameSearch) > 0 { whereCondition += " and display_name like '%" + jobListingFilter.AppNameSearch + "%' " diff --git a/pkg/app/AppListingService.go b/pkg/app/AppListingService.go index 6541c8fd05..21767da302 100644 --- a/pkg/app/AppListingService.go +++ b/pkg/app/AppListingService.go @@ -270,6 +270,7 @@ func (impl AppListingServiceImpl) FetchJobs(fetchJobListingRequest FetchAppListi Size: fetchJobListingRequest.Size, AppStatuses: fetchJobListingRequest.AppStatuses, Environments: fetchJobListingRequest.Environments, + AppIds: fetchJobListingRequest.AppIds, } appIds, err := impl.appRepository.FetchAppIdsWithFilter(jobListingFilter) if err != nil { diff --git a/util/rbac/EnforcerUtil.go b/util/rbac/EnforcerUtil.go index 414093462a..d957c21f66 100644 --- a/util/rbac/EnforcerUtil.go +++ b/util/rbac/EnforcerUtil.go @@ -22,6 +22,7 @@ import ( "github.com/devtron-labs/common-lib/utils/k8s" "github.com/devtron-labs/devtron/internal/sql/repository/helper" "github.com/devtron-labs/devtron/util" + "strings" "github.com/devtron-labs/devtron/internal/sql/repository/app" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig" @@ -165,7 +166,7 @@ func (impl EnforcerUtilImpl) GetRbacObjectsForAllApps(appType helper.AppType) ma } for _, item := range result { if _, ok := objects[item.Id]; !ok { - objects[item.Id] = fmt.Sprintf("%s/%s", item.Team.Name, item.AppName) + objects[item.Id] = fmt.Sprintf("%s/%s", item.Team.Name, strings.ToLower(item.AppName)) } } return objects From 6fccd954c409fbbe283765a3abc6304b5895dd2b Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Thu, 16 Nov 2023 16:36:40 +0530 Subject: [PATCH 26/76] workflow get --- api/restHandler/AppWorkflowRestHandler.go | 44 +++++++++++++++++++++-- util/rbac/EnforcerUtil.go | 15 ++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/api/restHandler/AppWorkflowRestHandler.go b/api/restHandler/AppWorkflowRestHandler.go index cdc0a9f44e..cfbaac11b4 100644 --- a/api/restHandler/AppWorkflowRestHandler.go +++ b/api/restHandler/AppWorkflowRestHandler.go @@ -22,6 +22,7 @@ import ( "github.com/devtron-labs/devtron/api/restHandler/common" "github.com/devtron-labs/devtron/internal/sql/repository/app" appWorkflow2 "github.com/devtron-labs/devtron/internal/sql/repository/appWorkflow" + "github.com/devtron-labs/devtron/internal/sql/repository/helper" "github.com/devtron-labs/devtron/internal/util" "github.com/devtron-labs/devtron/pkg/appWorkflow" "github.com/devtron-labs/devtron/pkg/bean" @@ -195,7 +196,11 @@ func (impl AppWorkflowRestHandlerImpl) FindAppWorkflow(w http.ResponseWriter, r // RBAC enforcer applying object := impl.enforcerUtil.GetAppRBACName(app.AppName) impl.Logger.Debugw("rbac object for other environment list", "object", object) - if ok := impl.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { + ok := impl.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) + if !ok { + ok = impl.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) + } + if !ok { common.WriteJsonResp(w, err, "unauthorized user", http.StatusForbidden) return } @@ -231,7 +236,42 @@ func (impl AppWorkflowRestHandlerImpl) FindAppWorkflow(w http.ResponseWriter, r workflows["appId"] = app.Id workflows["appName"] = app.AppName - if len(workflowsList) > 0 { + if len(workflowsList) > 0 && app.AppType == helper.Job { + // RBAC + userEmailId, err := impl.userAuthService.GetEmailFromToken(token) + if err != nil { + impl.Logger.Errorw("error in getting user emailId from token", "err", err) + common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) + return + } + + var workflowNames []string + var workflowIds []int + var updatedWorkflowList []appWorkflow.AppWorkflowDto + var rbacObjects []string + workNameObjectMap := make(map[string]appWorkflow.AppWorkflowDto) + + for _, workflow := range workflowsList { + workflowNames = append(workflowNames, workflow.Name) + workflowIds = append(workflowIds, workflow.Id) + } + workflowIdToObjectMap := impl.enforcerUtil.GetAllWorkflowRBACObjectsByAppId(appId, workflowNames, workflowIds) + itr := 0 + for _, val := range workflowIdToObjectMap { + rbacObjects = append(rbacObjects, val) + workNameObjectMap[val] = workflowsList[itr] + itr++ + } + + enforcedMap := impl.enforcer.EnforceByEmailInBatch(userEmailId, casbin.ResourceWorkflow, casbin.ActionGet, rbacObjects) + for obj, passed := range enforcedMap { + if passed { + updatedWorkflowList = append(updatedWorkflowList, workNameObjectMap[obj]) + } + } + + workflows["workflows"] = updatedWorkflowList + } else if len(workflowsList) > 0 { workflows["workflows"] = workflowsList } else { workflows["workflows"] = []appWorkflow.AppWorkflowDto{} diff --git a/util/rbac/EnforcerUtil.go b/util/rbac/EnforcerUtil.go index d957c21f66..431f11ee3b 100644 --- a/util/rbac/EnforcerUtil.go +++ b/util/rbac/EnforcerUtil.go @@ -69,6 +69,7 @@ type EnforcerUtil interface { GetRbacObjectNameByAppIdAndWorkflow(appId int, workflowName string) string GetWorkflowRBACByCiPipelineId(pipelineId int, workflowName string) string GetTeamEnvRBACNameByCiPipelineIdAndEnvIdOrName(ciPipelineId int, envId int, envName string) string + GetAllWorkflowRBACObjectsByAppId(appId int, workflowNames []string, workflowIds []int) map[int]string } type EnforcerUtilImpl struct { @@ -659,3 +660,17 @@ func (impl EnforcerUtilImpl) GetTeamEnvRBACNameByCiPipelineIdAndEnvIdOrName(ciPi } return fmt.Sprintf("%s/%s/%s", application.Team.Name, env.EnvironmentIdentifier, appName) } + +func (impl EnforcerUtilImpl) GetAllWorkflowRBACObjectsByAppId(appId int, workflowNames []string, workflowIds []int) map[int]string { + application, err := impl.appRepo.FindAppAndProjectByAppId(appId) + if err != nil { + return nil + } + appName := strings.ToLower(application.AppName) + teamName := application.Team.Name + objects := make(map[int]string, len(workflowNames)) + for index, wfName := range workflowNames { + objects[workflowIds[index]] = fmt.Sprintf("%s/%s/%s", teamName, appName, wfName) + } + return objects +} From 1dd7a5e9c28d0922ccdb9ae9500030ca566c35ae Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 17 Nov 2023 01:10:26 +0530 Subject: [PATCH 27/76] workflow status --- api/restHandler/app/PipelineConfigRestHandler.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/restHandler/app/PipelineConfigRestHandler.go b/api/restHandler/app/PipelineConfigRestHandler.go index 05e4a1489d..fa6255bbcb 100644 --- a/api/restHandler/app/PipelineConfigRestHandler.go +++ b/api/restHandler/app/PipelineConfigRestHandler.go @@ -603,7 +603,11 @@ func (handler PipelineConfigRestHandlerImpl) FetchAppWorkflowStatusForTriggerVie handler.Logger.Infow("request payload, FetchAppWorkflowStatusForTriggerView", "appId", appId) //RBAC CHECK resourceName := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, resourceName); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, resourceName) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, resourceName) + } + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } From 6823412b245ed51944cfb3aab38a9f68edc8881d Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 17 Nov 2023 08:44:25 +0530 Subject: [PATCH 28/76] ci-pipeline get --- api/restHandler/app/BuildPipelineRestHandler.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/restHandler/app/BuildPipelineRestHandler.go b/api/restHandler/app/BuildPipelineRestHandler.go index 529cc47fac..5d800bee97 100644 --- a/api/restHandler/app/BuildPipelineRestHandler.go +++ b/api/restHandler/app/BuildPipelineRestHandler.go @@ -805,7 +805,11 @@ func (handler PipelineConfigRestHandlerImpl) GetCiPipelineMin(w http.ResponseWri handler.Logger.Infow("request payload, GetCiPipelineMin", "appId", appId) token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) + } + if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } From 1b47695615c67229ed1188b73952776ae2dfc61c Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 17 Nov 2023 08:47:16 +0530 Subject: [PATCH 29/76] min other env --- api/restHandler/AppListingRestHandler.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/restHandler/AppListingRestHandler.go b/api/restHandler/AppListingRestHandler.go index 8652e7402b..3a006fe06e 100644 --- a/api/restHandler/AppListingRestHandler.go +++ b/api/restHandler/AppListingRestHandler.go @@ -1320,7 +1320,11 @@ func (handler AppListingRestHandlerImpl) FetchMinDetailOtherEnvironment(w http.R // RBAC enforcer applying object := handler.enforcerUtil.GetAppRBACName(app.AppName) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) + } + if !ok { common.WriteJsonResp(w, err, "unauthorized user", http.StatusForbidden) return } From f6d8ccc4decfd664999f346e62f894888fbb08bb Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 17 Nov 2023 08:48:52 +0530 Subject: [PATCH 30/76] app stage status --- api/restHandler/AppListingRestHandler.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/restHandler/AppListingRestHandler.go b/api/restHandler/AppListingRestHandler.go index 3a006fe06e..29f14f2cd4 100644 --- a/api/restHandler/AppListingRestHandler.go +++ b/api/restHandler/AppListingRestHandler.go @@ -1247,7 +1247,11 @@ func (handler AppListingRestHandlerImpl) FetchAppStageStatus(w http.ResponseWrit // RBAC enforcer applying object := handler.enforcerUtil.GetAppRBACName(app.AppName) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) + } + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } From 660642b02485aabe36b599c4bcf7def3d9edeb98 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 17 Nov 2023 09:06:54 +0530 Subject: [PATCH 31/76] material get --- api/restHandler/app/BuildPipelineRestHandler.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/restHandler/app/BuildPipelineRestHandler.go b/api/restHandler/app/BuildPipelineRestHandler.go index 5d800bee97..6691849e04 100644 --- a/api/restHandler/app/BuildPipelineRestHandler.go +++ b/api/restHandler/app/BuildPipelineRestHandler.go @@ -675,7 +675,11 @@ func (handler PipelineConfigRestHandlerImpl) FetchMaterials(w http.ResponseWrite //RBAC token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(ciPipeline.AppId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) + } + if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } From 25b85bb0741c5acb3f2a6ce9615169ea2218c1e4 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 17 Nov 2023 09:09:06 +0530 Subject: [PATCH 32/76] logs get --- api/restHandler/app/BuildPipelineRestHandler.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/restHandler/app/BuildPipelineRestHandler.go b/api/restHandler/app/BuildPipelineRestHandler.go index 6691849e04..e12b12a357 100644 --- a/api/restHandler/app/BuildPipelineRestHandler.go +++ b/api/restHandler/app/BuildPipelineRestHandler.go @@ -1043,7 +1043,11 @@ func (handler *PipelineConfigRestHandlerImpl) GetBuildLogs(w http.ResponseWriter //RBAC token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(ciPipeline.AppId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) + } + if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } From 476ed91009b3f41b736b9f6b2fcea3891e47caac Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 17 Nov 2023 09:22:54 +0530 Subject: [PATCH 33/76] get env for job --- api/restHandler/ConfigMapRestHandler.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/api/restHandler/ConfigMapRestHandler.go b/api/restHandler/ConfigMapRestHandler.go index 4d389fbc7f..f8b575a78c 100644 --- a/api/restHandler/ConfigMapRestHandler.go +++ b/api/restHandler/ConfigMapRestHandler.go @@ -892,12 +892,10 @@ func (handler ConfigMapRestHandlerImpl) GetEnvironmentsForJob(w http.ResponseWri return } //AUTH - check from casbin db - isSuperAdmin, err := handler.userAuthService.IsSuperAdmin(int(userId)) - if !isSuperAdmin || err != nil { - if err != nil { - handler.Logger.Errorw("request err, CheckSuperAdmin", "err", isSuperAdmin, "isSuperAdmin", isSuperAdmin) - } - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) + token := r.Header.Get("token") + object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) + if ok := handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object); !ok { + common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } //AUTH From fd49dc2093163a45ca1bb60a7c7e52a31e10dcb5 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 17 Nov 2023 09:26:04 +0530 Subject: [PATCH 34/76] pipeline get --- api/restHandler/app/BuildPipelineRestHandler.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/restHandler/app/BuildPipelineRestHandler.go b/api/restHandler/app/BuildPipelineRestHandler.go index e12b12a357..73627948e0 100644 --- a/api/restHandler/app/BuildPipelineRestHandler.go +++ b/api/restHandler/app/BuildPipelineRestHandler.go @@ -1148,7 +1148,11 @@ func (handler PipelineConfigRestHandlerImpl) GetCIPipelineById(w http.ResponseWr return } resourceName := handler.enforcerUtil.GetAppRBACName(app.AppName) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, resourceName); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, resourceName) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, resourceName) + } + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } From 2c47da96aca8b539e3952d98467f5e98d82c2440 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 17 Nov 2023 09:27:49 +0530 Subject: [PATCH 35/76] app get --- api/restHandler/app/PipelineConfigRestHandler.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/restHandler/app/PipelineConfigRestHandler.go b/api/restHandler/app/PipelineConfigRestHandler.go index fa6255bbcb..27dff7b086 100644 --- a/api/restHandler/app/PipelineConfigRestHandler.go +++ b/api/restHandler/app/PipelineConfigRestHandler.go @@ -418,7 +418,11 @@ func (handler PipelineConfigRestHandlerImpl) GetApp(w http.ResponseWriter, r *ht //rbac implementation starts here object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) + } + if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } From 1940f8b690121c11b52742cedcdc64f27e3cb674 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 17 Nov 2023 09:32:23 +0530 Subject: [PATCH 36/76] global plugins --- api/restHandler/GlobalPluginRestHandler.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/api/restHandler/GlobalPluginRestHandler.go b/api/restHandler/GlobalPluginRestHandler.go index e24c6538e8..f5c6796009 100644 --- a/api/restHandler/GlobalPluginRestHandler.go +++ b/api/restHandler/GlobalPluginRestHandler.go @@ -57,7 +57,11 @@ func (handler *GlobalPluginRestHandlerImpl) GetAllGlobalVariables(w http.Respons //on atleast one app & we can't check this without iterating through every app //TODO: update plugin as a resource in casbin and make rbac independent of appId resourceName := handler.enforcerUtil.GetAppRBACName(app.AppName) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, resourceName); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, resourceName) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionCreate, resourceName) + } + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } @@ -89,7 +93,11 @@ func (handler *GlobalPluginRestHandlerImpl) ListAllPlugins(w http.ResponseWriter //on atleast one app & we can't check this without iterating through every app //TODO: update plugin as a resource in casbin and make rbac independent of appId resourceName := handler.enforcerUtil.GetAppRBACName(app.AppName) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, resourceName); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, resourceName) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionCreate, resourceName) + } + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } @@ -131,7 +139,11 @@ func (handler *GlobalPluginRestHandlerImpl) GetPluginDetailById(w http.ResponseW //on atleast one app & we can't check this without iterating through every app //TODO: update plugin as a resource in casbin and make rbac independent of appId resourceName := handler.enforcerUtil.GetAppRBACName(app.AppName) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, resourceName); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, resourceName) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionCreate, resourceName) + } + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } From 481a6794f3d452857c570a7c25bbfb0193780631 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 17 Nov 2023 09:47:33 +0530 Subject: [PATCH 37/76] git material --- api/restHandler/app/AutoCompleteRestHandler.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/restHandler/app/AutoCompleteRestHandler.go b/api/restHandler/app/AutoCompleteRestHandler.go index 3e7e640406..206517ea61 100644 --- a/api/restHandler/app/AutoCompleteRestHandler.go +++ b/api/restHandler/app/AutoCompleteRestHandler.go @@ -154,7 +154,11 @@ func (handler PipelineConfigRestHandlerImpl) GitListAutocomplete(w http.Response handler.Logger.Infow("request payload, GitListAutocomplete", "appId", appId) //RBAC object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) + } + if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } From c241767389eff88bb070917b127103c096d92be5 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 17 Nov 2023 09:59:03 +0530 Subject: [PATCH 38/76] cm cs get --- api/restHandler/ConfigMapRestHandler.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/api/restHandler/ConfigMapRestHandler.go b/api/restHandler/ConfigMapRestHandler.go index f8b575a78c..c44ae59904 100644 --- a/api/restHandler/ConfigMapRestHandler.go +++ b/api/restHandler/ConfigMapRestHandler.go @@ -188,7 +188,11 @@ func (handler ConfigMapRestHandlerImpl) CMGlobalFetch(w http.ResponseWriter, r * //RBAC START token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) + } + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } @@ -421,7 +425,11 @@ func (handler ConfigMapRestHandlerImpl) CSGlobalFetch(w http.ResponseWriter, r * //RBAC START token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) + } + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), nil, http.StatusForbidden) return } From 1db1798d150a9e39a796cd757cd37c919ede8266 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 17 Nov 2023 10:21:52 +0530 Subject: [PATCH 39/76] global variable --- api/restHandler/scopedVariable/ScopedVariableRestHandler.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/restHandler/scopedVariable/ScopedVariableRestHandler.go b/api/restHandler/scopedVariable/ScopedVariableRestHandler.go index 00e3a47547..414b80f62a 100644 --- a/api/restHandler/scopedVariable/ScopedVariableRestHandler.go +++ b/api/restHandler/scopedVariable/ScopedVariableRestHandler.go @@ -147,7 +147,11 @@ func (handler *ScopedVariableRestHandlerImpl) GetScopedVariables(w http.Response } handler.logger.Infow("request payload, GetScopedVariables", "payload", scope.AppId, scope.EnvId, scope.ClusterId) resourceName := handler.enforcerUtil.GetAppRBACName(app.AppName) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, resourceName); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, resourceName) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, resourceName) + } + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } From e6118bddd6b043769da28fe47289d30ac4d394a0 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 17 Nov 2023 10:26:28 +0530 Subject: [PATCH 40/76] get suggest --- api/restHandler/app/PipelineConfigRestHandler.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/restHandler/app/PipelineConfigRestHandler.go b/api/restHandler/app/PipelineConfigRestHandler.go index 27dff7b086..0d9d125966 100644 --- a/api/restHandler/app/PipelineConfigRestHandler.go +++ b/api/restHandler/app/PipelineConfigRestHandler.go @@ -685,7 +685,11 @@ func (handler PipelineConfigRestHandlerImpl) PipelineNameSuggestion(w http.Respo } suggestedName := fmt.Sprintf("%s-%d-%s", pType, appId, util2.Generate(4)) resourceName := handler.enforcerUtil.GetAppRBACName(app.AppName) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, resourceName); !ok { + ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, resourceName) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, resourceName) + } + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } From c08803269b7483b7222149a0989b788d58eadf66 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 17 Nov 2023 11:29:27 +0530 Subject: [PATCH 41/76] update app --- api/restHandler/AppRestHandler.go | 6 +++++- util/rbac/EnforcerUtil.go | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/api/restHandler/AppRestHandler.go b/api/restHandler/AppRestHandler.go index 558de715eb..11c118b1c0 100644 --- a/api/restHandler/AppRestHandler.go +++ b/api/restHandler/AppRestHandler.go @@ -223,7 +223,11 @@ func (handler AppRestHandlerImpl) UpdateApp(w http.ResponseWriter, r *http.Reque // check for request project/app permission object = handler.enforcerUtil.GetAppRBACNameByTeamIdAndAppId(request.TeamId, request.Id) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionUpdate, object); !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionUpdate, object) + if !ok { + ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionUpdate, object) + } + if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } diff --git a/util/rbac/EnforcerUtil.go b/util/rbac/EnforcerUtil.go index 431f11ee3b..60600ac529 100644 --- a/util/rbac/EnforcerUtil.go +++ b/util/rbac/EnforcerUtil.go @@ -70,6 +70,7 @@ type EnforcerUtil interface { GetWorkflowRBACByCiPipelineId(pipelineId int, workflowName string) string GetTeamEnvRBACNameByCiPipelineIdAndEnvIdOrName(ciPipelineId int, envId int, envName string) string GetAllWorkflowRBACObjectsByAppId(appId int, workflowNames []string, workflowIds []int) map[int]string + GetEnvRBACArrayByAppIdForJobs(appId int) []string } type EnforcerUtilImpl struct { @@ -674,3 +675,18 @@ func (impl EnforcerUtilImpl) GetAllWorkflowRBACObjectsByAppId(appId int, workflo } return objects } + +func (impl EnforcerUtilImpl) GetEnvRBACArrayByAppIdForJobs(appId int) []string { + var rbacObjects []string + + pipelines, err := impl.pipelineRepository.FindActiveByAppId(appId) + if err != nil { + impl.logger.Error(err) + return rbacObjects + } + for _, item := range pipelines { + rbacObjects = append(rbacObjects, impl.GetTeamEnvRBACNameByCiPipelineIdAndEnvIdOrName(item.Id, item.EnvironmentId, "")) + } + + return rbacObjects +} From aa2ad720575eb2491f7e66e70bc02a25978d9137 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 17 Nov 2023 14:03:03 +0530 Subject: [PATCH 42/76] job-clone --- pkg/pipeline/BuildPipelineConfigService.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/pipeline/BuildPipelineConfigService.go b/pkg/pipeline/BuildPipelineConfigService.go index 933e20dc46..e0859098ba 100644 --- a/pkg/pipeline/BuildPipelineConfigService.go +++ b/pkg/pipeline/BuildPipelineConfigService.go @@ -24,6 +24,7 @@ import ( app2 "github.com/devtron-labs/devtron/internal/sql/repository/app" "github.com/devtron-labs/devtron/internal/sql/repository/appWorkflow" dockerRegistryRepository "github.com/devtron-labs/devtron/internal/sql/repository/dockerRegistry" + "github.com/devtron-labs/devtron/internal/sql/repository/helper" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig" "github.com/devtron-labs/devtron/internal/util" "github.com/devtron-labs/devtron/pkg/attributes" @@ -1347,6 +1348,7 @@ func (impl *CiPipelineConfigServiceImpl) CreateCiPipeline(createRequest *bean.Ci } //--ecr config createRequest.AppName = app.AppName + createRequest.IsJob = app.AppType == helper.Job if !createRequest.IsJob { store, err := impl.getDefaultArtifactStore(createRequest.DockerRegistry) if err != nil { From 743106d7ebf88f8712d10df054712600f270984f Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 17 Nov 2023 15:22:01 +0530 Subject: [PATCH 43/76] workflow delete handling --- .../deployment/service/ChartGroupService.go | 2 +- pkg/appWorkflow/AppWorkflowService.go | 26 ++++++++++++++++++- pkg/cluster/EnvironmentService.go | 2 +- pkg/pipeline/CiCdPipelineOrchestrator.go | 2 +- pkg/team/TeamService.go | 2 +- pkg/user/UserAuthService.go | 6 +++-- pkg/user/bean/bean.go | 1 + pkg/user/repository/UserAuthRepository.go | 13 ++++++++++ wire_gen.go | 2 +- 9 files changed, 48 insertions(+), 8 deletions(-) diff --git a/pkg/appStore/deployment/service/ChartGroupService.go b/pkg/appStore/deployment/service/ChartGroupService.go index c643d318fd..edca1d9540 100644 --- a/pkg/appStore/deployment/service/ChartGroupService.go +++ b/pkg/appStore/deployment/service/ChartGroupService.go @@ -466,7 +466,7 @@ func (impl *ChartGroupServiceImpl) DeleteChartGroup(req *ChartGroupBean) error { return err } //deleting auth roles entries for this chart group - err = impl.userAuthService.DeleteRoles(bean.CHART_GROUP_TYPE, req.Name, tx, "") + err = impl.userAuthService.DeleteRoles(bean.CHART_GROUP_TYPE, req.Name, tx, "", "") if err != nil { impl.Logger.Errorw("error in deleting auth roles", "err", err) return err diff --git a/pkg/appWorkflow/AppWorkflowService.go b/pkg/appWorkflow/AppWorkflowService.go index 4fb34b175d..bee9a05c8b 100644 --- a/pkg/appWorkflow/AppWorkflowService.go +++ b/pkg/appWorkflow/AppWorkflowService.go @@ -18,6 +18,7 @@ package appWorkflow import ( + "errors" "fmt" mapset "github.com/deckarep/golang-set" appRepository "github.com/devtron-labs/devtron/internal/sql/repository/app" @@ -28,6 +29,8 @@ import ( "github.com/devtron-labs/devtron/pkg/pipeline" resourceGroup2 "github.com/devtron-labs/devtron/pkg/resourceGroup" "github.com/devtron-labs/devtron/pkg/sql" + "github.com/devtron-labs/devtron/pkg/user" + bean3 "github.com/devtron-labs/devtron/pkg/user/bean" "github.com/devtron-labs/devtron/util/rbac" "github.com/go-pg/pg" "go.uber.org/zap" @@ -70,6 +73,7 @@ type AppWorkflowServiceImpl struct { resourceGroupService resourceGroup2.ResourceGroupService appRepository appRepository.AppRepository enforcerUtil rbac.EnforcerUtil + userAuthService user.UserAuthService } type AppWorkflowDto struct { @@ -150,7 +154,7 @@ type PipelineIdentifier struct { func NewAppWorkflowServiceImpl(logger *zap.SugaredLogger, appWorkflowRepository appWorkflow.AppWorkflowRepository, ciCdPipelineOrchestrator pipeline.CiCdPipelineOrchestrator, ciPipelineRepository pipelineConfig.CiPipelineRepository, pipelineRepository pipelineConfig.PipelineRepository, enforcerUtil rbac.EnforcerUtil, resourceGroupService resourceGroup2.ResourceGroupService, - appRepository appRepository.AppRepository) *AppWorkflowServiceImpl { + appRepository appRepository.AppRepository, userAuthService user.UserAuthService) *AppWorkflowServiceImpl { return &AppWorkflowServiceImpl{ Logger: logger, appWorkflowRepository: appWorkflowRepository, @@ -160,6 +164,7 @@ func NewAppWorkflowServiceImpl(logger *zap.SugaredLogger, appWorkflowRepository enforcerUtil: enforcerUtil, resourceGroupService: resourceGroupService, appRepository: appRepository, + userAuthService: userAuthService, } } @@ -180,6 +185,15 @@ func (impl AppWorkflowServiceImpl) CreateAppWorkflow(req AppWorkflowDto) (AppWor } savedAppWf, err = impl.appWorkflowRepository.UpdateAppWorkflow(wf) } else { + workflow, err := impl.appWorkflowRepository.FindByNameAndAppId(req.Name, req.AppId) + if err != nil && err != pg.ErrNoRows { + impl.Logger.Errorw("error in finding workflow by app id and name", "name", req.Name, "appId", req.AppId) + return req, err + } + if workflow.Id != 0 { + impl.Logger.Errorw("workflow with this name already exist", "err", err) + return req, errors.New("workflow with this name already exist in this app") + } wf := &appWorkflow.AppWorkflow{ Name: req.Name, AppId: req.AppId, @@ -258,6 +272,11 @@ func (impl AppWorkflowServiceImpl) DeleteAppWorkflow(appWorkflowId int, userId i impl.Logger.Errorw("err", err) return err } + app, err := impl.appRepository.FindById(wf.AppId) + if err != nil { + impl.Logger.Errorw("error in finding app by app id", "err", err, "appId", wf.AppId) + return err + } mappingForCI, err := impl.appWorkflowRepository.FindWFAllMappingByWorkflowId(wf.Id) if err != nil { @@ -294,6 +313,11 @@ func (impl AppWorkflowServiceImpl) DeleteAppWorkflow(appWorkflowId int, userId i return err } } + err = impl.userAuthService.DeleteRoles(bean3.WorkflowType, app.AppName, tx, "", wf.Name) + if err != nil { + impl.Logger.Errorw("error in deleting auth roles", "err", err) + return err + } err = tx.Commit() if err != nil { diff --git a/pkg/cluster/EnvironmentService.go b/pkg/cluster/EnvironmentService.go index 849d9d6957..b5a3a9c3fa 100644 --- a/pkg/cluster/EnvironmentService.go +++ b/pkg/cluster/EnvironmentService.go @@ -745,7 +745,7 @@ func (impl EnvironmentServiceImpl) Delete(deleteReq *EnvironmentBean, userId int return err } //deleting auth roles entries for this environment - err = impl.userAuthService.DeleteRoles(bean.ENV_TYPE, deleteRequest.Name, tx, existingEnv.EnvironmentIdentifier) + err = impl.userAuthService.DeleteRoles(bean.ENV_TYPE, deleteRequest.Name, tx, existingEnv.EnvironmentIdentifier, "") if err != nil { impl.logger.Errorw("error in deleting auth roles", "err", err) return err diff --git a/pkg/pipeline/CiCdPipelineOrchestrator.go b/pkg/pipeline/CiCdPipelineOrchestrator.go index f6c947c75d..ceb74b52e0 100644 --- a/pkg/pipeline/CiCdPipelineOrchestrator.go +++ b/pkg/pipeline/CiCdPipelineOrchestrator.go @@ -1168,7 +1168,7 @@ func (impl CiCdPipelineOrchestratorImpl) DeleteApp(appId int, userId int32) erro return err } //deleting auth roles entries for this project - err = impl.userAuthService.DeleteRoles(bean3.APP_TYPE, app.AppName, tx, "") + err = impl.userAuthService.DeleteRoles(bean3.APP_TYPE, app.AppName, tx, "", "") if err != nil { impl.logger.Errorw("error in deleting auth roles", "err", err) return err diff --git a/pkg/team/TeamService.go b/pkg/team/TeamService.go index a6b678c287..af3828ebe9 100644 --- a/pkg/team/TeamService.go +++ b/pkg/team/TeamService.go @@ -185,7 +185,7 @@ func (impl TeamServiceImpl) Delete(deleteRequest *TeamRequest) error { return err } //deleting auth roles entries for this project - err = impl.userAuthService.DeleteRoles(bean.PROJECT_TYPE, deleteRequest.Name, tx, "") + err = impl.userAuthService.DeleteRoles(bean.PROJECT_TYPE, deleteRequest.Name, tx, "", "") if err != nil { impl.logger.Errorw("error in deleting auth roles", "err", err) return err diff --git a/pkg/user/UserAuthService.go b/pkg/user/UserAuthService.go index b1719ccd48..348102874a 100644 --- a/pkg/user/UserAuthService.go +++ b/pkg/user/UserAuthService.go @@ -54,7 +54,7 @@ type UserAuthService interface { CreateRole(roleData *bean.RoleData) (bool, error) AuthVerification(r *http.Request) (bool, error) - DeleteRoles(entityType string, entityName string, tx *pg.Tx, envIdentifier string) error + DeleteRoles(entityType string, entityName string, tx *pg.Tx, envIdentifier string, workflowName string) error } type UserAuthServiceImpl struct { @@ -476,7 +476,7 @@ func (impl UserAuthServiceImpl) AuthVerification(r *http.Request) (bool, error) //TODO - extends for other purpose return true, nil } -func (impl UserAuthServiceImpl) DeleteRoles(entityType string, entityName string, tx *pg.Tx, envIdentifier string) (err error) { +func (impl UserAuthServiceImpl) DeleteRoles(entityType string, entityName string, tx *pg.Tx, envIdentifier string, workflowName string) (err error) { var roleModels []*repository2.RoleModel switch entityType { case bean2.PROJECT_TYPE: @@ -487,6 +487,8 @@ func (impl UserAuthServiceImpl) DeleteRoles(entityType string, entityName string roleModels, err = impl.userAuthRepository.GetRolesForApp(entityName) case bean2.CHART_GROUP_TYPE: roleModels, err = impl.userAuthRepository.GetRolesForChartGroup(entityName) + case bean2.WorkflowType: + roleModels, err = impl.userAuthRepository.GetRolesForWorkflow(workflowName, entityName) } if err != nil { impl.logger.Errorw(fmt.Sprintf("error in getting roles by %s", entityType), "err", err, "name", entityName) diff --git a/pkg/user/bean/bean.go b/pkg/user/bean/bean.go index 13b17d2630..b4d7ea9b1a 100644 --- a/pkg/user/bean/bean.go +++ b/pkg/user/bean/bean.go @@ -6,6 +6,7 @@ const ( PROJECT_TYPE = "team" ENV_TYPE = "environment" APP_TYPE = "app" + WorkflowType = "workflow" CHART_GROUP_TYPE = "chart-group" MANAGER_TYPE RoleType = "manager" ADMIN_TYPE RoleType = "admin" diff --git a/pkg/user/repository/UserAuthRepository.go b/pkg/user/repository/UserAuthRepository.go index 065170e12b..663744e94e 100644 --- a/pkg/user/repository/UserAuthRepository.go +++ b/pkg/user/repository/UserAuthRepository.go @@ -61,6 +61,7 @@ type UserAuthRepository interface { //GetRoleByFilterForClusterEntity(cluster, namespace, group, kind, resource, action string) (RoleModel, error) GetRolesByUserIdAndEntityType(userId int32, entityType string) ([]*RoleModel, error) CreateRolesWithAccessTypeAndEntity(team, entityName, env, entity, cluster, namespace, group, kind, resource, actionType, accessType string, UserId int32, role string) (bool, error) + GetRolesForWorkflow(workflow, entityName string) ([]*RoleModel, error) } type UserAuthRepositoryImpl struct { @@ -992,3 +993,15 @@ func (impl UserAuthRepositoryImpl) GetRolesByUserIdAndEntityType(userId int32, e } return models, nil } + +func (impl UserAuthRepositoryImpl) GetRolesForWorkflow(workflow, entityName string) ([]*RoleModel, error) { + var roles []*RoleModel + err := impl.dbConnection.Model(&roles).Where("workflow = ?", workflow). + Where("entity_name = ?", entityName). + Select() + if err != nil { + impl.Logger.Errorw("error in getting roles for team", "err", err, "workflow", workflow) + return nil, err + } + return roles, nil +} diff --git a/wire_gen.go b/wire_gen.go index d3334c920a..e6089248df 100644 --- a/wire_gen.go +++ b/wire_gen.go @@ -519,7 +519,7 @@ func InitializeApp() (*App, error) { appListingServiceImpl := app2.NewAppListingServiceImpl(sugaredLogger, appListingRepositoryImpl, applicationServiceClientImpl, appRepositoryImpl, appListingViewBuilderImpl, pipelineRepositoryImpl, linkoutsRepositoryImpl, appLevelMetricsRepositoryImpl, envLevelAppMetricsRepositoryImpl, cdWorkflowRepositoryImpl, pipelineOverrideRepositoryImpl, environmentRepositoryImpl, argoUserServiceImpl, envConfigOverrideRepositoryImpl, chartRepositoryImpl, ciPipelineRepositoryImpl, dockerRegistryIpsConfigServiceImpl) deploymentEventHandlerImpl := app2.NewDeploymentEventHandlerImpl(sugaredLogger, appListingServiceImpl, eventRESTClientImpl, eventSimpleFactoryImpl) cdHandlerImpl := pipeline.NewCdHandlerImpl(sugaredLogger, userServiceImpl, cdWorkflowRepositoryImpl, ciLogServiceImpl, ciArtifactRepositoryImpl, ciPipelineMaterialRepositoryImpl, pipelineRepositoryImpl, environmentRepositoryImpl, ciWorkflowRepositoryImpl, helmAppServiceImpl, pipelineOverrideRepositoryImpl, workflowDagExecutorImpl, appListingServiceImpl, appListingRepositoryImpl, pipelineStatusTimelineRepositoryImpl, applicationServiceClientImpl, argoUserServiceImpl, deploymentEventHandlerImpl, eventRESTClientImpl, pipelineStatusTimelineResourcesServiceImpl, pipelineStatusSyncDetailServiceImpl, pipelineStatusTimelineServiceImpl, appServiceImpl, appStatusServiceImpl, enforcerUtilImpl, installedAppRepositoryImpl, installedAppVersionHistoryRepositoryImpl, appRepositoryImpl, resourceGroupServiceImpl, imageTaggingServiceImpl, k8sUtil, workflowServiceImpl, clusterServiceImplExtended, blobStorageConfigServiceImpl) - appWorkflowServiceImpl := appWorkflow2.NewAppWorkflowServiceImpl(sugaredLogger, appWorkflowRepositoryImpl, ciCdPipelineOrchestratorImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, enforcerUtilImpl, resourceGroupServiceImpl, appRepositoryImpl) + appWorkflowServiceImpl := appWorkflow2.NewAppWorkflowServiceImpl(sugaredLogger, appWorkflowRepositoryImpl, ciCdPipelineOrchestratorImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, enforcerUtilImpl, resourceGroupServiceImpl, appRepositoryImpl, userAuthServiceImpl) appCloneServiceImpl := appClone.NewAppCloneServiceImpl(sugaredLogger, pipelineBuilderImpl, materialRepositoryImpl, chartServiceImpl, configMapServiceImpl, appWorkflowServiceImpl, appListingServiceImpl, propertiesConfigServiceImpl, ciTemplateOverrideRepositoryImpl, pipelineStageServiceImpl, ciTemplateServiceImpl, appRepositoryImpl, ciPipelineRepositoryImpl, pipelineRepositoryImpl, appWorkflowRepositoryImpl) deploymentTemplateRepositoryImpl := repository.NewDeploymentTemplateRepositoryImpl(db, sugaredLogger) deploymentTemplateServiceImpl := generateManifest.NewDeploymentTemplateServiceImpl(sugaredLogger, chartServiceImpl, appListingServiceImpl, appListingRepositoryImpl, deploymentTemplateRepositoryImpl, helmAppServiceImpl, chartRepositoryImpl, chartTemplateServiceImpl, helmAppClientImpl, k8sUtil, propertiesConfigServiceImpl, deploymentTemplateHistoryServiceImpl, environmentRepositoryImpl, appRepositoryImpl, scopedVariableManagerImpl) From 4b6381f8029fd7058a111717db4284a11c5a6a58 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 17 Nov 2023 17:58:36 +0530 Subject: [PATCH 44/76] omit empty --- api/bean/UserRequest.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/bean/UserRequest.go b/api/bean/UserRequest.go index f8b47d2636..1edbfc8d3c 100644 --- a/api/bean/UserRequest.go +++ b/api/bean/UserRequest.go @@ -66,7 +66,7 @@ type RoleFilter struct { Group string `json:"group"` Kind string `json:"kind"` Resource string `json:"resource"` - Workflow string `json:"workflow"` + Workflow string `json:"workflow,omitempty"` } type Role struct { From 13f44d1baa13e3e6baf921d9d5304f5f8335b50e Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 17 Nov 2023 18:28:50 +0530 Subject: [PATCH 45/76] entity --- pkg/user/repository/UserAuthRepository.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/user/repository/UserAuthRepository.go b/pkg/user/repository/UserAuthRepository.go index 663744e94e..5c626d7553 100644 --- a/pkg/user/repository/UserAuthRepository.go +++ b/pkg/user/repository/UserAuthRepository.go @@ -317,7 +317,7 @@ func (impl UserAuthRepositoryImpl) GetRoleByFilterForAllTypes(entity, team, app, _, err = impl.dbConnection.Query(&model, query, entity, act) } else if entity == bean2.EntityJobs { if len(team) > 0 && len(act) > 0 { - query := "SELECT role.* FROM roles role WHERE role.team = ? AND role.action=? " + query := "SELECT role.* FROM roles role WHERE role.team = ? AND role.action=? AND role.entity=? " if len(env) == 0 { query = query + " AND role.environment is NULL" } else { @@ -333,7 +333,7 @@ func (impl UserAuthRepositoryImpl) GetRoleByFilterForAllTypes(entity, team, app, } else { query += " AND role.workflow='" + workflow + "';" } - _, err = impl.dbConnection.Query(&model, query, team, act) + _, err = impl.dbConnection.Query(&model, query, team, act, entity) } else { return model, nil } From 47ce0e79028a1d8cc8b62b6abb9faf5703040fc6 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 17 Nov 2023 20:56:30 +0530 Subject: [PATCH 46/76] workflow empty --- api/bean/UserRequest.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/bean/UserRequest.go b/api/bean/UserRequest.go index 1edbfc8d3c..f8b47d2636 100644 --- a/api/bean/UserRequest.go +++ b/api/bean/UserRequest.go @@ -66,7 +66,7 @@ type RoleFilter struct { Group string `json:"group"` Kind string `json:"kind"` Resource string `json:"resource"` - Workflow string `json:"workflow,omitempty"` + Workflow string `json:"workflow"` } type Role struct { From e854c4935b12f0f7a6e633c4780838a143ba8523 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Sun, 19 Nov 2023 10:45:43 +0530 Subject: [PATCH 47/76] review comments --- api/restHandler/AppWorkflowRestHandler.go | 9 +++++---- api/restHandler/app/BuildPipelineRestHandler.go | 1 + api/restHandler/bean/bean.go | 2 ++ api/router/PipelineConfigRouter.go | 6 +++--- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/api/restHandler/AppWorkflowRestHandler.go b/api/restHandler/AppWorkflowRestHandler.go index cfbaac11b4..b5dd6fe166 100644 --- a/api/restHandler/AppWorkflowRestHandler.go +++ b/api/restHandler/AppWorkflowRestHandler.go @@ -19,6 +19,7 @@ package restHandler import ( "encoding/json" + bean2 "github.com/devtron-labs/devtron/api/restHandler/bean" "github.com/devtron-labs/devtron/api/restHandler/common" "github.com/devtron-labs/devtron/internal/sql/repository/app" appWorkflow2 "github.com/devtron-labs/devtron/internal/sql/repository/appWorkflow" @@ -134,7 +135,7 @@ func (handler AppWorkflowRestHandlerImpl) DeleteAppWorkflow(w http.ResponseWrite } appWorkflow, err := handler.appWorkflowService.FindAppWorkflowById(appWorkflowId, appId) if err != nil { - handler.Logger.Errorw("bad request", "err", err) + handler.Logger.Errorw("error in finding appWorkflow by appWorkflowId and appId", "err", err, "appWorkflowId", appWorkflowId, "appid", appId) common.WriteJsonResp(w, err, nil, http.StatusInternalServerError) return } @@ -270,11 +271,11 @@ func (impl AppWorkflowRestHandlerImpl) FindAppWorkflow(w http.ResponseWriter, r } } - workflows["workflows"] = updatedWorkflowList + workflows[bean2.Workflows] = updatedWorkflowList } else if len(workflowsList) > 0 { - workflows["workflows"] = workflowsList + workflows[bean2.Workflows] = workflowsList } else { - workflows["workflows"] = []appWorkflow.AppWorkflowDto{} + workflows[bean2.Workflows] = []appWorkflow.AppWorkflowDto{} } common.WriteJsonResp(w, err, workflows, http.StatusOK) } diff --git a/api/restHandler/app/BuildPipelineRestHandler.go b/api/restHandler/app/BuildPipelineRestHandler.go index 73627948e0..886d2fe9ec 100644 --- a/api/restHandler/app/BuildPipelineRestHandler.go +++ b/api/restHandler/app/BuildPipelineRestHandler.go @@ -589,6 +589,7 @@ func (handler PipelineConfigRestHandlerImpl) TriggerCiPipeline(w http.ResponseWr if len(appWorkflowMapping) > 0 { workflowName = appWorkflowMapping[0].AppWorkflow.Name } + // This is being done for jobs, jobs execute in default-env (devtron-ci) namespace by default. so considering DefaultCiNamespace as env for rbac enforcement envName := "" if ciTriggerRequest.EnvironmentId == 0 { envName = pipeline.DefaultCiWorkflowNamespace diff --git a/api/restHandler/bean/bean.go b/api/restHandler/bean/bean.go index f12fb42d74..df52f1287f 100644 --- a/api/restHandler/bean/bean.go +++ b/api/restHandler/bean/bean.go @@ -6,6 +6,8 @@ import ( "strings" ) +const Workflows = "workflows" + type EphemeralContainerData struct { Name string `json:"name"` IsExternal bool `json:"isExternal"` diff --git a/api/router/PipelineConfigRouter.go b/api/router/PipelineConfigRouter.go index 92b79ad8fc..54bc7613ec 100644 --- a/api/router/PipelineConfigRouter.go +++ b/api/router/PipelineConfigRouter.go @@ -149,12 +149,12 @@ func (router PipelineConfigRouterImpl) initPipelineConfigRouter(configRouter *mu configRouter.Path("/app-wf/{app-id}/{app-wf-id}"). HandlerFunc(router.appWorkflowRestHandler.DeleteAppWorkflow).Methods("DELETE") - configRouter.Path("/wf/all/component-names/{appId}"). - HandlerFunc(router.appWorkflowRestHandler.FindAllWorkflows).Methods("GET") - configRouter.Path("/app-wf/all"). HandlerFunc(router.appWorkflowRestHandler.FindAllWorkflowsForApps).Methods("POST") + configRouter.Path("/wf/all/component-names/{appId}"). + HandlerFunc(router.appWorkflowRestHandler.FindAllWorkflows).Methods("GET") + configRouter.Path("/cd-pipeline/workflow/history/{appId}/{environmentId}/{pipelineId}").HandlerFunc(router.restHandler.ListDeploymentHistory).Methods("GET") configRouter.Path("/cd-pipeline/workflow/logs/{appId}/{environmentId}/{pipelineId}/{workflowId}").HandlerFunc(router.restHandler.GetPrePostDeploymentLogs).Methods("GET") configRouter.Path("/cd-pipeline/workflow/trigger-info/{appId}/{environmentId}/{pipelineId}/{workflowRunnerId}").HandlerFunc(router.restHandler.FetchCdWorkflowDetails).Methods("GET") From 91adfe26d22ac36487d3f1f6cfcd264ec14faeef Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Sun, 19 Nov 2023 12:14:45 +0530 Subject: [PATCH 48/76] review comments --- api/restHandler/AppListingRestHandler.go | 10 +---- api/restHandler/AppRestHandler.go | 20 ++------- api/restHandler/AppWorkflowRestHandler.go | 5 +-- api/restHandler/ConfigMapRestHandler.go | 40 ++++------------- api/restHandler/GlobalPluginRestHandler.go | 15 ++----- .../app/AutoCompleteRestHandler.go | 5 +-- .../app/BuildPipelineRestHandler.go | 45 +++---------------- .../app/PipelineConfigRestHandler.go | 32 +++---------- .../ScopedVariableRestHandler.go | 5 +-- cmd/external-app/wire_gen.go | 2 +- util/rbac/EnforcerUtil.go | 13 +++++- wire_gen.go | 2 +- 12 files changed, 48 insertions(+), 146 deletions(-) diff --git a/api/restHandler/AppListingRestHandler.go b/api/restHandler/AppListingRestHandler.go index 29f14f2cd4..91b1515568 100644 --- a/api/restHandler/AppListingRestHandler.go +++ b/api/restHandler/AppListingRestHandler.go @@ -1247,10 +1247,7 @@ func (handler AppListingRestHandlerImpl) FetchAppStageStatus(w http.ResponseWrit // RBAC enforcer applying object := handler.enforcerUtil.GetAppRBACName(app.AppName) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionGet) if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return @@ -1324,10 +1321,7 @@ func (handler AppListingRestHandlerImpl) FetchMinDetailOtherEnvironment(w http.R // RBAC enforcer applying object := handler.enforcerUtil.GetAppRBACName(app.AppName) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionGet) if !ok { common.WriteJsonResp(w, err, "unauthorized user", http.StatusForbidden) return diff --git a/api/restHandler/AppRestHandler.go b/api/restHandler/AppRestHandler.go index 11c118b1c0..15f0ae0d9e 100644 --- a/api/restHandler/AppRestHandler.go +++ b/api/restHandler/AppRestHandler.go @@ -118,10 +118,7 @@ func (handler AppRestHandlerImpl) GetAppMetaInfo(w http.ResponseWriter, r *http. //rback implementation starts here token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionGet) if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return @@ -212,10 +209,7 @@ func (handler AppRestHandlerImpl) UpdateApp(w http.ResponseWriter, r *http.Reque // check for existing project/app permission object := handler.enforcerUtil.GetAppRBACNameByAppId(request.Id) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionUpdate, object) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionUpdate, object) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionUpdate) if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return @@ -223,10 +217,7 @@ func (handler AppRestHandlerImpl) UpdateApp(w http.ResponseWriter, r *http.Reque // check for request project/app permission object = handler.enforcerUtil.GetAppRBACNameByTeamIdAndAppId(request.TeamId, request.Id) - ok = handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionUpdate, object) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionUpdate, object) - } + ok = handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionUpdate) if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return @@ -385,10 +376,7 @@ func (handler AppRestHandlerImpl) UpdateAppNote(w http.ResponseWriter, r *http.R // check for existing project/app permission object := handler.enforcerUtil.GetAppRBACNameByAppId(bean.Identifier) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionUpdate, object) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionUpdate, object) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionUpdate) if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return diff --git a/api/restHandler/AppWorkflowRestHandler.go b/api/restHandler/AppWorkflowRestHandler.go index b5dd6fe166..8295ec20bd 100644 --- a/api/restHandler/AppWorkflowRestHandler.go +++ b/api/restHandler/AppWorkflowRestHandler.go @@ -197,10 +197,7 @@ func (impl AppWorkflowRestHandlerImpl) FindAppWorkflow(w http.ResponseWriter, r // RBAC enforcer applying object := impl.enforcerUtil.GetAppRBACName(app.AppName) impl.Logger.Debugw("rbac object for other environment list", "object", object) - ok := impl.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) - if !ok { - ok = impl.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) - } + ok := impl.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionGet) if !ok { common.WriteJsonResp(w, err, "unauthorized user", http.StatusForbidden) return diff --git a/api/restHandler/ConfigMapRestHandler.go b/api/restHandler/ConfigMapRestHandler.go index c44ae59904..dd1848e143 100644 --- a/api/restHandler/ConfigMapRestHandler.go +++ b/api/restHandler/ConfigMapRestHandler.go @@ -112,10 +112,7 @@ func (handler ConfigMapRestHandlerImpl) CMGlobalAddUpdate(w http.ResponseWriter, //RBAC START token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(configMapRequest.AppId) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, object) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionCreate, object) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionCreate) if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return @@ -188,10 +185,7 @@ func (handler ConfigMapRestHandlerImpl) CMGlobalFetch(w http.ResponseWriter, r * //RBAC START token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionGet) if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return @@ -228,10 +222,7 @@ func (handler ConfigMapRestHandlerImpl) CMGlobalFetchForEdit(w http.ResponseWrit } token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionGet) if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return @@ -348,10 +339,7 @@ func (handler ConfigMapRestHandlerImpl) CSGlobalAddUpdate(w http.ResponseWriter, //RBAC START token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(configMapRequest.AppId) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, object) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionCreate, object) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionCreate) if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return @@ -425,10 +413,7 @@ func (handler ConfigMapRestHandlerImpl) CSGlobalFetch(w http.ResponseWriter, r * //RBAC START token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionGet) if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), nil, http.StatusForbidden) return @@ -507,10 +492,7 @@ func (handler ConfigMapRestHandlerImpl) CMGlobalDelete(w http.ResponseWriter, r //RBAC START token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionDelete, object) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionDelete, object) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionDelete) if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), nil, http.StatusForbidden) return @@ -602,10 +584,7 @@ func (handler ConfigMapRestHandlerImpl) CSGlobalDelete(w http.ResponseWriter, r //RBAC START token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionDelete, object) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionDelete, object) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionDelete) if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), nil, http.StatusForbidden) return @@ -697,10 +676,7 @@ func (handler ConfigMapRestHandlerImpl) CSGlobalFetchForEdit(w http.ResponseWrit //RBAC START token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionUpdate, object) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionUpdate, object) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionUpdate) if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), nil, http.StatusForbidden) return diff --git a/api/restHandler/GlobalPluginRestHandler.go b/api/restHandler/GlobalPluginRestHandler.go index f5c6796009..6d4ccd8d8b 100644 --- a/api/restHandler/GlobalPluginRestHandler.go +++ b/api/restHandler/GlobalPluginRestHandler.go @@ -57,10 +57,7 @@ func (handler *GlobalPluginRestHandlerImpl) GetAllGlobalVariables(w http.Respons //on atleast one app & we can't check this without iterating through every app //TODO: update plugin as a resource in casbin and make rbac independent of appId resourceName := handler.enforcerUtil.GetAppRBACName(app.AppName) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, resourceName) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionCreate, resourceName) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, resourceName, casbin.ActionCreate) if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return @@ -93,10 +90,7 @@ func (handler *GlobalPluginRestHandlerImpl) ListAllPlugins(w http.ResponseWriter //on atleast one app & we can't check this without iterating through every app //TODO: update plugin as a resource in casbin and make rbac independent of appId resourceName := handler.enforcerUtil.GetAppRBACName(app.AppName) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, resourceName) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionCreate, resourceName) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, resourceName, casbin.ActionCreate) if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return @@ -139,10 +133,7 @@ func (handler *GlobalPluginRestHandlerImpl) GetPluginDetailById(w http.ResponseW //on atleast one app & we can't check this without iterating through every app //TODO: update plugin as a resource in casbin and make rbac independent of appId resourceName := handler.enforcerUtil.GetAppRBACName(app.AppName) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, resourceName) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionCreate, resourceName) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, resourceName, casbin.ActionCreate) if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return diff --git a/api/restHandler/app/AutoCompleteRestHandler.go b/api/restHandler/app/AutoCompleteRestHandler.go index 206517ea61..f1bfd4ee3b 100644 --- a/api/restHandler/app/AutoCompleteRestHandler.go +++ b/api/restHandler/app/AutoCompleteRestHandler.go @@ -154,10 +154,7 @@ func (handler PipelineConfigRestHandlerImpl) GitListAutocomplete(w http.Response handler.Logger.Infow("request payload, GitListAutocomplete", "appId", appId) //RBAC object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionGet) if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return diff --git a/api/restHandler/app/BuildPipelineRestHandler.go b/api/restHandler/app/BuildPipelineRestHandler.go index 886d2fe9ec..f0cce87046 100644 --- a/api/restHandler/app/BuildPipelineRestHandler.go +++ b/api/restHandler/app/BuildPipelineRestHandler.go @@ -458,10 +458,7 @@ func (handler PipelineConfigRestHandlerImpl) GetCiPipeline(w http.ResponseWriter return } resourceName := handler.enforcerUtil.GetAppRBACName(app.AppName) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, resourceName) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, resourceName) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, resourceName, casbin.ActionGet) if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return @@ -676,10 +673,7 @@ func (handler PipelineConfigRestHandlerImpl) FetchMaterials(w http.ResponseWrite //RBAC token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(ciPipeline.AppId) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionGet) if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return @@ -810,10 +804,7 @@ func (handler PipelineConfigRestHandlerImpl) GetCiPipelineMin(w http.ResponseWri handler.Logger.Infow("request payload, GetCiPipelineMin", "appId", appId) token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionGet) if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return @@ -1044,10 +1035,7 @@ func (handler *PipelineConfigRestHandlerImpl) GetBuildLogs(w http.ResponseWriter //RBAC token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(ciPipeline.AppId) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionGet) if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return @@ -1149,10 +1137,7 @@ func (handler PipelineConfigRestHandlerImpl) GetCIPipelineById(w http.ResponseWr return } resourceName := handler.enforcerUtil.GetAppRBACName(app.AppName) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, resourceName) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, resourceName) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, resourceName, casbin.ActionGet) if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return @@ -1210,16 +1195,8 @@ func (handler PipelineConfigRestHandlerImpl) CreateMaterial(w http.ResponseWrite common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } - isAuthorised := false resourceObject := handler.enforcerUtil.GetAppRBACNameByAppId(createMaterialDto.AppId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, resourceObject); ok { - isAuthorised = true - } - if !isAuthorised { - if ok := handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionCreate, resourceObject); ok { - isAuthorised = true - } - } + isAuthorised := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, resourceObject, casbin.ActionCreate) if !isAuthorised { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return @@ -1283,16 +1260,8 @@ func (handler PipelineConfigRestHandlerImpl) UpdateMaterial(w http.ResponseWrite return } } - isAuthorised := false resourceObject := handler.enforcerUtil.GetAppRBACNameByAppId(updateMaterialDto.AppId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, resourceObject); ok { - isAuthorised = true - } - if !isAuthorised { - if ok := handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionCreate, resourceObject); ok { - isAuthorised = true - } - } + isAuthorised := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, resourceObject, casbin.ActionCreate) if !isAuthorised { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return diff --git a/api/restHandler/app/PipelineConfigRestHandler.go b/api/restHandler/app/PipelineConfigRestHandler.go index 0d9d125966..45c6e4915f 100644 --- a/api/restHandler/app/PipelineConfigRestHandler.go +++ b/api/restHandler/app/PipelineConfigRestHandler.go @@ -226,10 +226,7 @@ func (handler PipelineConfigRestHandlerImpl) DeleteApp(w http.ResponseWriter, r return } resourceObject := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionDelete, resourceObject) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionDelete, resourceObject) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, resourceObject, casbin.ActionDelete) if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return @@ -352,16 +349,10 @@ func (handler PipelineConfigRestHandlerImpl) CreateApp(w http.ResponseWriter, r common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } - isAuthorised := false + // with admin roles, you have to access for all the apps of the project to create new app. (admin or manager with specific app permission can't create app.) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, fmt.Sprintf("%s/%s", strings.ToLower(project.Name), "*")); ok { - isAuthorised = true - } - if !isAuthorised { - if ok := handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionCreate, fmt.Sprintf("%s/%s", strings.ToLower(project.Name), "*")); ok { - isAuthorised = true - } - } + object := fmt.Sprintf("%s/%s", strings.ToLower(project.Name), "*") + isAuthorised := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionCreate) if !isAuthorised { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return @@ -418,10 +409,7 @@ func (handler PipelineConfigRestHandlerImpl) GetApp(w http.ResponseWriter, r *ht //rbac implementation starts here object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, object) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionGet) if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return @@ -607,10 +595,7 @@ func (handler PipelineConfigRestHandlerImpl) FetchAppWorkflowStatusForTriggerVie handler.Logger.Infow("request payload, FetchAppWorkflowStatusForTriggerView", "appId", appId) //RBAC CHECK resourceName := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, resourceName) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, resourceName) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, resourceName, casbin.ActionGet) if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return @@ -685,10 +670,7 @@ func (handler PipelineConfigRestHandlerImpl) PipelineNameSuggestion(w http.Respo } suggestedName := fmt.Sprintf("%s-%d-%s", pType, appId, util2.Generate(4)) resourceName := handler.enforcerUtil.GetAppRBACName(app.AppName) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, resourceName) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, resourceName) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, resourceName, casbin.ActionGet) if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return diff --git a/api/restHandler/scopedVariable/ScopedVariableRestHandler.go b/api/restHandler/scopedVariable/ScopedVariableRestHandler.go index 414b80f62a..4f5aad00b5 100644 --- a/api/restHandler/scopedVariable/ScopedVariableRestHandler.go +++ b/api/restHandler/scopedVariable/ScopedVariableRestHandler.go @@ -147,10 +147,7 @@ func (handler *ScopedVariableRestHandlerImpl) GetScopedVariables(w http.Response } handler.logger.Infow("request payload, GetScopedVariables", "payload", scope.AppId, scope.EnvId, scope.ClusterId) resourceName := handler.enforcerUtil.GetAppRBACName(app.AppName) - ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, resourceName) - if !ok { - ok = handler.enforcer.Enforce(token, casbin.ResourceJobs, casbin.ActionGet, resourceName) - } + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, resourceName, casbin.ActionGet) if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return diff --git a/cmd/external-app/wire_gen.go b/cmd/external-app/wire_gen.go index 3f896b0530..6fde0ae593 100644 --- a/cmd/external-app/wire_gen.go +++ b/cmd/external-app/wire_gen.go @@ -259,7 +259,7 @@ func InitializeApp() (*App, error) { return nil, err } ciPipelineRepositoryImpl := pipelineConfig.NewCiPipelineRepositoryImpl(db, sugaredLogger) - enforcerUtilImpl := rbac.NewEnforcerUtilImpl(sugaredLogger, teamRepositoryImpl, appRepositoryImpl, environmentRepositoryImpl, pipelineRepositoryImpl, ciPipelineRepositoryImpl, clusterRepositoryImpl) + enforcerUtilImpl := rbac.NewEnforcerUtilImpl(sugaredLogger, teamRepositoryImpl, appRepositoryImpl, environmentRepositoryImpl, pipelineRepositoryImpl, ciPipelineRepositoryImpl, clusterRepositoryImpl, enforcerImpl) k8sApplicationRestHandlerImpl := application2.NewK8sApplicationRestHandlerImpl(sugaredLogger, k8sApplicationServiceImpl, pumpImpl, terminalSessionHandlerImpl, enforcerImpl, enforcerUtilHelmImpl, enforcerUtilImpl, helmAppServiceImpl, userServiceImpl, k8sCommonServiceImpl, validate) k8sApplicationRouterImpl := application2.NewK8sApplicationRouterImpl(k8sApplicationRestHandlerImpl) chartRefRepositoryImpl := chartRepoRepository.NewChartRefRepositoryImpl(db) diff --git a/util/rbac/EnforcerUtil.go b/util/rbac/EnforcerUtil.go index 60600ac529..8b6dba2e78 100644 --- a/util/rbac/EnforcerUtil.go +++ b/util/rbac/EnforcerUtil.go @@ -71,6 +71,7 @@ type EnforcerUtil interface { GetTeamEnvRBACNameByCiPipelineIdAndEnvIdOrName(ciPipelineId int, envId int, envName string) string GetAllWorkflowRBACObjectsByAppId(appId int, workflowNames []string, workflowIds []int) map[int]string GetEnvRBACArrayByAppIdForJobs(appId int) []string + CheckAppRbacForAppOrJob(token, resourceName, action string) bool } type EnforcerUtilImpl struct { @@ -81,13 +82,14 @@ type EnforcerUtilImpl struct { pipelineRepository pipelineConfig.PipelineRepository ciPipelineRepository pipelineConfig.CiPipelineRepository clusterRepository repository.ClusterRepository + enforcer casbin.Enforcer *EnforcerUtilHelmImpl } func NewEnforcerUtilImpl(logger *zap.SugaredLogger, teamRepository team.TeamRepository, appRepo app.AppRepository, environmentRepository repository.EnvironmentRepository, pipelineRepository pipelineConfig.PipelineRepository, ciPipelineRepository pipelineConfig.CiPipelineRepository, - clusterRepository repository.ClusterRepository) *EnforcerUtilImpl { + clusterRepository repository.ClusterRepository, enforcer casbin.Enforcer) *EnforcerUtilImpl { return &EnforcerUtilImpl{ logger: logger, teamRepository: teamRepository, @@ -100,6 +102,7 @@ func NewEnforcerUtilImpl(logger *zap.SugaredLogger, teamRepository team.TeamRepo logger: logger, clusterRepository: clusterRepository, }, + enforcer: enforcer, } } @@ -690,3 +693,11 @@ func (impl EnforcerUtilImpl) GetEnvRBACArrayByAppIdForJobs(appId int) []string { return rbacObjects } + +func (impl EnforcerUtilImpl) CheckAppRbacForAppOrJob(token, resourceName, action string) bool { + ok := impl.enforcer.Enforce(token, casbin.ResourceApplications, action, resourceName) + if !ok { + ok = impl.enforcer.Enforce(token, casbin.ResourceJobs, action, resourceName) + } + return ok +} diff --git a/wire_gen.go b/wire_gen.go index e6089248df..bbc55a2f27 100644 --- a/wire_gen.go +++ b/wire_gen.go @@ -300,7 +300,7 @@ func InitializeApp() (*App, error) { tokenCache := util2.NewTokenCache(sugaredLogger, acdAuthConfig, userAuthServiceImpl) syncedEnforcer := casbin.Create() enforcerImpl := casbin.NewEnforcerImpl(syncedEnforcer, sessionManager, sugaredLogger) - enforcerUtilImpl := rbac.NewEnforcerUtilImpl(sugaredLogger, teamRepositoryImpl, appRepositoryImpl, environmentRepositoryImpl, pipelineRepositoryImpl, ciPipelineRepositoryImpl, clusterRepositoryImpl) + enforcerUtilImpl := rbac.NewEnforcerUtilImpl(sugaredLogger, teamRepositoryImpl, appRepositoryImpl, environmentRepositoryImpl, pipelineRepositoryImpl, ciPipelineRepositoryImpl, clusterRepositoryImpl, enforcerImpl) appListingRepositoryQueryBuilder := helper.NewAppListingRepositoryQueryBuilder(sugaredLogger) appListingRepositoryImpl := repository.NewAppListingRepositoryImpl(sugaredLogger, db, appListingRepositoryQueryBuilder, environmentRepositoryImpl) pipelineConfigRepositoryImpl := chartConfig.NewPipelineConfigRepository(db) From 6797749b76e32a0bfcca1be99100d82c8da9d2f3 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Sun, 19 Nov 2023 12:28:38 +0530 Subject: [PATCH 49/76] rbac --- api/restHandler/app/BuildPipelineRestHandler.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/restHandler/app/BuildPipelineRestHandler.go b/api/restHandler/app/BuildPipelineRestHandler.go index f0cce87046..e2ea9e3852 100644 --- a/api/restHandler/app/BuildPipelineRestHandler.go +++ b/api/restHandler/app/BuildPipelineRestHandler.go @@ -1580,7 +1580,8 @@ func (handler PipelineConfigRestHandlerImpl) FetchWorkflowDetails(w http.Respons //RBAC token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(ciPipeline.AppId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionGet) + if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } From 6b8c2dd3c8d09c4c7a6b9bfad489580b9877d5f7 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Mon, 20 Nov 2023 09:38:18 +0530 Subject: [PATCH 50/76] comments-remove --- api/restHandler/app/BuildPipelineRestHandler.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/api/restHandler/app/BuildPipelineRestHandler.go b/api/restHandler/app/BuildPipelineRestHandler.go index e2ea9e3852..c184265d9b 100644 --- a/api/restHandler/app/BuildPipelineRestHandler.go +++ b/api/restHandler/app/BuildPipelineRestHandler.go @@ -355,11 +355,6 @@ func (handler PipelineConfigRestHandlerImpl) PatchCiPipelines(w http.ResponseWri common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) return } - //isSuperAdmin, err := handler.userAuthService.IsSuperAdmin(int(userId)) - //if err != nil { - // common.WriteJsonResp(w, err, "failed to check if user is super admin", http.StatusInternalServerError) - // return - //} var patchRequest bean.CiPatchRequest err = decoder.Decode(&patchRequest) patchRequest.UserId = userId From c2fe525d9c68225ed211f2b767fa32a8dd57ea01 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Mon, 20 Nov 2023 12:25:23 +0530 Subject: [PATCH 51/76] saving role in lower --- pkg/user/UserCommonService.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/user/UserCommonService.go b/pkg/user/UserCommonService.go index a0cb495f94..da5798a7ad 100644 --- a/pkg/user/UserCommonService.go +++ b/pkg/user/UserCommonService.go @@ -115,7 +115,7 @@ func (impl UserCommonServiceImpl) getDefaultRbacRoleAndPolicyByRoleFilter(entity func getRenderedRoleData(defaultRoleData repository2.RoleCacheDetailObj, pValUpdateMap map[repository2.PValUpdateKey]string) *repository2.RoleModel { renderedRoleData := &repository2.RoleModel{ - Role: getResolvedValueFromPValDetailObject(defaultRoleData.Role, pValUpdateMap), + Role: strings.ToLower(getResolvedValueFromPValDetailObject(defaultRoleData.Role, pValUpdateMap)), Entity: getResolvedValueFromPValDetailObject(defaultRoleData.Entity, pValUpdateMap), EntityName: getResolvedValueFromPValDetailObject(defaultRoleData.EntityName, pValUpdateMap), Team: getResolvedValueFromPValDetailObject(defaultRoleData.Team, pValUpdateMap), From 304900c71628023c1c0a86dee16974ec9d75bbdf Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Mon, 20 Nov 2023 18:51:32 +0530 Subject: [PATCH 52/76] script number change --- scripts/sql/{189_jobs_rbac.down.sql => 190_jobs_rbac.down.sql} | 0 scripts/sql/{189_jobs_rbac.up.sql => 190_jobs_rbac.up.sql} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename scripts/sql/{189_jobs_rbac.down.sql => 190_jobs_rbac.down.sql} (100%) rename scripts/sql/{189_jobs_rbac.up.sql => 190_jobs_rbac.up.sql} (100%) diff --git a/scripts/sql/189_jobs_rbac.down.sql b/scripts/sql/190_jobs_rbac.down.sql similarity index 100% rename from scripts/sql/189_jobs_rbac.down.sql rename to scripts/sql/190_jobs_rbac.down.sql diff --git a/scripts/sql/189_jobs_rbac.up.sql b/scripts/sql/190_jobs_rbac.up.sql similarity index 100% rename from scripts/sql/189_jobs_rbac.up.sql rename to scripts/sql/190_jobs_rbac.up.sql From ed88602e75a7e398363121cd5d9904e24bef9000 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Tue, 21 Nov 2023 11:50:41 +0530 Subject: [PATCH 53/76] all jobs handling --- pkg/user/UserCommonService.go | 2 +- pkg/user/casbin/Adapter.go | 1 + scripts/sql/190_jobs_rbac.down.sql | 1 + scripts/sql/190_jobs_rbac.up.sql | 3 ++- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/pkg/user/UserCommonService.go b/pkg/user/UserCommonService.go index da5798a7ad..a0cb495f94 100644 --- a/pkg/user/UserCommonService.go +++ b/pkg/user/UserCommonService.go @@ -115,7 +115,7 @@ func (impl UserCommonServiceImpl) getDefaultRbacRoleAndPolicyByRoleFilter(entity func getRenderedRoleData(defaultRoleData repository2.RoleCacheDetailObj, pValUpdateMap map[repository2.PValUpdateKey]string) *repository2.RoleModel { renderedRoleData := &repository2.RoleModel{ - Role: strings.ToLower(getResolvedValueFromPValDetailObject(defaultRoleData.Role, pValUpdateMap)), + Role: getResolvedValueFromPValDetailObject(defaultRoleData.Role, pValUpdateMap), Entity: getResolvedValueFromPValDetailObject(defaultRoleData.Entity, pValUpdateMap), EntityName: getResolvedValueFromPValDetailObject(defaultRoleData.EntityName, pValUpdateMap), Team: getResolvedValueFromPValDetailObject(defaultRoleData.Team, pValUpdateMap), diff --git a/pkg/user/casbin/Adapter.go b/pkg/user/casbin/Adapter.go index 671c74b1eb..838c6a2d57 100644 --- a/pkg/user/casbin/Adapter.go +++ b/pkg/user/casbin/Adapter.go @@ -149,6 +149,7 @@ func GetAllSubjects() []string { func DeleteRoleForUser(user string, role string) bool { user = strings.ToLower(user) + role = strings.ToLower(role) response := e.DeleteRoleForUser(user, role) enforcerImplRef.InvalidateCache(user) return response diff --git a/scripts/sql/190_jobs_rbac.down.sql b/scripts/sql/190_jobs_rbac.down.sql index 95e2a8fe60..d1cef0ae3d 100644 --- a/scripts/sql/190_jobs_rbac.down.sql +++ b/scripts/sql/190_jobs_rbac.down.sql @@ -1,3 +1,4 @@ +UPDATE app SET app_name = REPLACE (app_name,'-','/') where app_type =2; ALTER TABLE roles DROP COLUMN workflow; DELETE from rbac_role_resource_detail where resource='workflow'; UPDATE rbac_policy_resource_detail set eligible_entity_access_types = ARRAY['apps/devtron-app','apps/helm-app'] where resource='project' OR resource ='global-environment' OR resource='terminal'; diff --git a/scripts/sql/190_jobs_rbac.up.sql b/scripts/sql/190_jobs_rbac.up.sql index 1cf7025677..774c5f714f 100644 --- a/scripts/sql/190_jobs_rbac.up.sql +++ b/scripts/sql/190_jobs_rbac.up.sql @@ -547,4 +547,5 @@ VALUES ('workflow', 'Workflow', 'Workflow', ARRAY ['jobs'], false, now(), 1, now Alter table roles add column IF NOT EXISTS workflow text; - +-- This is being done as casbin resource objects are being defined as TeamObj/AppObj and rbac enforcement is failing as jobName has / in it. +UPDATE app SET app_name = REPLACE (app_name,'/','-') where app_type =2; \ No newline at end of file From a8b37ad957620c4758291216cd467e56113c601e Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Tue, 21 Nov 2023 15:45:20 +0530 Subject: [PATCH 54/76] workflow by app name --- internal/sql/repository/app/AppRepository.go | 6 +++--- pkg/appWorkflow/AppWorkflowService.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/sql/repository/app/AppRepository.go b/internal/sql/repository/app/AppRepository.go index 02929b5f8c..9a49a8d0b5 100644 --- a/internal/sql/repository/app/AppRepository.go +++ b/internal/sql/repository/app/AppRepository.go @@ -76,7 +76,7 @@ type AppRepository interface { FetchAppIdsWithFilter(jobListingFilter helper.AppListingFilter) ([]int, error) FindAllActiveAppsWithTeamByAppNameMatch(appNameMatch string) ([]*App, error) FindAppAndProjectByIdsIn(ids []int) ([]*App, error) - FetchAppIdsByDisplaynames(names []string) (map[int]string, []int, error) + FetchAppIdsAndDisplayNamesByName(names []string) (map[int]string, []int, error) } const DevtronApp = "DevtronApp" @@ -446,14 +446,14 @@ func (repo AppRepositoryImpl) FindAppAndProjectByIdsIn(ids []int) ([]*App, error err := repo.dbConnection.Model(&apps).Column("app.*", "Team").Where("app.active = ?", true).Where("app.id in (?)", pg.In(ids)).Select() return apps, err } -func (repo AppRepositoryImpl) FetchAppIdsByDisplaynames(names []string) (map[int]string, []int, error) { +func (repo AppRepositoryImpl) FetchAppIdsAndDisplayNamesByName(names []string) (map[int]string, []int, error) { type App struct { Id int `json:"id"` DisplayName string `json:"display_name"` } var jobIdName []App whereCondition := " where active = true and app_type = 2 " - whereCondition += " and display_name in (" + helper.GetCommaSepratedStringWithComma(names) + ");" + whereCondition += " and app_name in (" + helper.GetCommaSepratedStringWithComma(names) + ");" query := "select id, display_name from app " + whereCondition _, err := repo.dbConnection.Query(&jobIdName, query) appResp := make(map[int]string) diff --git a/pkg/appWorkflow/AppWorkflowService.go b/pkg/appWorkflow/AppWorkflowService.go index bee9a05c8b..64b6b3539f 100644 --- a/pkg/appWorkflow/AppWorkflowService.go +++ b/pkg/appWorkflow/AppWorkflowService.go @@ -690,7 +690,7 @@ func (impl AppWorkflowServiceImpl) FindAllWorkflowsForApps(request WorkflowNames if len(request.AppNames) == 0 { return &WorkflowNamesResponse{}, nil } - appIdNameMapping, appIds, err := impl.appRepository.FetchAppIdsByDisplaynames(request.AppNames) + appIdNameMapping, appIds, err := impl.appRepository.FetchAppIdsAndDisplayNamesByName(request.AppNames) if err != nil { impl.Logger.Errorw("error in getting apps by appNames", "err", err, "appNames", request.AppNames) return nil, err From ce293f80a7306cc23504fa7eddf0a4435a9c05ea Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Tue, 21 Nov 2023 17:21:19 +0530 Subject: [PATCH 55/76] Revert "workflow by app name" This reverts commit a8b37ad957620c4758291216cd467e56113c601e. --- internal/sql/repository/app/AppRepository.go | 6 +++--- pkg/appWorkflow/AppWorkflowService.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/sql/repository/app/AppRepository.go b/internal/sql/repository/app/AppRepository.go index 9a49a8d0b5..02929b5f8c 100644 --- a/internal/sql/repository/app/AppRepository.go +++ b/internal/sql/repository/app/AppRepository.go @@ -76,7 +76,7 @@ type AppRepository interface { FetchAppIdsWithFilter(jobListingFilter helper.AppListingFilter) ([]int, error) FindAllActiveAppsWithTeamByAppNameMatch(appNameMatch string) ([]*App, error) FindAppAndProjectByIdsIn(ids []int) ([]*App, error) - FetchAppIdsAndDisplayNamesByName(names []string) (map[int]string, []int, error) + FetchAppIdsByDisplaynames(names []string) (map[int]string, []int, error) } const DevtronApp = "DevtronApp" @@ -446,14 +446,14 @@ func (repo AppRepositoryImpl) FindAppAndProjectByIdsIn(ids []int) ([]*App, error err := repo.dbConnection.Model(&apps).Column("app.*", "Team").Where("app.active = ?", true).Where("app.id in (?)", pg.In(ids)).Select() return apps, err } -func (repo AppRepositoryImpl) FetchAppIdsAndDisplayNamesByName(names []string) (map[int]string, []int, error) { +func (repo AppRepositoryImpl) FetchAppIdsByDisplaynames(names []string) (map[int]string, []int, error) { type App struct { Id int `json:"id"` DisplayName string `json:"display_name"` } var jobIdName []App whereCondition := " where active = true and app_type = 2 " - whereCondition += " and app_name in (" + helper.GetCommaSepratedStringWithComma(names) + ");" + whereCondition += " and display_name in (" + helper.GetCommaSepratedStringWithComma(names) + ");" query := "select id, display_name from app " + whereCondition _, err := repo.dbConnection.Query(&jobIdName, query) appResp := make(map[int]string) diff --git a/pkg/appWorkflow/AppWorkflowService.go b/pkg/appWorkflow/AppWorkflowService.go index 64b6b3539f..bee9a05c8b 100644 --- a/pkg/appWorkflow/AppWorkflowService.go +++ b/pkg/appWorkflow/AppWorkflowService.go @@ -690,7 +690,7 @@ func (impl AppWorkflowServiceImpl) FindAllWorkflowsForApps(request WorkflowNames if len(request.AppNames) == 0 { return &WorkflowNamesResponse{}, nil } - appIdNameMapping, appIds, err := impl.appRepository.FetchAppIdsAndDisplayNamesByName(request.AppNames) + appIdNameMapping, appIds, err := impl.appRepository.FetchAppIdsByDisplaynames(request.AppNames) if err != nil { impl.Logger.Errorw("error in getting apps by appNames", "err", err, "appNames", request.AppNames) return nil, err From 2ec2881eb5a9cacf481be78b0d872ae3c619072e Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Wed, 22 Nov 2023 15:46:34 +0530 Subject: [PATCH 56/76] job create --- pkg/pipeline/CiCdPipelineOrchestrator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/pipeline/CiCdPipelineOrchestrator.go b/pkg/pipeline/CiCdPipelineOrchestrator.go index 32f4d8fcd4..fe8caf38d2 100644 --- a/pkg/pipeline/CiCdPipelineOrchestrator.go +++ b/pkg/pipeline/CiCdPipelineOrchestrator.go @@ -1308,7 +1308,7 @@ func (impl CiCdPipelineOrchestratorImpl) createAppGroup(name, description string displayName := name appName := name if appType == helper.Job { - appName = name + "/" + util2.Generate(8) + "J" + appName = name + "-" + util2.Generate(8) + "J" } pg := &app2.App{ Active: true, From c66557dc9bea06bdc0b88c52490772e60bc4be68 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Wed, 22 Nov 2023 16:26:28 +0530 Subject: [PATCH 57/76] rbac --- api/restHandler/AppWorkflowRestHandler.go | 3 +- api/restHandler/ConfigMapRestHandler.go | 49 ++++++++++++++++------- util/rbac/EnforcerUtil.go | 7 +++- 3 files changed, 42 insertions(+), 17 deletions(-) diff --git a/api/restHandler/AppWorkflowRestHandler.go b/api/restHandler/AppWorkflowRestHandler.go index 8295ec20bd..cb8ec24c88 100644 --- a/api/restHandler/AppWorkflowRestHandler.go +++ b/api/restHandler/AppWorkflowRestHandler.go @@ -97,7 +97,8 @@ func (handler AppWorkflowRestHandlerImpl) CreateAppWorkflow(w http.ResponseWrite token := r.Header.Get("token") //rbac block starts from here resourceName := handler.enforcerUtil.GetAppRBACNameByAppId(request.AppId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, resourceName); !ok { + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, resourceName, casbin.ActionCreate) + if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } diff --git a/api/restHandler/ConfigMapRestHandler.go b/api/restHandler/ConfigMapRestHandler.go index dd1848e143..3fef49aa04 100644 --- a/api/restHandler/ConfigMapRestHandler.go +++ b/api/restHandler/ConfigMapRestHandler.go @@ -265,7 +265,8 @@ func (handler ConfigMapRestHandlerImpl) CMEnvironmentFetchForEdit(w http.Respons } token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionGet) + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } @@ -303,7 +304,8 @@ func (handler ConfigMapRestHandlerImpl) CMEnvironmentFetch(w http.ResponseWriter //RBAC START token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionGet) + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } @@ -376,14 +378,18 @@ func (handler ConfigMapRestHandlerImpl) CSEnvironmentAddUpdate(w http.ResponseWr //RBAC START token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(configMapRequest.AppId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, object); !ok { + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionCreate) + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } object = handler.enforcerUtil.GetEnvRBACNameByAppId(configMapRequest.AppId, configMapRequest.EnvironmentId) + object2 := handler.enforcerUtil.GetTeamEnvAppRbacObjectByAppIdEnvIdOrName(configMapRequest.AppId, configMapRequest.EnvironmentId, "") if ok := handler.enforcer.Enforce(token, casbin.ResourceEnvironment, casbin.ActionCreate, object); !ok { - common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) - return + if ok2 := handler.enforcer.Enforce(token, casbin.ResourceJobsEnv, casbin.ActionCreate, object2); !ok2 { + common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) + return + } } //RBAC END @@ -452,7 +458,8 @@ func (handler ConfigMapRestHandlerImpl) CSEnvironmentFetch(w http.ResponseWriter //RBAC START token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionGet) + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), nil, http.StatusForbidden) return } @@ -539,14 +546,18 @@ func (handler ConfigMapRestHandlerImpl) CMEnvironmentDelete(w http.ResponseWrite //RBAC START token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionDelete, object); !ok { + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionDelete) + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), nil, http.StatusForbidden) return } object = handler.enforcerUtil.GetEnvRBACNameByAppId(appId, envId) + object2 := handler.enforcerUtil.GetTeamEnvAppRbacObjectByAppIdEnvIdOrName(appId, envId, "") if ok := handler.enforcer.Enforce(token, casbin.ResourceEnvironment, casbin.ActionDelete, object); !ok { - common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), nil, http.StatusForbidden) - return + if ok2 := handler.enforcer.Enforce(token, casbin.ResourceJobsEnv, casbin.ActionDelete, object2); !ok2 { + common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), nil, http.StatusForbidden) + return + } } //RBAC END @@ -631,14 +642,18 @@ func (handler ConfigMapRestHandlerImpl) CSEnvironmentDelete(w http.ResponseWrite //RBAC START token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionDelete, object); !ok { + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionDelete) + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), nil, http.StatusForbidden) return } object = handler.enforcerUtil.GetEnvRBACNameByAppId(appId, envId) + object2 := handler.enforcerUtil.GetTeamEnvAppRbacObjectByAppIdEnvIdOrName(appId, envId, "") if ok := handler.enforcer.Enforce(token, casbin.ResourceEnvironment, casbin.ActionDelete, object); !ok { - common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), nil, http.StatusForbidden) - return + if ok2 := handler.enforcer.Enforce(token, casbin.ResourceJobsEnv, casbin.ActionDelete, object2); !ok2 { + common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), nil, http.StatusForbidden) + return + } } //RBAC END @@ -723,14 +738,18 @@ func (handler ConfigMapRestHandlerImpl) CSEnvironmentFetchForEdit(w http.Respons //RBAC START token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(appId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionUpdate, object); !ok { + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionUpdate) + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), nil, http.StatusForbidden) return } object = handler.enforcerUtil.GetEnvRBACNameByAppId(appId, envId) + object2 := handler.enforcerUtil.GetTeamEnvAppRbacObjectByAppIdEnvIdOrName(appId, envId, "") if ok := handler.enforcer.Enforce(token, casbin.ResourceEnvironment, casbin.ActionUpdate, object); !ok { - common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), nil, http.StatusForbidden) - return + if ok2 := handler.enforcer.Enforce(token, casbin.ResourceJobsEnv, casbin.ActionUpdate, object2); !ok2 { + common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), nil, http.StatusForbidden) + return + } } //RBAC END diff --git a/util/rbac/EnforcerUtil.go b/util/rbac/EnforcerUtil.go index 8b6dba2e78..147e2bfc45 100644 --- a/util/rbac/EnforcerUtil.go +++ b/util/rbac/EnforcerUtil.go @@ -69,6 +69,7 @@ type EnforcerUtil interface { GetRbacObjectNameByAppIdAndWorkflow(appId int, workflowName string) string GetWorkflowRBACByCiPipelineId(pipelineId int, workflowName string) string GetTeamEnvRBACNameByCiPipelineIdAndEnvIdOrName(ciPipelineId int, envId int, envName string) string + GetTeamEnvAppRbacObjectByAppIdEnvIdOrName(appId, envId int, envName string) string GetAllWorkflowRBACObjectsByAppId(appId int, workflowNames []string, workflowIds []int) map[int]string GetEnvRBACArrayByAppIdForJobs(appId int) []string CheckAppRbacForAppOrJob(token, resourceName, action string) bool @@ -650,7 +651,11 @@ func (impl EnforcerUtilImpl) GetTeamEnvRBACNameByCiPipelineIdAndEnvIdOrName(ciPi if err != nil { return fmt.Sprintf("%s/%s/%s", "", "", "") } - application, err := impl.appRepo.FindAppAndProjectByAppId(ciPipeline.AppId) + return impl.GetTeamEnvAppRbacObjectByAppIdEnvIdOrName(ciPipeline.AppId, envId, envName) + +} +func (impl EnforcerUtilImpl) GetTeamEnvAppRbacObjectByAppIdEnvIdOrName(appId, envId int, envName string) string { + application, err := impl.appRepo.FindAppAndProjectByAppId(appId) if err != nil { return fmt.Sprintf("%s/%s/%s", "", "", "") } From 14f32b21458b4169517d9d5379c2c21fc286064a Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Wed, 22 Nov 2023 18:28:21 +0530 Subject: [PATCH 58/76] cm-checks --- api/restHandler/ConfigMapRestHandler.go | 33 ++++++++++++++----------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/api/restHandler/ConfigMapRestHandler.go b/api/restHandler/ConfigMapRestHandler.go index 3fef49aa04..817d99bd19 100644 --- a/api/restHandler/ConfigMapRestHandler.go +++ b/api/restHandler/ConfigMapRestHandler.go @@ -148,14 +148,18 @@ func (handler ConfigMapRestHandlerImpl) CMEnvironmentAddUpdate(w http.ResponseWr //RBAC START token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(configMapRequest.AppId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionCreate, object); !ok { + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionCreate) + if !ok { common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } object = handler.enforcerUtil.GetEnvRBACNameByAppId(configMapRequest.AppId, configMapRequest.EnvironmentId) + object2 := handler.enforcerUtil.GetTeamEnvRBACNameByAppId(configMapRequest.AppId, configMapRequest.EnvironmentId) if ok := handler.enforcer.Enforce(token, casbin.ResourceEnvironment, casbin.ActionCreate, object); !ok { - common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) - return + if ok2 := handler.enforcer.Enforce(token, casbin.ResourceJobsEnv, casbin.ActionCreate, object2); !ok2 { + common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) + return + } } //RBAC END @@ -826,7 +830,7 @@ func (handler ConfigMapRestHandlerImpl) AddEnvironmentToJob(w http.ResponseWrite // RBAC ENFORCEMENT resourceObject := handler.enforcerUtil.GetTeamEnvRBACNameByAppId(envOverrideRequest.AppId, envOverrideRequest.EnvId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceJobsEnv, casbin.ActionGet, resourceObject); !ok { + if ok := handler.enforcer.Enforce(token, casbin.ResourceJobsEnv, casbin.ActionCreate, resourceObject); !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } @@ -852,17 +856,7 @@ func (handler ConfigMapRestHandlerImpl) RemoveEnvironmentFromJob(w http.Response return } - //AUTH - check from casbin db - isSuperAdmin, err := handler.userAuthService.IsSuperAdmin(int(userId)) - if !isSuperAdmin || err != nil { - if err != nil { - handler.Logger.Errorw("request err, CheckSuperAdmin", "err", isSuperAdmin, "isSuperAdmin", isSuperAdmin) - } - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) - return - } - //AUTH - + token := r.Header.Get("token") var envOverrideRequest bean.CreateJobEnvOverridePayload err = decoder.Decode(&envOverrideRequest) if err != nil { @@ -870,6 +864,15 @@ func (handler ConfigMapRestHandlerImpl) RemoveEnvironmentFromJob(w http.Response common.WriteJsonResp(w, err, nil, http.StatusBadRequest) return } + + // RBAC ENFORCEMENT + resourceObject := handler.enforcerUtil.GetTeamEnvRBACNameByAppId(envOverrideRequest.AppId, envOverrideRequest.EnvId) + if ok := handler.enforcer.Enforce(token, casbin.ResourceJobsEnv, casbin.ActionDelete, resourceObject); !ok { + common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) + return + } + // RBAC ENFORCEMENT ENDS + envOverrideRequest.UserId = userId handler.Logger.Infow("request payload, RemoveEnvironmentFromJob", "payload", envOverrideRequest) resp, err := handler.configMapService.ConfigSecretEnvironmentDelete(&envOverrideRequest) From e388bbf41a054bea507af27e4760d06f7de3b3ee Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Wed, 22 Nov 2023 18:43:08 +0530 Subject: [PATCH 59/76] removing logs --- pkg/user/RoleGroupService.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pkg/user/RoleGroupService.go b/pkg/user/RoleGroupService.go index 3237e06a85..c7637784c6 100644 --- a/pkg/user/RoleGroupService.go +++ b/pkg/user/RoleGroupService.go @@ -401,10 +401,10 @@ func (impl RoleGroupServiceImpl) UpdateRoleGroup(request *bean.RoleGroup, token return nil, err } eliminatedPolicies = append(eliminatedPolicies, items...) - impl.logger.Infow("eliminated policies", "eliminatedPolicies", eliminatedPolicies) + impl.logger.Debugw("eliminated policies", "eliminatedPolicies", eliminatedPolicies) if len(eliminatedPolicies) > 0 { pRes := casbin2.RemovePolicy(eliminatedPolicies) - impl.logger.Infow("pRes : failed policies 1", "pRes", &pRes) + impl.logger.Debugw("pRes : failed policies 1", "pRes", &pRes) println(pRes) } // DELETE PROCESS ENDS @@ -449,11 +449,10 @@ func (impl RoleGroupServiceImpl) UpdateRoleGroup(request *bean.RoleGroup, token } } } - impl.logger.Infow("policies", "policies", policies) //updating in casbin if len(policies) > 0 { pRes := casbin2.AddPolicy(policies) - impl.logger.Infow("pres failed policies on add policy", "pres", &pRes) + impl.logger.Debugw("pres failed policies on add policy", "pres", &pRes) println(pRes) } //loading policy for syncing orchestrator to casbin with newly added policies From d92d2929f99591e6ee50703ec6f5d9e4cc113a51 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Thu, 23 Nov 2023 07:49:01 +0530 Subject: [PATCH 60/76] cm-edit rbac --- api/restHandler/ConfigMapRestHandler.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/api/restHandler/ConfigMapRestHandler.go b/api/restHandler/ConfigMapRestHandler.go index 817d99bd19..dfb272e13f 100644 --- a/api/restHandler/ConfigMapRestHandler.go +++ b/api/restHandler/ConfigMapRestHandler.go @@ -274,6 +274,11 @@ func (handler ConfigMapRestHandlerImpl) CMEnvironmentFetchForEdit(w http.Respons common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) return } + object = handler.enforcerUtil.GetTeamEnvRBACNameByAppId(appId, envId) + if ok = handler.enforcer.Enforce(token, casbin.ResourceJobsEnv, casbin.ActionGet, object); !ok { + common.WriteJsonResp(w, fmt.Errorf("unauthorized user"), "Unauthorized User", http.StatusForbidden) + return + } name := vars["name"] response, err := handler.configMapService.CMEnvironmentFetchForEdit(name, cmId, appId, envId) From 8cf927397fa34a5ab1c86ed55cd7b505f90fbd1d Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Thu, 23 Nov 2023 13:07:07 +0530 Subject: [PATCH 61/76] empty handling --- api/restHandler/AppWorkflowRestHandler.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/restHandler/AppWorkflowRestHandler.go b/api/restHandler/AppWorkflowRestHandler.go index cb8ec24c88..169b354fce 100644 --- a/api/restHandler/AppWorkflowRestHandler.go +++ b/api/restHandler/AppWorkflowRestHandler.go @@ -268,7 +268,9 @@ func (impl AppWorkflowRestHandlerImpl) FindAppWorkflow(w http.ResponseWriter, r updatedWorkflowList = append(updatedWorkflowList, workNameObjectMap[obj]) } } - + if len(updatedWorkflowList) == 0 { + updatedWorkflowList = []appWorkflow.AppWorkflowDto{} + } workflows[bean2.Workflows] = updatedWorkflowList } else if len(workflowsList) > 0 { workflows[bean2.Workflows] = workflowsList From 3292ef0ee5a1c69a0f42ca68a931cf942a8b7378 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Thu, 23 Nov 2023 15:49:31 +0530 Subject: [PATCH 62/76] script --- scripts/sql/{192_jobs_rbac.down.sql => 193_jobs_rbac.down.sql} | 0 scripts/sql/{192_jobs_rbac.up.sql => 193_jobs_rbac.up.sql} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename scripts/sql/{192_jobs_rbac.down.sql => 193_jobs_rbac.down.sql} (100%) rename scripts/sql/{192_jobs_rbac.up.sql => 193_jobs_rbac.up.sql} (100%) diff --git a/scripts/sql/192_jobs_rbac.down.sql b/scripts/sql/193_jobs_rbac.down.sql similarity index 100% rename from scripts/sql/192_jobs_rbac.down.sql rename to scripts/sql/193_jobs_rbac.down.sql diff --git a/scripts/sql/192_jobs_rbac.up.sql b/scripts/sql/193_jobs_rbac.up.sql similarity index 100% rename from scripts/sql/192_jobs_rbac.up.sql rename to scripts/sql/193_jobs_rbac.up.sql From dd8ed2547bccac24efd4c24de986e61f9a6c922e Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 24 Nov 2023 08:23:03 +0530 Subject: [PATCH 63/76] comments --- pkg/user/casbin/rbacpolicy.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/user/casbin/rbacpolicy.go b/pkg/user/casbin/rbacpolicy.go index 4605dab4b5..151894b28f 100644 --- a/pkg/user/casbin/rbacpolicy.go +++ b/pkg/user/casbin/rbacpolicy.go @@ -37,6 +37,7 @@ const ( ResourceAutocomplete = "autocomplete" ResourceChartGroup = "chart-group" + // ResourceJobs ,ResourceJobsEnv ,ResourceWorkflow these three resources are being used in jobs for rbac. ResourceJobs = "jobs" ResourceJobsEnv = "jobenv" ResourceWorkflow = "workflow" From ec4b42c29ee14b172001d77e9880725a97e0597e Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 24 Nov 2023 12:55:04 +0530 Subject: [PATCH 64/76] error code --- api/restHandler/AppWorkflowRestHandler.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/api/restHandler/AppWorkflowRestHandler.go b/api/restHandler/AppWorkflowRestHandler.go index 169b354fce..2ba352a1c2 100644 --- a/api/restHandler/AppWorkflowRestHandler.go +++ b/api/restHandler/AppWorkflowRestHandler.go @@ -19,6 +19,7 @@ package restHandler import ( "encoding/json" + "errors" bean2 "github.com/devtron-labs/devtron/api/restHandler/bean" "github.com/devtron-labs/devtron/api/restHandler/common" "github.com/devtron-labs/devtron/internal/sql/repository/app" @@ -107,6 +108,10 @@ func (handler AppWorkflowRestHandlerImpl) CreateAppWorkflow(w http.ResponseWrite res, err := handler.appWorkflowService.CreateAppWorkflow(request) if err != nil { + if errors.Is(err, errors.New("workflow with this name already exist in this app")) { + common.WriteJsonResp(w, err, []byte("Creation Failed"), http.StatusBadRequest) + return + } handler.Logger.Errorw("error on creating", "err", err) common.WriteJsonResp(w, err, []byte("Creation Failed"), http.StatusInternalServerError) return From 6377d3f3d087190b7b488f22d99165ac2afec890 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 24 Nov 2023 13:20:57 +0530 Subject: [PATCH 65/76] validations and handling --- api/restHandler/app/PipelineConfigRestHandler.go | 7 +++++++ pkg/pipeline/CiCdPipelineOrchestrator.go | 2 +- pkg/pipeline/bean/CiBuildConfig.go | 1 + scripts/sql/193_jobs_rbac.down.sql | 3 ++- scripts/sql/193_jobs_rbac.up.sql | 4 +++- 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/api/restHandler/app/PipelineConfigRestHandler.go b/api/restHandler/app/PipelineConfigRestHandler.go index 35b8029dce..d9459d064a 100644 --- a/api/restHandler/app/PipelineConfigRestHandler.go +++ b/api/restHandler/app/PipelineConfigRestHandler.go @@ -27,6 +27,7 @@ import ( "github.com/devtron-labs/devtron/client/gitSensor" "github.com/devtron-labs/devtron/pkg/chart" "github.com/devtron-labs/devtron/pkg/generateManifest" + bean3 "github.com/devtron-labs/devtron/pkg/pipeline/bean" resourceGroup2 "github.com/devtron-labs/devtron/pkg/resourceGroup" "github.com/devtron-labs/devtron/pkg/user/casbin" "github.com/devtron-labs/devtron/util/argo" @@ -360,6 +361,12 @@ func (handler PipelineConfigRestHandlerImpl) CreateApp(w http.ResponseWriter, r common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } + // Validation For appName + if ok := strings.Contains(createRequest.AppName, bean3.UniquePlaceHolderForAppName); ok { + common.WriteJsonResp(w, err, "app creation failed due to validation on app-name as it contains not allowed place-holder in name", http.StatusBadRequest) + return + } + var createResp *bean.CreateAppDTO err = nil if createRequest.TemplateId == 0 { diff --git a/pkg/pipeline/CiCdPipelineOrchestrator.go b/pkg/pipeline/CiCdPipelineOrchestrator.go index 8d7e2ee614..6055f7f5b3 100644 --- a/pkg/pipeline/CiCdPipelineOrchestrator.go +++ b/pkg/pipeline/CiCdPipelineOrchestrator.go @@ -1316,7 +1316,7 @@ func (impl CiCdPipelineOrchestratorImpl) createAppGroup(name, description string displayName := name appName := name if appType == helper.Job { - appName = name + "-" + util2.Generate(8) + "J" + appName = name + "-" + util2.Generate(8) + "J" + bean2.UniquePlaceHolderForAppName } pg := &app2.App{ Active: true, diff --git a/pkg/pipeline/bean/CiBuildConfig.go b/pkg/pipeline/bean/CiBuildConfig.go index f89d927a7a..4d169f8408 100644 --- a/pkg/pipeline/bean/CiBuildConfig.go +++ b/pkg/pipeline/bean/CiBuildConfig.go @@ -16,6 +16,7 @@ const ( BUILDPACK_BUILD_TYPE CiBuildType = "buildpack-build" ) const Main = "main" +const UniquePlaceHolderForAppName = "$etron" type CiBuildConfigBean struct { Id int `json:"id"` diff --git a/scripts/sql/193_jobs_rbac.down.sql b/scripts/sql/193_jobs_rbac.down.sql index d1cef0ae3d..c755c03564 100644 --- a/scripts/sql/193_jobs_rbac.down.sql +++ b/scripts/sql/193_jobs_rbac.down.sql @@ -1,4 +1,5 @@ -UPDATE app SET app_name = REPLACE (app_name,'-','/') where app_type =2; +UPDATE app SET app_name = REPLACE (app_name,'$etron','') where app_type =2; +-- UPDATE app SET app_name = REPLACE (app_name,'-','/') where app_type =2; not doing this because app_name can have different (-) //Kept for reference ALTER TABLE roles DROP COLUMN workflow; DELETE from rbac_role_resource_detail where resource='workflow'; UPDATE rbac_policy_resource_detail set eligible_entity_access_types = ARRAY['apps/devtron-app','apps/helm-app'] where resource='project' OR resource ='global-environment' OR resource='terminal'; diff --git a/scripts/sql/193_jobs_rbac.up.sql b/scripts/sql/193_jobs_rbac.up.sql index 774c5f714f..bfc57976d8 100644 --- a/scripts/sql/193_jobs_rbac.up.sql +++ b/scripts/sql/193_jobs_rbac.up.sql @@ -548,4 +548,6 @@ VALUES ('workflow', 'Workflow', 'Workflow', ARRAY ['jobs'], false, now(), 1, now Alter table roles add column IF NOT EXISTS workflow text; -- This is being done as casbin resource objects are being defined as TeamObj/AppObj and rbac enforcement is failing as jobName has / in it. -UPDATE app SET app_name = REPLACE (app_name,'/','-') where app_type =2; \ No newline at end of file +UPDATE app SET app_name = REPLACE (app_name,'/','-') where app_type =2; +-- This is being done to unique identifying app and job and other enities in future to avoid conflicts in rbac enforcement +UPDATE app SET app_name = CONCAT (app_name,'$etron') where app_type =2; \ No newline at end of file From 7a7770f755250a0d4c71369bba6203ab8a671f4c Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 24 Nov 2023 13:51:37 +0530 Subject: [PATCH 66/76] cancel workflow --- api/restHandler/app/BuildPipelineRestHandler.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/restHandler/app/BuildPipelineRestHandler.go b/api/restHandler/app/BuildPipelineRestHandler.go index aa1b7014e8..4de714061c 100644 --- a/api/restHandler/app/BuildPipelineRestHandler.go +++ b/api/restHandler/app/BuildPipelineRestHandler.go @@ -1399,7 +1399,8 @@ func (handler PipelineConfigRestHandlerImpl) CancelWorkflow(w http.ResponseWrite //RBAC token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(ciPipeline.AppId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionTrigger, object); !ok { + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionTrigger) + if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } From 4341c2f6b3ee8ccb934811136d412777e762a54a Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 24 Nov 2023 15:31:31 +0530 Subject: [PATCH 67/76] error checks --- api/restHandler/AppWorkflowRestHandler.go | 4 ++-- pkg/app/bean/ManifestPushTemplate.go | 2 ++ pkg/appWorkflow/AppWorkflowService.go | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/api/restHandler/AppWorkflowRestHandler.go b/api/restHandler/AppWorkflowRestHandler.go index 2ba352a1c2..af6c1cdeea 100644 --- a/api/restHandler/AppWorkflowRestHandler.go +++ b/api/restHandler/AppWorkflowRestHandler.go @@ -19,13 +19,13 @@ package restHandler import ( "encoding/json" - "errors" bean2 "github.com/devtron-labs/devtron/api/restHandler/bean" "github.com/devtron-labs/devtron/api/restHandler/common" "github.com/devtron-labs/devtron/internal/sql/repository/app" appWorkflow2 "github.com/devtron-labs/devtron/internal/sql/repository/appWorkflow" "github.com/devtron-labs/devtron/internal/sql/repository/helper" "github.com/devtron-labs/devtron/internal/util" + bean3 "github.com/devtron-labs/devtron/pkg/app/bean" "github.com/devtron-labs/devtron/pkg/appWorkflow" "github.com/devtron-labs/devtron/pkg/bean" "github.com/devtron-labs/devtron/pkg/pipeline" @@ -108,7 +108,7 @@ func (handler AppWorkflowRestHandlerImpl) CreateAppWorkflow(w http.ResponseWrite res, err := handler.appWorkflowService.CreateAppWorkflow(request) if err != nil { - if errors.Is(err, errors.New("workflow with this name already exist in this app")) { + if err.Error() == bean3.WORKFLOW_EXIST_ERROR { common.WriteJsonResp(w, err, []byte("Creation Failed"), http.StatusBadRequest) return } diff --git a/pkg/app/bean/ManifestPushTemplate.go b/pkg/app/bean/ManifestPushTemplate.go index d063f60709..1dea6e212b 100644 --- a/pkg/app/bean/ManifestPushTemplate.go +++ b/pkg/app/bean/ManifestPushTemplate.go @@ -2,6 +2,8 @@ package bean import "time" +const WORKFLOW_EXIST_ERROR = "workflow with this name already exist in this app" + type ManifestPushTemplate struct { WorkflowRunnerId int AppId int diff --git a/pkg/appWorkflow/AppWorkflowService.go b/pkg/appWorkflow/AppWorkflowService.go index bee9a05c8b..b1884fb759 100644 --- a/pkg/appWorkflow/AppWorkflowService.go +++ b/pkg/appWorkflow/AppWorkflowService.go @@ -25,6 +25,7 @@ import ( "github.com/devtron-labs/devtron/internal/sql/repository/appWorkflow" "github.com/devtron-labs/devtron/internal/sql/repository/pipelineConfig" "github.com/devtron-labs/devtron/internal/util" + bean2 "github.com/devtron-labs/devtron/pkg/app/bean" "github.com/devtron-labs/devtron/pkg/bean" "github.com/devtron-labs/devtron/pkg/pipeline" resourceGroup2 "github.com/devtron-labs/devtron/pkg/resourceGroup" @@ -192,7 +193,7 @@ func (impl AppWorkflowServiceImpl) CreateAppWorkflow(req AppWorkflowDto) (AppWor } if workflow.Id != 0 { impl.Logger.Errorw("workflow with this name already exist", "err", err) - return req, errors.New("workflow with this name already exist in this app") + return req, errors.New(bean2.WORKFLOW_EXIST_ERROR) } wf := &appWorkflow.AppWorkflow{ Name: req.Name, From 70dab164fa903d137bb7353751cd955099ca2210 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 24 Nov 2023 15:52:22 +0530 Subject: [PATCH 68/76] rbac --- api/restHandler/AppWorkflowRestHandler.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/restHandler/AppWorkflowRestHandler.go b/api/restHandler/AppWorkflowRestHandler.go index af6c1cdeea..82c27477d6 100644 --- a/api/restHandler/AppWorkflowRestHandler.go +++ b/api/restHandler/AppWorkflowRestHandler.go @@ -451,7 +451,8 @@ func (handler *AppWorkflowRestHandlerImpl) GetWorkflowsViewData(w http.ResponseW // RBAC enforcer applying object := handler.enforcerUtil.GetAppRBACName(app.AppName) handler.Logger.Debugw("rbac object for workflows view data", "object", object) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionGet) + if !ok { common.WriteJsonResp(w, err, "unauthorized user", http.StatusForbidden) return } From 0ef23e241e40e6e832066f61982d2d8b9e371376 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 24 Nov 2023 15:56:04 +0530 Subject: [PATCH 69/76] script number chnage --- scripts/sql/{193_jobs_rbac.down.sql => 194_jobs_rbac.down.sql} | 0 scripts/sql/{193_jobs_rbac.up.sql => 194_jobs_rbac.up.sql} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename scripts/sql/{193_jobs_rbac.down.sql => 194_jobs_rbac.down.sql} (100%) rename scripts/sql/{193_jobs_rbac.up.sql => 194_jobs_rbac.up.sql} (100%) diff --git a/scripts/sql/193_jobs_rbac.down.sql b/scripts/sql/194_jobs_rbac.down.sql similarity index 100% rename from scripts/sql/193_jobs_rbac.down.sql rename to scripts/sql/194_jobs_rbac.down.sql diff --git a/scripts/sql/193_jobs_rbac.up.sql b/scripts/sql/194_jobs_rbac.up.sql similarity index 100% rename from scripts/sql/193_jobs_rbac.up.sql rename to scripts/sql/194_jobs_rbac.up.sql From 7a14d950a7b83a28cf1cc1ca74765b423f77b19a Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Fri, 24 Nov 2023 16:22:58 +0530 Subject: [PATCH 70/76] workflow error --- api/restHandler/AppWorkflowRestHandler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/restHandler/AppWorkflowRestHandler.go b/api/restHandler/AppWorkflowRestHandler.go index 82c27477d6..ee2e49bc3c 100644 --- a/api/restHandler/AppWorkflowRestHandler.go +++ b/api/restHandler/AppWorkflowRestHandler.go @@ -109,7 +109,7 @@ func (handler AppWorkflowRestHandlerImpl) CreateAppWorkflow(w http.ResponseWrite res, err := handler.appWorkflowService.CreateAppWorkflow(request) if err != nil { if err.Error() == bean3.WORKFLOW_EXIST_ERROR { - common.WriteJsonResp(w, err, []byte("Creation Failed"), http.StatusBadRequest) + common.WriteJsonResp(w, err, bean3.WORKFLOW_EXIST_ERROR, http.StatusBadRequest) return } handler.Logger.Errorw("error on creating", "err", err) From 851b258da659d28932a02935f30430ddfa7ccddd Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Wed, 29 Nov 2023 13:34:58 +0530 Subject: [PATCH 71/76] review comments --- api/restHandler/AppWorkflowRestHandler.go | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/api/restHandler/AppWorkflowRestHandler.go b/api/restHandler/AppWorkflowRestHandler.go index ee2e49bc3c..0fcd7f0ff4 100644 --- a/api/restHandler/AppWorkflowRestHandler.go +++ b/api/restHandler/AppWorkflowRestHandler.go @@ -323,13 +323,9 @@ func (impl AppWorkflowRestHandlerImpl) FindAllWorkflowsForApps(w http.ResponseWr common.WriteJsonResp(w, err, "Unauthorized User", http.StatusUnauthorized) return } - // RBAC enforcer applying - isSuperAdmin, err := impl.userAuthService.IsSuperAdmin(int(userId)) - if !isSuperAdmin || err != nil { - if err != nil { - impl.Logger.Errorw("request err, CheckSuperAdmin", "err", isSuperAdmin, "isSuperAdmin", isSuperAdmin) - } - common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) + token := r.Header.Get("token") + if ok := impl.enforcer.Enforce(token, casbin.ResourceGlobal, casbin.ActionGet, "*"); !ok { + common.WriteJsonResp(w, err, "Unauthorized user", http.StatusForbidden) return } //RBAC enforcer Ends From 5ddae6cd1f0d1413b5b9a43b1fc1f7ec29a7a441 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Thu, 30 Nov 2023 12:32:23 +0530 Subject: [PATCH 72/76] refresh rbac --- api/restHandler/app/BuildPipelineRestHandler.go | 3 ++- wire_gen.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/api/restHandler/app/BuildPipelineRestHandler.go b/api/restHandler/app/BuildPipelineRestHandler.go index 4de714061c..7c925cd92b 100644 --- a/api/restHandler/app/BuildPipelineRestHandler.go +++ b/api/restHandler/app/BuildPipelineRestHandler.go @@ -758,7 +758,8 @@ func (handler PipelineConfigRestHandlerImpl) RefreshMaterials(w http.ResponseWri //RBAC token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(material.AppId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionGet) + if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } diff --git a/wire_gen.go b/wire_gen.go index b3681af4a3..05acd9eeda 100644 --- a/wire_gen.go +++ b/wire_gen.go @@ -502,7 +502,7 @@ func InitializeApp() (*App, error) { } devtronAppCMCSServiceImpl := pipeline.NewDevtronAppCMCSServiceImpl(sugaredLogger, appServiceImpl, attributesRepositoryImpl) cdPipelineConfigServiceImpl := pipeline.NewCdPipelineConfigServiceImpl(sugaredLogger, pipelineRepositoryImpl, environmentRepositoryImpl, pipelineConfigRepositoryImpl, appWorkflowRepositoryImpl, pipelineStageServiceImpl, appRepositoryImpl, appServiceImpl, deploymentGroupRepositoryImpl, ciCdPipelineOrchestratorImpl, appStatusRepositoryImpl, ciPipelineRepositoryImpl, prePostCdScriptHistoryServiceImpl, clusterRepositoryImpl, helmAppServiceImpl, enforcerUtilImpl, gitOpsConfigRepositoryImpl, pipelineStrategyHistoryServiceImpl, chartRepositoryImpl, resourceGroupServiceImpl, chartDeploymentServiceImpl, chartTemplateServiceImpl, propertiesConfigServiceImpl, appLevelMetricsRepositoryImpl, deploymentTemplateHistoryServiceImpl, scopedVariableManagerImpl, pipelineDeploymentServiceTypeConfig, applicationServiceClientImpl, customTagServiceImpl, pipelineConfigListenerServiceImpl, devtronAppCMCSServiceImpl) - appArtifactManagerImpl := pipeline.NewAppArtifactManagerImpl(sugaredLogger, cdWorkflowRepositoryImpl, userServiceImpl, imageTaggingServiceImpl, ciArtifactRepositoryImpl, ciWorkflowRepositoryImpl, pipelineStageServiceImpl, cdPipelineConfigServiceImpl, dockerArtifactStoreRepositoryImpl, ciPipelineRepositoryImpl) + appArtifactManagerImpl := pipeline.NewAppArtifactManagerImpl(sugaredLogger, cdWorkflowRepositoryImpl, userServiceImpl, imageTaggingServiceImpl, ciArtifactRepositoryImpl, ciWorkflowRepositoryImpl, pipelineStageServiceImpl, cdPipelineConfigServiceImpl, dockerArtifactStoreRepositoryImpl, ciPipelineRepositoryImpl,ciTemplateServiceImpl) globalStrategyMetadataChartRefMappingRepositoryImpl := chartRepoRepository.NewGlobalStrategyMetadataChartRefMappingRepositoryImpl(db, sugaredLogger) devtronAppStrategyServiceImpl := pipeline.NewDevtronAppStrategyServiceImpl(sugaredLogger, chartRepositoryImpl, globalStrategyMetadataChartRefMappingRepositoryImpl, ciCdPipelineOrchestratorImpl, cdPipelineConfigServiceImpl) appDeploymentTypeChangeManagerImpl := pipeline.NewAppDeploymentTypeChangeManagerImpl(sugaredLogger, pipelineRepositoryImpl, workflowDagExecutorImpl, appServiceImpl, chartTemplateServiceImpl, appStatusRepositoryImpl, helmAppServiceImpl, applicationServiceClientImpl, appArtifactManagerImpl, cdPipelineConfigServiceImpl) From b8c295b2aabc13c648b1836d7728b53d6e0398a7 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Thu, 30 Nov 2023 12:34:07 +0530 Subject: [PATCH 73/76] wire-gen --- wire_gen.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wire_gen.go b/wire_gen.go index 05acd9eeda..fcc9697161 100644 --- a/wire_gen.go +++ b/wire_gen.go @@ -502,7 +502,7 @@ func InitializeApp() (*App, error) { } devtronAppCMCSServiceImpl := pipeline.NewDevtronAppCMCSServiceImpl(sugaredLogger, appServiceImpl, attributesRepositoryImpl) cdPipelineConfigServiceImpl := pipeline.NewCdPipelineConfigServiceImpl(sugaredLogger, pipelineRepositoryImpl, environmentRepositoryImpl, pipelineConfigRepositoryImpl, appWorkflowRepositoryImpl, pipelineStageServiceImpl, appRepositoryImpl, appServiceImpl, deploymentGroupRepositoryImpl, ciCdPipelineOrchestratorImpl, appStatusRepositoryImpl, ciPipelineRepositoryImpl, prePostCdScriptHistoryServiceImpl, clusterRepositoryImpl, helmAppServiceImpl, enforcerUtilImpl, gitOpsConfigRepositoryImpl, pipelineStrategyHistoryServiceImpl, chartRepositoryImpl, resourceGroupServiceImpl, chartDeploymentServiceImpl, chartTemplateServiceImpl, propertiesConfigServiceImpl, appLevelMetricsRepositoryImpl, deploymentTemplateHistoryServiceImpl, scopedVariableManagerImpl, pipelineDeploymentServiceTypeConfig, applicationServiceClientImpl, customTagServiceImpl, pipelineConfigListenerServiceImpl, devtronAppCMCSServiceImpl) - appArtifactManagerImpl := pipeline.NewAppArtifactManagerImpl(sugaredLogger, cdWorkflowRepositoryImpl, userServiceImpl, imageTaggingServiceImpl, ciArtifactRepositoryImpl, ciWorkflowRepositoryImpl, pipelineStageServiceImpl, cdPipelineConfigServiceImpl, dockerArtifactStoreRepositoryImpl, ciPipelineRepositoryImpl,ciTemplateServiceImpl) + appArtifactManagerImpl := pipeline.NewAppArtifactManagerImpl(sugaredLogger, cdWorkflowRepositoryImpl, userServiceImpl, imageTaggingServiceImpl, ciArtifactRepositoryImpl, ciWorkflowRepositoryImpl, pipelineStageServiceImpl, cdPipelineConfigServiceImpl, dockerArtifactStoreRepositoryImpl, ciPipelineRepositoryImpl, ciTemplateServiceImpl) globalStrategyMetadataChartRefMappingRepositoryImpl := chartRepoRepository.NewGlobalStrategyMetadataChartRefMappingRepositoryImpl(db, sugaredLogger) devtronAppStrategyServiceImpl := pipeline.NewDevtronAppStrategyServiceImpl(sugaredLogger, chartRepositoryImpl, globalStrategyMetadataChartRefMappingRepositoryImpl, ciCdPipelineOrchestratorImpl, cdPipelineConfigServiceImpl) appDeploymentTypeChangeManagerImpl := pipeline.NewAppDeploymentTypeChangeManagerImpl(sugaredLogger, pipelineRepositoryImpl, workflowDagExecutorImpl, appServiceImpl, chartTemplateServiceImpl, appStatusRepositoryImpl, helmAppServiceImpl, applicationServiceClientImpl, appArtifactManagerImpl, cdPipelineConfigServiceImpl) From c91c18d549d68d8b6f455eb0483ddcb0da231629 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Thu, 30 Nov 2023 14:23:59 +0530 Subject: [PATCH 74/76] merge main --- api/restHandler/app/BuildPipelineRestHandler.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/restHandler/app/BuildPipelineRestHandler.go b/api/restHandler/app/BuildPipelineRestHandler.go index 7c925cd92b..3bb05ee8ee 100644 --- a/api/restHandler/app/BuildPipelineRestHandler.go +++ b/api/restHandler/app/BuildPipelineRestHandler.go @@ -721,7 +721,8 @@ func (handler PipelineConfigRestHandlerImpl) FetchMaterialsByMaterialId(w http.R //RBAC token := r.Header.Get("token") object := handler.enforcerUtil.GetAppRBACNameByAppId(ciPipeline.AppId) - if ok := handler.enforcer.Enforce(token, casbin.ResourceApplications, casbin.ActionGet, object); !ok { + ok := handler.enforcerUtil.CheckAppRbacForAppOrJob(token, object, casbin.ActionGet) + if !ok { common.WriteJsonResp(w, err, "Unauthorized User", http.StatusForbidden) return } From 50458ec36c1fe99615914fbcdb8d8d0314af1269 Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Thu, 30 Nov 2023 17:01:52 +0530 Subject: [PATCH 75/76] app type --- .../app/AutoCompleteRestHandler.go | 9 ++++-- internal/sql/repository/app/AppRepository.go | 12 ++++---- util/rbac/EnforcerUtil.go | 28 +++++++++++++------ 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/api/restHandler/app/AutoCompleteRestHandler.go b/api/restHandler/app/AutoCompleteRestHandler.go index f1bfd4ee3b..a6c7e87fdd 100644 --- a/api/restHandler/app/AutoCompleteRestHandler.go +++ b/api/restHandler/app/AutoCompleteRestHandler.go @@ -47,6 +47,9 @@ func (handler PipelineConfigRestHandlerImpl) GetAppListForAutocomplete(w http.Re common.WriteJsonResp(w, err, "Failed to parse appType param", http.StatusInternalServerError) return } + } else { + // if appType not provided we are considering it as customApp for now, doing this because to get all apps by team id rbac objects + appType = int(helper.CustomApp) } var teamIdInt int handler.Logger.Infow("request payload, GetAppListForAutocomplete", "teamId", teamId) @@ -91,9 +94,9 @@ func (handler PipelineConfigRestHandlerImpl) GetAppListForAutocomplete(w http.Re var appIdToObjectMap map[int]string if len(teamId) == 0 { - appIdToObjectMap = handler.enforcerUtil.GetRbacObjectsForAllAppsWithMatchingAppName(appName) + appIdToObjectMap = handler.enforcerUtil.GetRbacObjectsForAllAppsWithMatchingAppName(appName, helper.AppType(appType)) } else { - appIdToObjectMap = handler.enforcerUtil.GetRbacObjectsForAllAppsWithTeamID(teamIdInt) + appIdToObjectMap = handler.enforcerUtil.GetRbacObjectsForAllAppsWithTeamID(teamIdInt, helper.AppType(appType)) } for _, app := range apps { @@ -101,7 +104,7 @@ func (handler PipelineConfigRestHandlerImpl) GetAppListForAutocomplete(w http.Re rbacObjects = append(rbacObjects, object) } - enforcedMap := handler.enforcer.EnforceByEmailInBatch(userEmailId, casbin.ResourceApplications, casbin.ActionGet, rbacObjects) + enforcedMap := handler.enforcerUtil.CheckAppRbacForAppOrJobInBulk(userEmailId, casbin.ActionGet, rbacObjects, helper.AppType(appType)) for _, app := range apps { object := appIdToObjectMap[app.Id] if enforcedMap[object] { diff --git a/internal/sql/repository/app/AppRepository.go b/internal/sql/repository/app/AppRepository.go index 02929b5f8c..693da85306 100644 --- a/internal/sql/repository/app/AppRepository.go +++ b/internal/sql/repository/app/AppRepository.go @@ -58,7 +58,7 @@ type AppRepository interface { FindAll() ([]*App, error) FindAppsByEnvironmentId(environmentId int) ([]App, error) FindAllActiveAppsWithTeam(appType helper.AppType) ([]*App, error) - FindAllActiveAppsWithTeamWithTeamId(teamID int) ([]*App, error) + FindAllActiveAppsWithTeamWithTeamId(teamID int, appType helper.AppType) ([]*App, error) CheckAppExists(appNames []string) ([]*App, error) FindByIds(ids []*int) ([]*App, error) @@ -74,7 +74,7 @@ type AppRepository interface { FetchAllActiveDevtronAppsWithAppIdAndName() ([]*App, error) FindEnvironmentIdForInstalledApp(appId int) (int, error) FetchAppIdsWithFilter(jobListingFilter helper.AppListingFilter) ([]int, error) - FindAllActiveAppsWithTeamByAppNameMatch(appNameMatch string) ([]*App, error) + FindAllActiveAppsWithTeamByAppNameMatch(appNameMatch string, appType helper.AppType) ([]*App, error) FindAppAndProjectByIdsIn(ids []int) ([]*App, error) FetchAppIdsByDisplaynames(names []string) (map[int]string, []int, error) } @@ -238,21 +238,21 @@ func (repo AppRepositoryImpl) FindAllActiveAppsWithTeam(appType helper.AppType) return apps, err } -func (repo AppRepositoryImpl) FindAllActiveAppsWithTeamWithTeamId(teamID int) ([]*App, error) { +func (repo AppRepositoryImpl) FindAllActiveAppsWithTeamWithTeamId(teamID int, appType helper.AppType) ([]*App, error) { var apps []*App err := repo.dbConnection.Model(&apps).Column("Team"). Where("app.active = ?", true). - Where("app.app_type = ?", 0). + Where("app.app_type = ?", appType). Where("app.team_id = ?", teamID). Select() return apps, err } -func (repo AppRepositoryImpl) FindAllActiveAppsWithTeamByAppNameMatch(appNameMatch string) ([]*App, error) { +func (repo AppRepositoryImpl) FindAllActiveAppsWithTeamByAppNameMatch(appNameMatch string, appType helper.AppType) ([]*App, error) { var apps []*App appNameLikeQuery := "app.app_name like '%" + appNameMatch + "%'" err := repo.dbConnection.Model(&apps).Column("Team"). - Where("app.active = ?", true).Where("app.app_type = ?", helper.CustomApp).Where(appNameLikeQuery). + Where("app.active = ?", true).Where("app.app_type = ?", appType).Where(appNameLikeQuery). Select() return apps, err } diff --git a/util/rbac/EnforcerUtil.go b/util/rbac/EnforcerUtil.go index 147e2bfc45..99b9e0e09b 100644 --- a/util/rbac/EnforcerUtil.go +++ b/util/rbac/EnforcerUtil.go @@ -37,7 +37,7 @@ import ( type EnforcerUtil interface { GetAppRBACName(appName string) string GetRbacObjectsForAllApps(appType helper.AppType) map[int]string - GetRbacObjectsForAllAppsWithTeamID(teamID int) map[int]string + GetRbacObjectsForAllAppsWithTeamID(teamID int, appType helper.AppType) map[int]string GetAppRBACNameByAppId(appId int) string GetAppRBACByAppNameAndEnvId(appName string, envId int) string GetAppRBACByAppIdAndPipelineId(appId int, pipelineId int) string @@ -58,7 +58,7 @@ type EnforcerUtil interface { GetRBACNameForClusterEntity(clusterName string, resourceIdentifier k8s.ResourceIdentifier) (resourceName, objectName string) GetAppObjectByCiPipelineIds(ciPipelineIds []int) map[int]string GetAppAndEnvObjectByPipelineIds(cdPipelineIds []int) map[int][]string - GetRbacObjectsForAllAppsWithMatchingAppName(appNameMatch string) map[int]string + GetRbacObjectsForAllAppsWithMatchingAppName(appNameMatch string, appType helper.AppType) map[int]string GetAppAndEnvObjectByPipeline(cdPipelines []*bean.CDPipelineConfigObject) map[int][]string GetAppAndEnvObjectByDbPipeline(cdPipelines []*pipelineConfig.Pipeline) map[int][]string GetRbacObjectsByAppIds(appIds []int) map[int]string @@ -73,6 +73,7 @@ type EnforcerUtil interface { GetAllWorkflowRBACObjectsByAppId(appId int, workflowNames []string, workflowIds []int) map[int]string GetEnvRBACArrayByAppIdForJobs(appId int) []string CheckAppRbacForAppOrJob(token, resourceName, action string) bool + CheckAppRbacForAppOrJobInBulk(email, action string, rbacObjects []string, appType helper.AppType) map[string]bool } type EnforcerUtilImpl struct { @@ -178,15 +179,15 @@ func (impl EnforcerUtilImpl) GetRbacObjectsForAllApps(appType helper.AppType) ma return objects } -func (impl EnforcerUtilImpl) GetRbacObjectsForAllAppsWithTeamID(teamID int) map[int]string { +func (impl EnforcerUtilImpl) GetRbacObjectsForAllAppsWithTeamID(teamID int, appType helper.AppType) map[int]string { objects := make(map[int]string) - result, err := impl.appRepo.FindAllActiveAppsWithTeamWithTeamId(teamID) + result, err := impl.appRepo.FindAllActiveAppsWithTeamWithTeamId(teamID, appType) if err != nil { return objects } for _, item := range result { if _, ok := objects[item.Id]; !ok { - objects[item.Id] = fmt.Sprintf("%s/%s", item.Team.Name, item.AppName) + objects[item.Id] = fmt.Sprintf("%s/%s", item.Team.Name, strings.ToLower(item.AppName)) } } return objects @@ -539,15 +540,15 @@ func (impl EnforcerUtilImpl) GetAppAndEnvObjectByPipelineIds(cdPipelineIds []int return objects } -func (impl EnforcerUtilImpl) GetRbacObjectsForAllAppsWithMatchingAppName(appNameMatch string) map[int]string { +func (impl EnforcerUtilImpl) GetRbacObjectsForAllAppsWithMatchingAppName(appNameMatch string, appType helper.AppType) map[int]string { objects := make(map[int]string) - result, err := impl.appRepo.FindAllActiveAppsWithTeamByAppNameMatch(appNameMatch) + result, err := impl.appRepo.FindAllActiveAppsWithTeamByAppNameMatch(appNameMatch, appType) if err != nil { return objects } for _, item := range result { if _, ok := objects[item.Id]; !ok { - objects[item.Id] = fmt.Sprintf("%s/%s", item.Team.Name, item.AppName) + objects[item.Id] = fmt.Sprintf("%s/%s", item.Team.Name, strings.ToLower(item.AppName)) } } return objects @@ -706,3 +707,14 @@ func (impl EnforcerUtilImpl) CheckAppRbacForAppOrJob(token, resourceName, action } return ok } + +func (impl EnforcerUtilImpl) CheckAppRbacForAppOrJobInBulk(email, action string, rbacObjects []string, appType helper.AppType) map[string]bool { + var enforcedMap map[string]bool + if appType == helper.Job { + enforcedMap = impl.enforcer.EnforceByEmailInBatch(email, casbin.ResourceJobs, action, rbacObjects) + } else { + enforcedMap = impl.enforcer.EnforceByEmailInBatch(email, casbin.ResourceApplications, action, rbacObjects) + } + + return enforcedMap +} From 3a655d32276bee32e3df91567edc4ceafeb38c2b Mon Sep 17 00:00:00 2001 From: Shivam-nagar23 Date: Thu, 30 Nov 2023 19:03:41 +0530 Subject: [PATCH 76/76] message --- pkg/pipeline/CiHandler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/pipeline/CiHandler.go b/pkg/pipeline/CiHandler.go index 1f162c664a..44c4054856 100644 --- a/pkg/pipeline/CiHandler.go +++ b/pkg/pipeline/CiHandler.go @@ -1141,7 +1141,7 @@ func (impl *CiHandlerImpl) UpdateWorkflow(workflowStatus v1alpha1.WorkflowStatus savedWorkflow.Status = status } savedWorkflow.PodStatus = podStatus - + savedWorkflow.Message = message // NOTE: we are doing this for a quick fix where ci pending message become larger than 250 and in db we had set the charter limit to 250 if len(message) > 250 { savedWorkflow.Message = message[:250]