From bc9f5cd86ba8263df25de44377e4dd553536c4f2 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Mon, 28 Oct 2024 14:53:44 +0800 Subject: [PATCH 01/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/user/UserAuthResourceGroupResource.kt | 4 + .../user/UserAuthResourceMemberResource.kt | 18 +- .../devops/auth/pojo/enum/JoinedType.kt | 5 +- .../devops/auth/pojo/enum/OperateChannel.kt | 37 + .../request/GroupMemberCommonConditionReq.kt | 7 +- .../GroupMemberHandoverConditionReq.kt | 4 + .../request/GroupMemberRenewalConditionReq.kt | 4 + .../devops/auth/dao/AuthAuthorizationDao.kt | 7 + .../auth/dao/AuthResourceGroupMemberDao.kt | 25 +- .../dao/AuthResourceGroupPermissionDao.kt | 21 + .../rbac/config/RbacAuthConfiguration.kt | 19 +- ...ResourceGroupAndMemberFacadeServiceImpl.kt | 889 +++++++++++++++++- ...ermissionResourceGroupPermissionService.kt | 15 + .../RbacPermissionResourceMemberService.kt | 691 +------------- .../RbacPermissionResourceValidateService.kt | 35 + ...sionResourceGroupAndMemberFacadeService.kt | 80 +- ...ermissionResourceGroupPermissionService.kt | 6 + .../SamplePermissionResourceMemberService.kt | 78 +- ...SamplePermissionResourceValidateService.kt | 9 + .../ServiceResourceMemberResourceImpl.kt | 8 +- .../user/UserAuthResourceGroupResourceImpl.kt | 15 +- .../UserAuthResourceMemberResourceImpl.kt | 34 +- .../PermissionAuthorizationServiceImpl.kt | 5 +- ...sionResourceGroupAndMemberFacadeService.kt | 101 +- ...ermissionResourceGroupPermissionService.kt | 9 + .../iam/PermissionResourceMemberService.kt | 71 -- .../iam/PermissionResourceValidateService.kt | 10 + .../ResourceAuthorizationConditionRequest.kt | 4 + ...ceAuthorizationHandoverConditionRequest.kt | 6 + .../api/pojo/ResourceAuthorizationResponse.kt | 2 + 30 files changed, 1334 insertions(+), 885 deletions(-) create mode 100644 src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/OperateChannel.kt diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthResourceGroupResource.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthResourceGroupResource.kt index 5dc4c034267..61dca343871 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthResourceGroupResource.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthResourceGroupResource.kt @@ -30,6 +30,7 @@ package com.tencent.devops.auth.api.user import com.tencent.devops.auth.pojo.dto.GroupMemberRenewalDTO import com.tencent.devops.auth.pojo.dto.RenameGroupDTO +import com.tencent.devops.auth.pojo.enum.OperateChannel import com.tencent.devops.auth.pojo.vo.GroupDetailsInfoVo import com.tencent.devops.auth.pojo.vo.IamGroupPoliciesVo import com.tencent.devops.common.api.annotation.BkInterfaceI18n @@ -110,6 +111,9 @@ interface UserAuthResourceGroupResource { @QueryParam("action") @Parameter(description = "操作") action: String?, + @QueryParam("operateChannel") + @Parameter(description = "操作渠道") + operateChannel: OperateChannel?, @Parameter(description = "起始位置,从0开始") @QueryParam("start") start: Int, diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthResourceMemberResource.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthResourceMemberResource.kt index 26a74ba5b87..f5cab40a861 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthResourceMemberResource.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthResourceMemberResource.kt @@ -2,6 +2,7 @@ package com.tencent.devops.auth.api.user import com.tencent.devops.auth.pojo.ResourceMemberInfo import com.tencent.devops.auth.pojo.enum.BatchOperateType +import com.tencent.devops.auth.pojo.enum.OperateChannel import com.tencent.devops.auth.pojo.request.GroupMemberCommonConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberHandoverConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberRenewalConditionReq @@ -96,8 +97,8 @@ interface UserAuthResourceMemberResource { @PUT @Path("/batch/renewal") - @Operation(summary = "批量续期组成员权限--无需进行审批") - fun batchRenewalGroupMembers( + @Operation(summary = "批量续期组成员权限--管理员视角") + fun batchRenewalGroupMembersFromManager( @Parameter(description = "用户名", required = true) @HeaderParam(AUTH_HEADER_USER_ID) userId: String, @@ -110,8 +111,8 @@ interface UserAuthResourceMemberResource { @DELETE @Path("/batch/remove") - @Operation(summary = "批量移除用户组成员") - fun batchRemoveGroupMembers( + @Operation(summary = "批量移除用户组成员--管理员视角") + fun batchRemoveGroupMembersFromManager( @Parameter(description = "用户名", required = true) @HeaderParam(AUTH_HEADER_USER_ID) userId: String, @@ -124,8 +125,8 @@ interface UserAuthResourceMemberResource { @PUT @Path("/batch/handover") - @Operation(summary = "批量交接用户组成员") - fun batchHandoverGroupMembers( + @Operation(summary = "批量交接用户组成员--管理员视角") + fun batchHandoverGroupMembersFromManager( @Parameter(description = "用户名", required = true) @HeaderParam(AUTH_HEADER_USER_ID) userId: String, @@ -211,6 +212,9 @@ interface UserAuthResourceMemberResource { relatedResourceCode: String?, @QueryParam("action") @Parameter(description = "操作") - action: String? + action: String?, + @QueryParam("operateChannel") + @Parameter(description = "操作渠道") + operateChannel: OperateChannel? ): Result> } diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/JoinedType.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/JoinedType.kt index 06b700c88bd..8bff11d4870 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/JoinedType.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/JoinedType.kt @@ -32,5 +32,8 @@ enum class JoinedType { DIRECT, // 通过模板加入 - TEMPLATE + TEMPLATE, + + // 通过组织加入 + DEPARTMENT } diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/OperateChannel.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/OperateChannel.kt new file mode 100644 index 00000000000..5c08753de64 --- /dev/null +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/OperateChannel.kt @@ -0,0 +1,37 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. + * + * A copy of the MIT License is included in this file. + * + * + * Terms of the MIT License: + * --------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +package com.tencent.devops.auth.pojo.enum + +enum class OperateChannel(val value: String) { + // 个人视角 + PERSONAL("personal"), + + // 管理员视角 + MANAGER("manager"); +} diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberCommonConditionReq.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberCommonConditionReq.kt index db943b94c74..3261a5f3774 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberCommonConditionReq.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberCommonConditionReq.kt @@ -1,6 +1,7 @@ package com.tencent.devops.auth.pojo.request import com.tencent.devops.auth.pojo.ResourceMemberInfo +import com.tencent.devops.auth.pojo.enum.OperateChannel import io.swagger.v3.oas.annotations.media.Schema @Schema(title = "用户组成员处理公共请求体") @@ -14,11 +15,13 @@ open class GroupMemberCommonConditionReq( @get:Schema(title = "是否排除唯一管理员组") open var excludedUniqueManagerGroup: Boolean = false, @get:Schema(title = "目标对象") - open val targetMember: ResourceMemberInfo + open val targetMember: ResourceMemberInfo, + @get:Schema(title = "操作渠道") + open val operateChannel: OperateChannel = OperateChannel.MANAGER ) { override fun toString(): String { return "GroupMemberCommonConditionReq(groupIds=$groupIds,resourceTypes=$resourceTypes," + "allSelection=$allSelection,excludedUniqueManagerGroup=$excludedUniqueManagerGroup," + - "targetMember=$targetMember)" + "targetMember=$targetMember,operateChannel=$operateChannel)" } } diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberHandoverConditionReq.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberHandoverConditionReq.kt index dc0f85b0daa..e99d5dd99c5 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberHandoverConditionReq.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberHandoverConditionReq.kt @@ -29,6 +29,7 @@ package com.tencent.devops.auth.pojo.request import com.tencent.devops.auth.constant.AuthMessageCode.INVALID_HANDOVER_TO import com.tencent.devops.auth.pojo.ResourceMemberInfo +import com.tencent.devops.auth.pojo.enum.OperateChannel import com.tencent.devops.common.api.exception.ErrorCodeException import io.swagger.v3.oas.annotations.media.Schema @@ -44,6 +45,8 @@ data class GroupMemberHandoverConditionReq( override var excludedUniqueManagerGroup: Boolean = false, @get:Schema(title = "目标对象") override val targetMember: ResourceMemberInfo, + @get:Schema(title = "操作渠道") + override val operateChannel: OperateChannel = OperateChannel.MANAGER, @get:Schema(title = "授予人") val handoverTo: ResourceMemberInfo ) : GroupMemberCommonConditionReq( @@ -51,6 +54,7 @@ data class GroupMemberHandoverConditionReq( resourceTypes = resourceTypes, allSelection = allSelection, excludedUniqueManagerGroup = excludedUniqueManagerGroup, + operateChannel = operateChannel, targetMember = targetMember ) { fun checkHandoverTo() { diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberRenewalConditionReq.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberRenewalConditionReq.kt index b8b6ce8598c..6ed88f07a21 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberRenewalConditionReq.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberRenewalConditionReq.kt @@ -28,6 +28,7 @@ package com.tencent.devops.auth.pojo.request import com.tencent.devops.auth.pojo.ResourceMemberInfo +import com.tencent.devops.auth.pojo.enum.OperateChannel import io.swagger.v3.oas.annotations.media.Schema @Schema(title = "用户组成员续期") @@ -42,6 +43,8 @@ data class GroupMemberRenewalConditionReq( override var excludedUniqueManagerGroup: Boolean = false, @get:Schema(title = "目标对象") override val targetMember: ResourceMemberInfo, + @get:Schema(title = "操作渠道") + override val operateChannel: OperateChannel = OperateChannel.MANAGER, @get:Schema(title = "续期时长(天)") val renewalDuration: Int ) : GroupMemberCommonConditionReq( @@ -49,5 +52,6 @@ data class GroupMemberRenewalConditionReq( resourceTypes = resourceTypes, allSelection = allSelection, excludedUniqueManagerGroup = excludedUniqueManagerGroup, + operateChannel = operateChannel, targetMember = targetMember ) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthAuthorizationDao.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthAuthorizationDao.kt index dca6f34e966..d973d4ffe59 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthAuthorizationDao.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthAuthorizationDao.kt @@ -191,6 +191,12 @@ class AuthAuthorizationDao { if (resourceName != null) { conditions.add(RESOURCE_NAME.like("%$resourceName%")) } + if (!filterResourceCodes.isNullOrEmpty()) { + conditions.add(RESOURCE_CODE.`in`(filterResourceCodes)) + } + if (!excludeResourceCodes.isNullOrEmpty()) { + conditions.add(RESOURCE_CODE.notIn(excludeResourceCodes)) + } if (handoverFrom != null) { conditions.add(HANDOVER_FROM.eq(handoverFrom)) } @@ -204,6 +210,7 @@ class AuthAuthorizationDao { fun TAuthResourceAuthorizationRecord.convert(): ResourceAuthorizationResponse { return ResourceAuthorizationResponse( + id = id, projectCode = projectCode, resourceType = resourceType, resourceName = resourceName, diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupMemberDao.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupMemberDao.kt index 5a016760aaf..f279039dab4 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupMemberDao.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupMemberDao.kt @@ -543,8 +543,10 @@ class AuthResourceGroupMemberDao { iamTemplateIds: List, resourceType: String? = null, iamGroupIds: List? = null, + excludeIamGroupIds: List? = null, minExpiredAt: LocalDateTime? = null, - maxExpiredAt: LocalDateTime? = null + maxExpiredAt: LocalDateTime? = null, + memberDeptInfos: List? = null ): Map { val conditions = buildMemberGroupCondition( projectCode = projectCode, @@ -552,8 +554,10 @@ class AuthResourceGroupMemberDao { iamTemplateIds = iamTemplateIds, resourceType = resourceType, iamGroupIds = iamGroupIds, + excludeIamGroupIds = excludeIamGroupIds, minExpiredAt = minExpiredAt, - maxExpiredAt = maxExpiredAt + maxExpiredAt = maxExpiredAt, + memberDeptInfos = memberDeptInfos ) return with(TAuthResourceGroupMember.T_AUTH_RESOURCE_GROUP_MEMBER) { val select = dslContext.select(RESOURCE_TYPE, count()) @@ -592,8 +596,10 @@ class AuthResourceGroupMemberDao { iamTemplateIds: List, resourceType: String? = null, iamGroupIds: List? = null, + excludeIamGroupIds: List? = null, minExpiredAt: LocalDateTime? = null, maxExpiredAt: LocalDateTime? = null, + memberDeptInfos: List? = null, offset: Int? = null, limit: Int? = null ): List { @@ -603,8 +609,10 @@ class AuthResourceGroupMemberDao { iamTemplateIds = iamTemplateIds, resourceType = resourceType, iamGroupIds = iamGroupIds, + excludeIamGroupIds = excludeIamGroupIds, minExpiredAt = minExpiredAt, - maxExpiredAt = maxExpiredAt + maxExpiredAt = maxExpiredAt, + memberDeptInfos = memberDeptInfos ) return with(TAuthResourceGroupMember.T_AUTH_RESOURCE_GROUP_MEMBER) { dslContext.selectFrom(this) @@ -622,8 +630,10 @@ class AuthResourceGroupMemberDao { iamTemplateIds: List, resourceType: String? = null, iamGroupIds: List? = null, + excludeIamGroupIds: List? = null, minExpiredAt: LocalDateTime? = null, - maxExpiredAt: LocalDateTime? = null + maxExpiredAt: LocalDateTime? = null, + memberDeptInfos: List? = null ): MutableList { val conditions = mutableListOf() with(TAuthResourceGroupMember.T_AUTH_RESOURCE_GROUP_MEMBER) { @@ -641,6 +651,10 @@ class AuthResourceGroupMemberDao { MEMBER_ID.`in`(iamTemplateIds) .and(MEMBER_TYPE.eq(ManagerScopesEnum.getType(ManagerScopesEnum.TEMPLATE))) ) + .or( + MEMBER_ID.`in`(memberDeptInfos) + .and(MEMBER_TYPE.eq(ManagerScopesEnum.getType(ManagerScopesEnum.DEPARTMENT))) + ) ) resourceType?.let { conditions.add(RESOURCE_TYPE.eq(resourceType)) } minExpiredAt?.let { conditions.add(EXPIRED_TIME.ge(minExpiredAt)) } @@ -648,6 +662,9 @@ class AuthResourceGroupMemberDao { if (!iamGroupIds.isNullOrEmpty()) { conditions.add(IAM_GROUP_ID.`in`(iamGroupIds)) } + if (!excludeIamGroupIds.isNullOrEmpty()) { + conditions.add(IAM_GROUP_ID.notIn(excludeIamGroupIds)) + } } return conditions } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupPermissionDao.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupPermissionDao.kt index 4eb94a340c0..439b357e03e 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupPermissionDao.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupPermissionDao.kt @@ -2,6 +2,7 @@ package com.tencent.devops.auth.dao import com.tencent.devops.auth.pojo.dto.ResourceGroupPermissionDTO import com.tencent.devops.common.auth.api.AuthResourceType +import com.tencent.devops.common.auth.api.ResourceTypeId import com.tencent.devops.model.auth.tables.TAuthResourceGroupPermission import com.tencent.devops.model.auth.tables.records.TAuthResourceGroupPermissionRecord import org.jooq.Condition @@ -183,6 +184,26 @@ class AuthResourceGroupPermissionDao { } } + fun isGroupsHasProjectLevelPermission( + dslContext: DSLContext, + projectCode: String, + filterIamGroupIds: List, + actionRelatedResourceType: String, + action: String + ): Boolean { + return with(TAuthResourceGroupPermission.T_AUTH_RESOURCE_GROUP_PERMISSION) { + dslContext.selectCount() + .from(this) + .where(PROJECT_CODE.eq(projectCode)) + .and(IAM_GROUP_ID.`in`(filterIamGroupIds)) + .and(ACTION_RELATED_RESOURCE_TYPE.eq(actionRelatedResourceType)) + .and(ACTION.eq(action)) + .and(RELATED_RESOURCE_TYPE.eq(ResourceTypeId.PROJECT)) + .and(RELATED_RESOURCE_CODE.eq(projectCode)) + .fetchOne(0, Int::class.java)!! > 0 + } + } + fun listGroupResourcesWithPermission( dslContext: DSLContext, projectCode: String, diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/config/RbacAuthConfiguration.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/config/RbacAuthConfiguration.kt index aa62e4ef582..bea9b0d81f8 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/config/RbacAuthConfiguration.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/config/RbacAuthConfiguration.kt @@ -43,6 +43,7 @@ import com.tencent.bk.sdk.iam.service.v2.impl.V2GrantServiceImpl import com.tencent.bk.sdk.iam.service.v2.impl.V2ManagerServiceImpl import com.tencent.bk.sdk.iam.service.v2.impl.V2PolicyServiceImpl import com.tencent.devops.auth.dao.AuthActionDao +import com.tencent.devops.auth.dao.AuthAuthorizationDao import com.tencent.devops.auth.dao.AuthMigrationDao import com.tencent.devops.auth.dao.AuthMonitorSpaceDao import com.tencent.devops.auth.dao.AuthResourceDao @@ -207,7 +208,10 @@ class RbacAuthConfiguration { dslContext: DSLContext, deptService: DeptService, iamV2ManagerService: V2ManagerService, - rbacCacheService: RbacCacheService + rbacCacheService: RbacCacheService, + permissionAuthorizationService: PermissionAuthorizationService, + syncIamGroupMemberService: PermissionResourceGroupSyncService, + authAuthorizationDao: AuthAuthorizationDao ) = RbacPermissionResourceGroupAndMemberFacadeServiceImpl( permissionResourceGroupService = permissionResourceGroupService, groupPermissionService = groupPermissionService, @@ -217,7 +221,10 @@ class RbacAuthConfiguration { dslContext = dslContext, deptService = deptService, iamV2ManagerService = iamV2ManagerService, - rbacCacheService = rbacCacheService + rbacCacheService = rbacCacheService, + permissionAuthorizationService = permissionAuthorizationService, + syncIamGroupMemberService = syncIamGroupMemberService, + authAuthorizationDao = authAuthorizationDao ) @Bean @@ -259,18 +266,14 @@ class RbacAuthConfiguration { authResourceGroupMemberDao: AuthResourceGroupMemberDao, dslContext: DSLContext, deptService: DeptService, - rbacCacheService: RbacCacheService, - permissionAuthorizationService: PermissionAuthorizationService, - syncIamGroupMemberService: PermissionResourceGroupSyncService + rbacCacheService: RbacCacheService ) = RbacPermissionResourceMemberService( authResourceService = authResourceService, iamV2ManagerService = iamV2ManagerService, authResourceGroupDao = authResourceGroupDao, authResourceGroupMemberDao = authResourceGroupMemberDao, dslContext = dslContext, - deptService = deptService, - permissionAuthorizationService = permissionAuthorizationService, - syncIamGroupMemberService = syncIamGroupMemberService + deptService = deptService ) @Bean diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupAndMemberFacadeServiceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupAndMemberFacadeServiceImpl.kt index 79229b6946b..45c30ba701f 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupAndMemberFacadeServiceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupAndMemberFacadeServiceImpl.kt @@ -1,33 +1,55 @@ package com.tencent.devops.auth.provider.rbac.service import com.tencent.bk.sdk.iam.constants.ManagerScopesEnum +import com.tencent.bk.sdk.iam.dto.manager.ManagerMember import com.tencent.bk.sdk.iam.dto.response.MemberGroupDetailsResponse import com.tencent.bk.sdk.iam.service.v2.V2ManagerService import com.tencent.devops.auth.constant.AuthI18nConstants +import com.tencent.devops.auth.constant.AuthMessageCode +import com.tencent.devops.auth.dao.AuthAuthorizationDao import com.tencent.devops.auth.dao.AuthResourceGroupDao import com.tencent.devops.auth.dao.AuthResourceGroupMemberDao import com.tencent.devops.auth.pojo.AuthResourceGroupMember import com.tencent.devops.auth.pojo.ResourceMemberInfo import com.tencent.devops.auth.pojo.dto.IamGroupIdsQueryConditionDTO import com.tencent.devops.auth.pojo.dto.ProjectMembersQueryConditionDTO +import com.tencent.devops.auth.pojo.enum.BatchOperateType import com.tencent.devops.auth.pojo.enum.JoinedType +import com.tencent.devops.auth.pojo.enum.OperateChannel import com.tencent.devops.auth.pojo.enum.RemoveMemberButtonControl +import com.tencent.devops.auth.pojo.request.GroupMemberCommonConditionReq +import com.tencent.devops.auth.pojo.request.GroupMemberHandoverConditionReq +import com.tencent.devops.auth.pojo.request.GroupMemberRenewalConditionReq +import com.tencent.devops.auth.pojo.request.GroupMemberSingleRenewalReq import com.tencent.devops.auth.pojo.request.ProjectMembersQueryConditionReq +import com.tencent.devops.auth.pojo.request.RemoveMemberFromProjectReq +import com.tencent.devops.auth.pojo.vo.BatchOperateGroupMemberCheckVo import com.tencent.devops.auth.pojo.vo.GroupDetailsInfoVo import com.tencent.devops.auth.pojo.vo.MemberGroupCountWithPermissionsVo import com.tencent.devops.auth.service.DeptService +import com.tencent.devops.auth.service.PermissionAuthorizationService import com.tencent.devops.auth.service.iam.PermissionResourceGroupAndMemberFacadeService import com.tencent.devops.auth.service.iam.PermissionResourceGroupPermissionService import com.tencent.devops.auth.service.iam.PermissionResourceGroupService +import com.tencent.devops.auth.service.iam.PermissionResourceGroupSyncService import com.tencent.devops.auth.service.iam.PermissionResourceMemberService +import com.tencent.devops.common.api.exception.ErrorCodeException import com.tencent.devops.common.api.model.SQLPage import com.tencent.devops.common.api.util.DateTimeUtil +import com.tencent.devops.common.api.util.timestamp import com.tencent.devops.common.api.util.timestampmilli +import com.tencent.devops.common.auth.api.ActionId import com.tencent.devops.common.auth.api.AuthResourceType +import com.tencent.devops.common.auth.api.ResourceTypeId +import com.tencent.devops.common.auth.api.pojo.ResetAllResourceAuthorizationReq +import com.tencent.devops.common.auth.api.pojo.ResourceAuthorizationConditionRequest +import com.tencent.devops.common.service.utils.RetryUtils import com.tencent.devops.common.web.utils.I18nUtil import com.tencent.devops.model.auth.tables.records.TAuthResourceGroupRecord import org.jooq.DSLContext import org.slf4j.LoggerFactory +import java.util.concurrent.CompletableFuture +import java.util.concurrent.Executors import java.util.concurrent.TimeUnit class RbacPermissionResourceGroupAndMemberFacadeServiceImpl( @@ -39,7 +61,10 @@ class RbacPermissionResourceGroupAndMemberFacadeServiceImpl( private val dslContext: DSLContext, private val deptService: DeptService, private val iamV2ManagerService: V2ManagerService, - private val rbacCacheService: RbacCacheService + private val rbacCacheService: RbacCacheService, + private val authAuthorizationDao: AuthAuthorizationDao, + private val syncIamGroupMemberService: PermissionResourceGroupSyncService, + private val permissionAuthorizationService: PermissionAuthorizationService ) : PermissionResourceGroupAndMemberFacadeService { override fun getMemberGroupsDetails( projectId: String, @@ -52,6 +77,7 @@ class RbacPermissionResourceGroupAndMemberFacadeServiceImpl( relatedResourceType: String?, relatedResourceCode: String?, action: String?, + operateChannel: OperateChannel?, start: Int?, limit: Int? ): SQLPage { @@ -66,14 +92,15 @@ class RbacPermissionResourceGroupAndMemberFacadeServiceImpl( action = action ) ) - // 查询成员所在资源用户组列表,直接加入+通过用户组(模板)加入 - val (count, resourceGroupMembers) = permissionResourceMemberService.listResourceGroupMembers( + // 查询成员所在资源用户组列表 + val (count, resourceGroupMembers) = listResourceGroupMembers( projectCode = projectId, memberId = memberId, resourceType = resourceType, iamGroupIds = iamGroupIdsByConditions, minExpiredAt = minExpiredAt, maxExpiredAt = maxExpiredAt, + operateChannel = operateChannel, start = start, limit = limit ) @@ -219,6 +246,7 @@ class RbacPermissionResourceGroupAndMemberFacadeServiceImpl( }, joinedType = when (authResourceGroupMember.memberType) { ManagerScopesEnum.getType(ManagerScopesEnum.TEMPLATE) -> JoinedType.TEMPLATE + ManagerScopesEnum.getType(ManagerScopesEnum.DEPARTMENT) -> JoinedType.DEPARTMENT else -> JoinedType.DIRECT }, operator = "" @@ -233,7 +261,8 @@ class RbacPermissionResourceGroupAndMemberFacadeServiceImpl( maxExpiredAt: Long?, relatedResourceType: String?, relatedResourceCode: String?, - action: String? + action: String?, + operateChannel: OperateChannel? ): List { // 查询项目下包含该成员的组列表 val projectGroupIds = authResourceGroupMemberDao.listResourceGroupMember( @@ -249,6 +278,16 @@ class RbacPermissionResourceGroupAndMemberFacadeServiceImpl( iamGroupIds = projectGroupIds ).filter { it.iamTemplateId != null } .map { it.iamTemplateId.toString() } + // 获取用户部门信息 + val memberDeptInfos = if (operateChannel == OperateChannel.PERSONAL) { + deptService.getUserInfo( + userId = "admin", + name = memberId + )?.deptInfo ?: return emptyList() + deptService.getUserDeptInfo(memberId).toList() + } else { + emptyList() + } val iamGroupIdsByConditions = listIamGroupIdsByConditions( condition = IamGroupIdsQueryConditionDTO( @@ -259,7 +298,7 @@ class RbacPermissionResourceGroupAndMemberFacadeServiceImpl( action = action ) ) - // 获取成员直接加入的组和通过模板加入的组 + // 获取成员加入的用户组 val memberGroupCountMap = authResourceGroupMemberDao.countMemberGroup( dslContext = dslContext, projectCode = projectCode, @@ -267,7 +306,8 @@ class RbacPermissionResourceGroupAndMemberFacadeServiceImpl( iamTemplateIds = iamTemplateId, iamGroupIds = iamGroupIdsByConditions, minExpiredAt = minExpiredAt?.let { DateTimeUtil.convertTimestampToLocalDateTime(it / 1000) }, - maxExpiredAt = maxExpiredAt?.let { DateTimeUtil.convertTimestampToLocalDateTime(it / 1000) } + maxExpiredAt = maxExpiredAt?.let { DateTimeUtil.convertTimestampToLocalDateTime(it / 1000) }, + memberDeptInfos = memberDeptInfos ) val memberGroupCountList = mutableListOf() // 项目排在第一位 @@ -328,6 +368,196 @@ class RbacPermissionResourceGroupAndMemberFacadeServiceImpl( } } + override fun listMemberGroupIdsInProject( + projectCode: String, + memberId: String + ): List { + // 获取用户加入的项目级用户组模板ID + val iamTemplateIds = listProjectMemberGroupTemplateIds( + projectCode = projectCode, + memberId = memberId + ) + return authResourceGroupMemberDao.listMemberGroupIdsInProject( + dslContext = dslContext, + projectCode = projectCode, + memberId = memberId, + iamTemplateIds = iamTemplateIds + ) + } + + @Suppress("LongParameterList") + override fun listResourceGroupMembers( + projectCode: String, + memberId: String, + resourceType: String?, + iamGroupIds: List?, + excludeIamGroupIds: List?, + minExpiredAt: Long?, + maxExpiredAt: Long?, + operateChannel: OperateChannel?, + start: Int?, + limit: Int? + ): Pair> { + // 获取用户加入的项目级用户组模板ID + val iamTemplateIds = listProjectMemberGroupTemplateIds( + projectCode = projectCode, + memberId = memberId + ) + // 获取用户所属组织 + val memberDeptInfos = if (operateChannel == OperateChannel.PERSONAL) { + getMemberDeptInfos(memberId) + } else { + emptyList() + } + + val minExpiredTime = minExpiredAt?.let { DateTimeUtil.convertTimestampToLocalDateTime(it / 1000) } + val maxExpiredTime = maxExpiredAt?.let { DateTimeUtil.convertTimestampToLocalDateTime(it / 1000) } + val count = authResourceGroupMemberDao.countMemberGroup( + dslContext = dslContext, + projectCode = projectCode, + memberId = memberId, + iamTemplateIds = iamTemplateIds, + resourceType = resourceType, + iamGroupIds = iamGroupIds, + excludeIamGroupIds = excludeIamGroupIds, + minExpiredAt = minExpiredTime, + maxExpiredAt = maxExpiredTime, + memberDeptInfos = memberDeptInfos + )[resourceType] ?: 0L + val resourceGroupMembers = authResourceGroupMemberDao.listMemberGroupDetail( + dslContext = dslContext, + projectCode = projectCode, + memberId = memberId, + iamTemplateIds = iamTemplateIds, + resourceType = resourceType, + iamGroupIds = iamGroupIds, + excludeIamGroupIds = excludeIamGroupIds, + minExpiredAt = minExpiredTime, + maxExpiredAt = maxExpiredTime, + memberDeptInfos = memberDeptInfos, + offset = start, + limit = limit + ) + return Pair(count, resourceGroupMembers) + } + + // 获取用户加入的项目级用户组模板ID + private fun listProjectMemberGroupTemplateIds( + projectCode: String, + memberId: String + ): List { + // 查询项目下包含该成员的组列表 + val projectGroupIds = authResourceGroupMemberDao.listResourceGroupMember( + dslContext = dslContext, + projectCode = projectCode, + resourceType = AuthResourceType.PROJECT.value, + memberId = memberId + ).map { it.iamGroupId.toString() } + // 通过项目组ID获取人员模板ID + return authResourceGroupDao.listByRelationId( + dslContext = dslContext, + projectCode = projectCode, + iamGroupIds = projectGroupIds + ).filter { it.iamTemplateId != null } + .map { it.iamTemplateId.toString() } + } + + private fun getMemberDeptInfos( + memberId: String + ): List { + deptService.getUserInfo( + userId = "admin", + name = memberId + )?.deptInfo ?: return emptyList() + return deptService.getUserDeptInfo(memberId).toList() + } + + private fun getGroupIdsByGroupMemberCondition( + projectCode: String, + commonCondition: GroupMemberCommonConditionReq + ): Map> { + val finalResourceGroupMembers = mutableListOf() + with(commonCondition) { + // 1.根据条件筛选出用户组 + val resourceGroupMembersByCondition = when { + // 全选 + allSelection -> { + listResourceGroupMembers( + projectCode = projectCode, + memberId = commonCondition.targetMember.id, + operateChannel = commonCondition.operateChannel + ).second + } + // 全选某些资源类型用户组 + resourceTypes.isNotEmpty() -> { + resourceTypes.flatMap { resourceType -> + listResourceGroupMembers( + projectCode = projectCode, + memberId = commonCondition.targetMember.id, + resourceType = resourceType, + operateChannel = commonCondition.operateChannel + ).second + } + } + + else -> { + emptyList() + } + } + + if (resourceGroupMembersByCondition.isNotEmpty()) { + finalResourceGroupMembers.addAll(resourceGroupMembersByCondition) + } + + if (groupIds.isNotEmpty()) { + val resourceGroupMembersOfSelect = listResourceGroupMembers( + projectCode = projectCode, + memberId = commonCondition.targetMember.id, + iamGroupIds = groupIds + ).second + finalResourceGroupMembers.addAll(resourceGroupMembersOfSelect) + } + + // 2.进行分类,直接/模板/部门加入 + val groupIdsOfDirectJoined = finalResourceGroupMembers.filter { + it.memberType == ManagerScopesEnum.getType(ManagerScopesEnum.TEMPLATE) + }.map { it.iamGroupId }.toMutableList() + + val groupInfoIdsOfTemplateJoined = finalResourceGroupMembers.filter { + it.memberType == ManagerScopesEnum.getType(ManagerScopesEnum.USER) + }.map { it.iamGroupId }.toMutableList() + + val groupInfoIdsOfDepartmentJoined = finalResourceGroupMembers.filter { + it.memberType == ManagerScopesEnum.getType(ManagerScopesEnum.DEPARTMENT) + }.map { it.iamGroupId }.toMutableList() + + // 3.根据条件排除用户组。 + // 3.1 排除唯一管理组(将用户移出用户组时,需进行排除) + if (excludedUniqueManagerGroup) { + val excludedUniqueManagerGroupIds = authResourceGroupMemberDao.listProjectUniqueManagerGroups( + dslContext = dslContext, + projectCode = projectCode, + iamGroupIds = groupIdsOfDirectJoined + ) + groupIdsOfDirectJoined.removeAll { + excludedUniqueManagerGroupIds.contains(it) + } + } + // 4.组装返回结果。 + val result = mutableMapOf>() + if (groupIdsOfDirectJoined.isNotEmpty()) { + result[ManagerScopesEnum.USER] = groupIdsOfDirectJoined + } + if (groupInfoIdsOfTemplateJoined.isNotEmpty()) { + result[ManagerScopesEnum.TEMPLATE] = groupInfoIdsOfTemplateJoined + } + if (groupInfoIdsOfDepartmentJoined.isNotEmpty()) { + result[ManagerScopesEnum.DEPARTMENT] = groupInfoIdsOfTemplateJoined + } + return result + } + } + override fun listProjectMembersByComplexConditions( conditionReq: ProjectMembersQueryConditionReq ): SQLPage { @@ -414,9 +644,656 @@ class RbacPermissionResourceGroupAndMemberFacadeServiceImpl( } } + override fun listInvalidAuthorizationsAfterOperatedGroups( + projectCode: String, + iamGroupIds: List, + memberId: String + ): Pair, List> { + logger.info("list invalid authorizations after operated groups:$projectCode|$iamGroupIds|$memberId") + deptService.getUserInfo(memberId, memberId) ?: return Pair(emptyList(), emptyList()) + // 1.筛选出本次退出/交接中包含流水线执行权限的用户组 + val operatedGroupsWithExecutePerm = groupPermissionService.listGroupsByPermissionConditions( + projectCode = projectCode, + relatedResourceType = AuthResourceType.PIPELINE_DEFAULT.value, + action = ActionId.PIPELINE_EXECUTE, + filterIamGroupIds = iamGroupIds + ) + logger.debug("list operated groups with execute perm:{}", operatedGroupsWithExecutePerm) + + // 2.获取用户退出/交接以上操作的用户组后,还未退出的流水线/项目级别(仅这些类型会包含流水线执行权限)的用户组。 + val userGroupsJoinedAfterOperatedGroups = listResourceGroupMembers( + projectCode = projectCode, + memberId = memberId, + resourceType = ResourceTypeId.PIPELINE, + excludeIamGroupIds = operatedGroupsWithExecutePerm + ).second.toMutableList().apply { + addAll( + listResourceGroupMembers( + projectCode = projectCode, + memberId = memberId, + resourceType = ResourceTypeId.PROJECT, + excludeIamGroupIds = operatedGroupsWithExecutePerm + ).second + ) + }.map { it.iamGroupId } + logger.debug("list user groups joined after operated groups:{}", userGroupsJoinedAfterOperatedGroups) + // 3.查询未退出的流水线/项目级别的用户组中是否包含项目级别的流水线执行权限。 + // 查询用户在未退出的用户组中否还有整个项目的流水线执行权限。若有的话,则对流水线的代持人权限未造成影响。 + val hasAllPipelineExecutePermAfterOperateGroups = groupPermissionService.isGroupsHasProjectLevelPermission( + projectCode = projectCode, + filterIamGroupIds = userGroupsJoinedAfterOperatedGroups, + action = ActionId.PIPELINE_EXECUTE + ) + logger.debug("has all pipeline execute perm after operate groups:{}", hasAllPipelineExecutePermAfterOperateGroups) + + // 3.1.若用户在未退出的组中拥有整个项目的流水线执行权限,则本次不会对任何的流水线代持人权限造成影响。 + if (hasAllPipelineExecutePermAfterOperateGroups) + return Pair(emptyList(), emptyList()) + + // 3.2.若没有的话,查询本次退出/交接的用户组中是否包含项目级别的流水线执行权限。 + val hasAllPipelineExecutePermInOperateGroups = groupPermissionService.isGroupsHasProjectLevelPermission( + projectCode = projectCode, + filterIamGroupIds = operatedGroupsWithExecutePerm, + action = ActionId.PIPELINE_EXECUTE + ) + logger.debug("has all pipeline execute perm in operate groups:{}", hasAllPipelineExecutePermInOperateGroups) + + val pipelinesWithoutAuthorization = if (hasAllPipelineExecutePermInOperateGroups) { + // 3.2.1 如果本次退出/交接的用户组中包含项目级别的流水线执行权限, + // 那么查询出用户还有执行流水线权限的流水线,该项目下除了这些流水线,其他的流水线代持人权限都会失效。 + val userHasExecutePermAfterOperatedGroups = groupPermissionService.listGroupResourcesWithPermission( + projectCode = projectCode, + filterIamGroupIds = userGroupsJoinedAfterOperatedGroups, + relatedResourceType = ResourceTypeId.PIPELINE, + action = ActionId.PIPELINE_EXECUTE + )[ResourceTypeId.PIPELINE] ?: emptyList() + logger.debug("user has execute perm after operated groups:{}", userHasExecutePermAfterOperatedGroups) + // 失去代持人权限的流水线 + authAuthorizationDao.list( + dslContext = dslContext, + condition = ResourceAuthorizationConditionRequest( + projectCode = projectCode, + resourceType = ResourceTypeId.PIPELINE, + handoverFrom = memberId, + excludeResourceCodes = userHasExecutePermAfterOperatedGroups + ) + ).map { it.resourceCode } + } else { + // 3.2.2 如果本次退出/交接的用户组中不包含整个项目的流水线执行权限。 + // 通过计算得出,用户本次操作用户组,导致失去流水线执行权限的流水线。 + // 然后再计算失去这些流水线执行权限后,会导致哪些流水线的代持人权限失效。 + val pipelinesWithExecutePermAfterOperatedGroups = groupPermissionService.listGroupResourcesWithPermission( + projectCode = projectCode, + filterIamGroupIds = userGroupsJoinedAfterOperatedGroups, + relatedResourceType = ResourceTypeId.PIPELINE, + action = ActionId.PIPELINE_EXECUTE + )[ResourceTypeId.PIPELINE] ?: emptyList() + logger.debug("pipelines with execute perm after operate groups:{}", pipelinesWithExecutePermAfterOperatedGroups) + + val pipelinesWithExecutePermInOperateGroups = groupPermissionService.listGroupResourcesWithPermission( + projectCode = projectCode, + filterIamGroupIds = operatedGroupsWithExecutePerm, + relatedResourceType = ResourceTypeId.PIPELINE, + action = ActionId.PIPELINE_EXECUTE + )[ResourceTypeId.PIPELINE] ?: emptyList() + logger.debug("pipelines with execute perm in operate groups:{}", pipelinesWithExecutePermInOperateGroups) + + val pipelineExecutePermLostFromUser = pipelinesWithExecutePermInOperateGroups.filterNot { + pipelinesWithExecutePermAfterOperatedGroups.contains(it) + } + // 失去代持人权限的流水线 + authAuthorizationDao.list( + dslContext = dslContext, + condition = ResourceAuthorizationConditionRequest( + projectCode = projectCode, + resourceType = ResourceTypeId.PIPELINE, + handoverFrom = memberId, + filterResourceCodes = pipelineExecutePermLostFromUser + ) + ).map { it.resourceCode } + } + logger.debug("pipelines without authorization:{}", pipelinesWithoutAuthorization) + if (pipelinesWithoutAuthorization.isNotEmpty()) { + return Pair(operatedGroupsWithExecutePerm, pipelinesWithoutAuthorization) + } + return Pair(emptyList(), emptyList()) + } + + override fun renewalGroupMember( + userId: String, + projectCode: String, + renewalConditionReq: GroupMemberSingleRenewalReq + ): Boolean { + logger.info("renewal group member $userId|$projectCode|$renewalConditionReq") + val groupId = renewalConditionReq.groupId + batchOperateGroupMembers( + projectCode = projectCode, + conditionReq = GroupMemberRenewalConditionReq( + groupIds = listOf(groupId), + targetMember = renewalConditionReq.targetMember, + renewalDuration = renewalConditionReq.renewalDuration + ), + operateGroupMemberTask = ::renewalTask + ) + return true + } + + private fun renewalTask( + projectCode: String, + groupId: Int, + renewalConditionReq: GroupMemberRenewalConditionReq, + expiredAt: Long + ) { + logger.info("renewal group member ${renewalConditionReq.targetMember}|$projectCode|$groupId|$expiredAt") + val targetMember = renewalConditionReq.targetMember + if (targetMember.type == ManagerScopesEnum.getType(ManagerScopesEnum.USER) && + deptService.isUserDeparted(targetMember.id)) { + return + } + val secondsOfRenewalDuration = TimeUnit.DAYS.toSeconds(renewalConditionReq.renewalDuration.toLong()) + val secondsOfCurrentTime = System.currentTimeMillis() / 1000 + // 若权限已过期,则为当前时间+续期天数,若未过期,则为有效期+续期天数 + val finalExpiredAt = if (expiredAt < secondsOfCurrentTime) { + secondsOfCurrentTime + } else { + expiredAt + } + secondsOfRenewalDuration + if (!isNeedToRenewal(finalExpiredAt)) { + return + } + permissionResourceMemberService.renewalIamGroupMembers( + groupId = groupId, + members = listOf(ManagerMember(targetMember.type, targetMember.id)), + expiredAt = finalExpiredAt + ) + authResourceGroupMemberDao.update( + dslContext = dslContext, + projectCode = projectCode, + iamGroupId = groupId, + expiredTime = DateTimeUtil.convertTimestampToLocalDateTime(finalExpiredAt), + memberId = targetMember.id + ) + } + + private fun isNeedToRenewal(expiredAt: Long): Boolean { + return expiredAt < PERMANENT_EXPIRED_TIME + } + + override fun batchRenewalGroupMembersFromManager( + userId: String, + projectCode: String, + renewalConditionReq: GroupMemberRenewalConditionReq + ): Boolean { + logger.info("batch renewal group member $userId|$projectCode|$renewalConditionReq") + batchOperateGroupMembers( + projectCode = projectCode, + conditionReq = renewalConditionReq, + operateGroupMemberTask = ::renewalTask + ) + return true + } + + override fun batchHandoverGroupMembersFromManager( + userId: String, + projectCode: String, + handoverMemberDTO: GroupMemberHandoverConditionReq + ): Boolean { + logger.info("batch handover group members $userId|$projectCode|$handoverMemberDTO") + handoverMemberDTO.checkHandoverTo() + batchOperateGroupMembers( + projectCode = projectCode, + conditionReq = handoverMemberDTO, + operateGroupMemberTask = ::handoverTask + ) + return true + } + + override fun batchDeleteResourceGroupMembersFromManager( + userId: String, + projectCode: String, + removeMemberDTO: GroupMemberCommonConditionReq + ): Boolean { + logger.info("batch delete group members $userId|$projectCode|$removeMemberDTO") + removeMemberDTO.excludedUniqueManagerGroup = true + batchOperateGroupMembers( + projectCode = projectCode, + conditionReq = removeMemberDTO, + operateGroupMemberTask = ::deleteTask + ) + return true + } + + private fun handoverTask( + projectCode: String, + groupId: Int, + handoverMemberDTO: GroupMemberHandoverConditionReq, + expiredAt: Long + ) { + logger.info( + "handover group member $projectCode|$groupId|" + + "${handoverMemberDTO.targetMember}|${handoverMemberDTO.handoverTo}" + ) + val currentTimeSeconds = System.currentTimeMillis() / 1000 + var finalExpiredAt = expiredAt + when { + // 若权限已过期,如果是唯一管理员组,允许交接,交接人将获得半年权限;其他的直接删除。 + expiredAt < currentTimeSeconds -> { + val isUniqueManagerGroup = authResourceGroupMemberDao.listProjectUniqueManagerGroups( + dslContext = dslContext, + projectCode = projectCode, + iamGroupIds = listOf(groupId) + ).isNotEmpty() + if (isUniqueManagerGroup) { + finalExpiredAt = currentTimeSeconds + TimeUnit.DAYS.toSeconds(180) + } else { + deleteTask( + projectCode = projectCode, + groupId = groupId, + removeMemberDTO = GroupMemberCommonConditionReq( + targetMember = handoverMemberDTO.targetMember + ), + expiredAt = finalExpiredAt + ) + return + } + } + // 若交接人已经在用户组内,无需交接。 + authResourceGroupMemberDao.isMemberInGroup( + dslContext = dslContext, + projectCode = projectCode, + iamGroupId = groupId, + memberId = handoverMemberDTO.handoverTo.id + ) -> { + deleteTask( + projectCode = projectCode, + groupId = groupId, + removeMemberDTO = GroupMemberCommonConditionReq( + targetMember = handoverMemberDTO.targetMember + ), + expiredAt = finalExpiredAt + ) + return + } + } + + val members = listOf( + ManagerMember( + handoverMemberDTO.handoverTo.type, + handoverMemberDTO.handoverTo.id + ) + ) + if (finalExpiredAt < currentTimeSeconds) { + throw ErrorCodeException( + errorCode = AuthMessageCode.INVALID_EXPIRED_PERM_NOT_ALLOW_TO_HANDOVER + ) + } + + permissionResourceMemberService.addIamGroupMember( + groupId = groupId, + members = members, + expiredAt = finalExpiredAt + ) + permissionResourceMemberService.deleteIamGroupMembers( + groupId = groupId, + type = handoverMemberDTO.targetMember.type, + memberIds = listOf(handoverMemberDTO.targetMember.id) + ) + authResourceGroupMemberDao.handoverGroupMembers( + dslContext = dslContext, + projectCode = projectCode, + iamGroupId = groupId, + handoverFrom = handoverMemberDTO.targetMember, + handoverTo = handoverMemberDTO.handoverTo, + expiredTime = DateTimeUtil.convertTimestampToLocalDateTime(finalExpiredAt) + ) + } + + private fun deleteTask( + projectCode: String, + groupId: Int, + removeMemberDTO: GroupMemberCommonConditionReq, + expiredAt: Long + ) { + val targetMember = removeMemberDTO.targetMember + logger.info("delete group member $projectCode|$groupId|$targetMember") + permissionResourceMemberService.deleteIamGroupMembers( + groupId = groupId, + type = targetMember.type, + memberIds = listOf(targetMember.id) + ) + authResourceGroupMemberDao.batchDeleteGroupMembers( + dslContext = dslContext, + projectCode = projectCode, + iamGroupId = groupId, + memberIds = listOf(removeMemberDTO.targetMember.id) + ) + } + + override fun batchOperateGroupMembersCheck( + userId: String, + projectCode: String, + batchOperateType: BatchOperateType, + conditionReq: GroupMemberCommonConditionReq + ): BatchOperateGroupMemberCheckVo { + logger.info("batch operate group member check|$userId|$projectCode|$batchOperateType|$conditionReq") + // 获取用户加入的用户组 + val joinedType2GroupIds = getGroupIdsByGroupMemberCondition( + projectCode = projectCode, + commonCondition = conditionReq + ) + val groupIdsOfDirectJoined = joinedType2GroupIds[ManagerScopesEnum.USER] ?: emptyList() + val groupInfoIdsOfTemplateJoined = joinedType2GroupIds[ManagerScopesEnum.TEMPLATE] ?: emptyList() + + val totalCount = groupIdsOfDirectJoined.size + groupInfoIdsOfTemplateJoined.size + val groupCountOfTemplateJoined = groupInfoIdsOfTemplateJoined.size + + return when (batchOperateType) { + BatchOperateType.REMOVE -> { + val groupCountOfUniqueManager = authResourceGroupMemberDao.listProjectUniqueManagerGroups( + dslContext = dslContext, + projectCode = projectCode, + iamGroupIds = groupIdsOfDirectJoined + ).size + BatchOperateGroupMemberCheckVo( + totalCount = totalCount, + inoperableCount = groupCountOfUniqueManager + groupCountOfTemplateJoined + ) + } + + BatchOperateType.RENEWAL -> { + with(conditionReq) { + val isUserDeparted = targetMember.type == ManagerScopesEnum.getType(ManagerScopesEnum.USER) && + deptService.isUserDeparted(targetMember.id) + // 离职用户不允许续期 + if (isUserDeparted) { + BatchOperateGroupMemberCheckVo( + totalCount = totalCount, + inoperableCount = totalCount + ) + } else { + // 永久期限 不允许再续期 + val groupCountOfPermanentExpiredTime = listMemberGroupsDetails( + projectCode = projectCode, + memberId = targetMember.id, + memberType = targetMember.type, + groupIds = groupIdsOfDirectJoined + ).filter { + // iam用的是秒级时间戳 + it.expiredAt == PERMANENT_EXPIRED_TIME / 1000 + }.size + BatchOperateGroupMemberCheckVo( + totalCount = totalCount, + inoperableCount = groupCountOfPermanentExpiredTime + groupCountOfTemplateJoined + ) + } + } + } + + BatchOperateType.HANDOVER -> { + // 已过期(除唯一管理员组)或通过模板加入的不允许移交 + with(conditionReq) { + val finalGroupIds = groupIdsOfDirectJoined.toMutableList() + val uniqueManagerGroupIds = authResourceGroupMemberDao.listProjectUniqueManagerGroups( + dslContext = dslContext, + projectCode = projectCode, + iamGroupIds = groupIdsOfDirectJoined + ) + // 去除唯一管理员组 + if (uniqueManagerGroupIds.isNotEmpty()) { + finalGroupIds.removeAll(uniqueManagerGroupIds) + } + val groupCountOfExpired = listMemberGroupsDetails( + projectCode = projectCode, + memberId = targetMember.id, + memberType = targetMember.type, + groupIds = finalGroupIds + ).filter { + // iam用的是秒级时间戳 + it.expiredAt < System.currentTimeMillis() / 1000 + }.size + BatchOperateGroupMemberCheckVo( + totalCount = totalCount, + inoperableCount = groupCountOfTemplateJoined + groupCountOfExpired + ) + } + } + + else -> { + BatchOperateGroupMemberCheckVo( + totalCount = totalCount, + inoperableCount = groupCountOfTemplateJoined + ) + } + } + } + + override fun removeMemberFromProject( + userId: String, + projectCode: String, + removeMemberFromProjectReq: RemoveMemberFromProjectReq + ): List { + logger.info("remove member from project $userId|$projectCode|$removeMemberFromProjectReq") + return with(removeMemberFromProjectReq) { + val memberType = targetMember.type + val isNeedToHandover = handoverTo != null + if (memberType == ManagerScopesEnum.getType(ManagerScopesEnum.USER) && isNeedToHandover) { + removeMemberFromProjectReq.checkHandoverTo() + val handoverMemberDTO = GroupMemberHandoverConditionReq( + allSelection = true, + targetMember = targetMember, + handoverTo = handoverTo!! + ) + batchOperateGroupMembers( + projectCode = projectCode, + conditionReq = handoverMemberDTO, + operateGroupMemberTask = ::handoverTask + ) + permissionAuthorizationService.resetAllResourceAuthorization( + operator = userId, + projectCode = projectCode, + condition = ResetAllResourceAuthorizationReq( + projectCode = projectCode, + handoverFrom = removeMemberFromProjectReq.targetMember.id, + handoverTo = removeMemberFromProjectReq.handoverTo!!.id, + preCheck = false, + checkPermission = false + ) + ) + } else { + val removeMemberDTO = GroupMemberCommonConditionReq( + allSelection = true, + targetMember = targetMember + ) + batchOperateGroupMembers( + projectCode = projectCode, + conditionReq = removeMemberDTO, + operateGroupMemberTask = ::deleteTask + ) + } + + if (memberType == ManagerScopesEnum.getType(ManagerScopesEnum.USER)) { + // 查询用户还存在那些组织中 + val userDeptInfos = deptService.getUserInfo( + userId = "admin", + name = targetMember.id + )?.deptInfo?.map { it.name!! } + if (userDeptInfos != null) { + return authResourceGroupMemberDao.isMembersInProject( + dslContext = dslContext, + projectCode = projectCode, + memberNames = userDeptInfos, + memberType = ManagerScopesEnum.getType(ManagerScopesEnum.DEPARTMENT) + ) + } + } + return emptyList() + } + } + + override fun removeMemberFromProjectCheck( + userId: String, + projectCode: String, + removeMemberFromProjectReq: RemoveMemberFromProjectReq + ): Boolean { + val targetMember = removeMemberFromProjectReq.targetMember + val isMemberHasNoPermission = batchOperateGroupMembersCheck( + userId = userId, + projectCode = projectCode, + batchOperateType = BatchOperateType.HANDOVER, + conditionReq = GroupMemberCommonConditionReq( + allSelection = true, + targetMember = removeMemberFromProjectReq.targetMember + ) + ).let { it.totalCount == it.inoperableCount } + + val isMemberHasNoAuthorizations = + if (targetMember.type == ManagerScopesEnum.getType(ManagerScopesEnum.USER)) { + permissionAuthorizationService.listResourceAuthorizations( + condition = ResourceAuthorizationConditionRequest( + projectCode = projectCode, + handoverFrom = targetMember.id + ) + ).count == 0L + } else { + true + } + return isMemberHasNoPermission && isMemberHasNoAuthorizations + } + + private fun batchOperateGroupMembers( + projectCode: String, + conditionReq: T, + operateGroupMemberTask: ( + projectCode: String, + groupId: Int, + conditionReq: T, + expiredAt: Long + ) -> Unit + ): Boolean { + // 直接加入的组 + val groupIds = getGroupIdsByGroupMemberCondition( + projectCode = projectCode, + commonCondition = conditionReq + )[ManagerScopesEnum.USER] + if (groupIds.isNullOrEmpty()) { + return true + } + + val targetMember = conditionReq.targetMember + val memberGroupsDetailsList = listMemberGroupsDetails( + projectCode = projectCode, + memberId = targetMember.id, + memberType = targetMember.type, + groupIds = groupIds + ) + val outOfSyncGroupIds = mutableListOf() + val futures = groupIds.map { groupId -> + CompletableFuture.supplyAsync( + { + val memberGroupsDetails = memberGroupsDetailsList.firstOrNull { it.id == groupId } + if (memberGroupsDetails == null) { + logger.warn( + "The data is out of sync, and the record no longer exists in the iam.$groupId" + ) + outOfSyncGroupIds.add(groupId) + return@supplyAsync + } + val expiredAt = memberGroupsDetails.expiredAt + RetryUtils.retry(3) { + operateGroupMemberTask.invoke( + projectCode, + groupId, + conditionReq, + expiredAt + ) + } + }, executorService + ) + } + handleFutures( + projectCode = projectCode, + outOfSyncGroupIds = outOfSyncGroupIds, + futures = futures + ) + return true + } + + private fun listMemberGroupsDetails( + projectCode: String, + memberId: String, + memberType: String, + groupIds: List + ): List { + val memberGroupsDetailsList = mutableListOf() + val groupIdsChunk = groupIds.chunked(100) + val futures = groupIdsChunk.map { + CompletableFuture.supplyAsync( + { + memberGroupsDetailsList.addAll( + // 若离职,则从数据库获取用户加入组的过期时间,调用iam接口会报错。 + // 虽然数据库的过期时间可能不是最新的。 + if (memberType == ManagerScopesEnum.getType(ManagerScopesEnum.USER) && + deptService.isUserDeparted(userId = memberId)) { + val records = authResourceGroupMemberDao.listMemberGroupDetail( + dslContext = dslContext, + projectCode = projectCode, + memberId = memberId, + iamTemplateIds = emptyList(), + iamGroupIds = it + ) + records.map { record -> + MemberGroupDetailsResponse().apply { + id = record.iamGroupId + expiredAt = record.expiredTime.timestamp() + } + } + } else { + iamV2ManagerService.listMemberGroupsDetails( + memberType, + memberId, + it.joinToString(",") + ) + } + ) + }, executorService + ) + } + try { + CompletableFuture.allOf(*futures.toTypedArray()).join() + } catch (ignore: Exception) { + logger.warn("list member groups details failed!$ignore") + throw ignore + } + return memberGroupsDetailsList + } + + private fun handleFutures( + projectCode: String, + outOfSyncGroupIds: List, + futures: List> + ) { + try { + CompletableFuture.allOf(*futures.toTypedArray()).join() + // 存在iam那边已经把用户组下成员删除,但蓝盾数据库未同步问题 + outOfSyncGroupIds.forEach { + syncIamGroupMemberService.syncIamGroupMember( + projectCode = projectCode, + iamGroupId = it + ) + } + } catch (ignore: Exception) { + logger.warn("batch operate group members failed", ignore) + throw ErrorCodeException( + errorCode = AuthMessageCode.ERROR_BATCH_OPERATE_GROUP_MEMBERS + ) + } + } + companion object { private val logger = LoggerFactory.getLogger(RbacPermissionResourceMemberService::class.java) + private val executorService = Executors.newFixedThreadPool(30) + // 永久过期时间 private const val PERMANENT_EXPIRED_TIME = 4102444800000L } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupPermissionService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupPermissionService.kt index eb461b5bbb5..128084b24ce 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupPermissionService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupPermissionService.kt @@ -295,6 +295,21 @@ class RbacPermissionResourceGroupPermissionService( ) } + override fun isGroupsHasProjectLevelPermission( + projectCode: String, + filterIamGroupIds: List, + action: String + ): Boolean { + val actionRelatedResourceType = rbacCacheService.getActionInfo(action).relatedResourceType + return resourceGroupPermissionDao.isGroupsHasProjectLevelPermission( + dslContext = dslContext, + projectCode = projectCode, + filterIamGroupIds = filterIamGroupIds, + actionRelatedResourceType = actionRelatedResourceType, + action = action + ) + } + override fun listGroupResourcesWithPermission( projectCode: String, filterIamGroupIds: List, diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceMemberService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceMemberService.kt index 401e717b46f..f93cf5cdc67 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceMemberService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceMemberService.kt @@ -8,7 +8,6 @@ import com.tencent.bk.sdk.iam.dto.manager.V2ManagerRoleGroupInfo import com.tencent.bk.sdk.iam.dto.manager.dto.GroupMemberRenewApplicationDTO import com.tencent.bk.sdk.iam.dto.manager.dto.ManagerMemberGroupDTO import com.tencent.bk.sdk.iam.dto.manager.dto.SearchGroupDTO -import com.tencent.bk.sdk.iam.dto.response.MemberGroupDetailsResponse import com.tencent.bk.sdk.iam.service.v2.V2ManagerService import com.tencent.devops.auth.constant.AuthMessageCode import com.tencent.devops.auth.dao.AuthResourceGroupDao @@ -16,36 +15,22 @@ import com.tencent.devops.auth.dao.AuthResourceGroupMemberDao import com.tencent.devops.auth.pojo.AuthResourceGroupMember import com.tencent.devops.auth.pojo.ResourceMemberInfo import com.tencent.devops.auth.pojo.dto.GroupMemberRenewalDTO -import com.tencent.devops.auth.pojo.enum.BatchOperateType import com.tencent.devops.auth.pojo.enum.MemberType -import com.tencent.devops.auth.pojo.request.GroupMemberCommonConditionReq -import com.tencent.devops.auth.pojo.request.GroupMemberHandoverConditionReq -import com.tencent.devops.auth.pojo.request.GroupMemberRenewalConditionReq -import com.tencent.devops.auth.pojo.request.GroupMemberSingleRenewalReq -import com.tencent.devops.auth.pojo.request.RemoveMemberFromProjectReq -import com.tencent.devops.auth.pojo.vo.BatchOperateGroupMemberCheckVo import com.tencent.devops.auth.pojo.vo.ResourceMemberCountVO import com.tencent.devops.auth.service.DeptService -import com.tencent.devops.auth.service.PermissionAuthorizationService -import com.tencent.devops.auth.service.iam.PermissionResourceGroupSyncService import com.tencent.devops.auth.service.iam.PermissionResourceMemberService import com.tencent.devops.common.api.exception.ErrorCodeException import com.tencent.devops.common.api.model.SQLPage import com.tencent.devops.common.api.util.DateTimeUtil import com.tencent.devops.common.api.util.PageUtil -import com.tencent.devops.common.api.util.timestamp import com.tencent.devops.common.auth.api.AuthResourceType import com.tencent.devops.common.auth.api.pojo.BkAuthGroup import com.tencent.devops.common.auth.api.pojo.BkAuthGroupAndUserList -import com.tencent.devops.common.auth.api.pojo.ResetAllResourceAuthorizationReq -import com.tencent.devops.common.auth.api.pojo.ResourceAuthorizationConditionRequest -import com.tencent.devops.common.service.utils.RetryUtils import com.tencent.devops.project.constant.ProjectMessageCode import org.apache.commons.lang3.RandomUtils import org.jooq.DSLContext import org.slf4j.LoggerFactory import java.time.LocalDateTime -import java.util.concurrent.CompletableFuture import java.util.concurrent.Executors import java.util.concurrent.TimeUnit @@ -56,9 +41,7 @@ class RbacPermissionResourceMemberService( private val authResourceGroupDao: AuthResourceGroupDao, private val authResourceGroupMemberDao: AuthResourceGroupMemberDao, private val dslContext: DSLContext, - private val deptService: DeptService, - private val permissionAuthorizationService: PermissionAuthorizationService, - private val syncIamGroupMemberService: PermissionResourceGroupSyncService + private val deptService: DeptService ) : PermissionResourceMemberService { override fun getResourceGroupMembers( projectCode: String, @@ -616,25 +599,6 @@ class RbacPermissionResourceMemberService( return true } - override fun renewalGroupMember( - userId: String, - projectCode: String, - renewalConditionReq: GroupMemberSingleRenewalReq - ): Boolean { - logger.info("renewal group member $userId|$projectCode|$renewalConditionReq") - val groupId = renewalConditionReq.groupId - batchOperateGroupMembers( - projectCode = projectCode, - conditionReq = GroupMemberRenewalConditionReq( - groupIds = listOf(groupId), - targetMember = renewalConditionReq.targetMember, - renewalDuration = renewalConditionReq.renewalDuration - ), - operateGroupMemberTask = ::renewalTask - ) - return true - } - override fun renewalIamGroupMembers( groupId: Int, members: List, @@ -653,76 +617,6 @@ class RbacPermissionResourceMemberService( return true } - override fun batchRenewalGroupMembers( - userId: String, - projectCode: String, - renewalConditionReq: GroupMemberRenewalConditionReq - ): Boolean { - logger.info("batch renewal group member $userId|$projectCode|$renewalConditionReq") - batchOperateGroupMembers( - projectCode = projectCode, - conditionReq = renewalConditionReq, - operateGroupMemberTask = ::renewalTask - ) - return true - } - - private fun renewalTask( - projectCode: String, - groupId: Int, - renewalConditionReq: GroupMemberRenewalConditionReq, - expiredAt: Long - ) { - logger.info("renewal group member ${renewalConditionReq.targetMember}|$projectCode|$groupId|$expiredAt") - val targetMember = renewalConditionReq.targetMember - if (targetMember.type == ManagerScopesEnum.getType(ManagerScopesEnum.USER) && - deptService.isUserDeparted(targetMember.id)) { - return - } - val secondsOfRenewalDuration = TimeUnit.DAYS.toSeconds(renewalConditionReq.renewalDuration.toLong()) - val secondsOfCurrentTime = System.currentTimeMillis() / 1000 - // 若权限已过期,则为当前时间+续期天数,若未过期,则为有效期+续期天数 - val finalExpiredAt = if (expiredAt < secondsOfCurrentTime) { - secondsOfCurrentTime - } else { - expiredAt - } + secondsOfRenewalDuration - if (!isNeedToRenewal(finalExpiredAt)) { - return - } - renewalIamGroupMembers( - groupId = groupId, - members = listOf(ManagerMember(targetMember.type, targetMember.id)), - expiredAt = finalExpiredAt - ) - authResourceGroupMemberDao.update( - dslContext = dslContext, - projectCode = projectCode, - iamGroupId = groupId, - expiredTime = DateTimeUtil.convertTimestampToLocalDateTime(finalExpiredAt), - memberId = targetMember.id - ) - } - - private fun isNeedToRenewal(expiredAt: Long): Boolean { - return expiredAt < PERMANENT_EXPIRED_TIME - } - - override fun batchDeleteResourceGroupMembers( - userId: String, - projectCode: String, - removeMemberDTO: GroupMemberCommonConditionReq - ): Boolean { - logger.info("batch delete group members $userId|$projectCode|$removeMemberDTO") - removeMemberDTO.excludedUniqueManagerGroup = true - batchOperateGroupMembers( - projectCode = projectCode, - conditionReq = removeMemberDTO, - operateGroupMemberTask = ::deleteTask - ) - return true - } - override fun deleteIamGroupMembers( groupId: Int, type: String, @@ -743,586 +637,6 @@ class RbacPermissionResourceMemberService( return true } - private fun deleteTask( - projectCode: String, - groupId: Int, - removeMemberDTO: GroupMemberCommonConditionReq, - expiredAt: Long - ) { - val targetMember = removeMemberDTO.targetMember - logger.info("delete group member $projectCode|$groupId|$targetMember") - deleteIamGroupMembers( - groupId = groupId, - type = targetMember.type, - memberIds = listOf(targetMember.id) - ) - authResourceGroupMemberDao.batchDeleteGroupMembers( - dslContext = dslContext, - projectCode = projectCode, - iamGroupId = groupId, - memberIds = listOf(removeMemberDTO.targetMember.id) - ) - } - - override fun batchHandoverGroupMembers( - userId: String, - projectCode: String, - handoverMemberDTO: GroupMemberHandoverConditionReq - ): Boolean { - logger.info("batch handover group members $userId|$projectCode|$handoverMemberDTO") - handoverMemberDTO.checkHandoverTo() - batchOperateGroupMembers( - projectCode = projectCode, - conditionReq = handoverMemberDTO, - operateGroupMemberTask = ::handoverTask - ) - return true - } - - override fun batchOperateGroupMembersCheck( - userId: String, - projectCode: String, - batchOperateType: BatchOperateType, - conditionReq: GroupMemberCommonConditionReq - ): BatchOperateGroupMemberCheckVo { - logger.info("batch operate group member check|$userId|$projectCode|$batchOperateType|$conditionReq") - // 获取用户加入的用户组 - val (groupIdsOfDirectJoined, groupInfoIdsOfTemplateJoined) = getGroupIdsByCondition( - projectCode = projectCode, - commonCondition = conditionReq - ) - val totalCount = groupIdsOfDirectJoined.size + groupInfoIdsOfTemplateJoined.size - val groupCountOfTemplateJoined = groupInfoIdsOfTemplateJoined.size - - return when (batchOperateType) { - BatchOperateType.REMOVE -> { - val groupCountOfUniqueManager = authResourceGroupMemberDao.listProjectUniqueManagerGroups( - dslContext = dslContext, - projectCode = projectCode, - iamGroupIds = groupIdsOfDirectJoined - ).size - BatchOperateGroupMemberCheckVo( - totalCount = totalCount, - inoperableCount = groupCountOfUniqueManager + groupCountOfTemplateJoined - ) - } - - BatchOperateType.RENEWAL -> { - with(conditionReq) { - val isUserDeparted = targetMember.type == ManagerScopesEnum.getType(ManagerScopesEnum.USER) && - deptService.isUserDeparted(targetMember.id) - // 离职用户不允许续期 - if (isUserDeparted) { - BatchOperateGroupMemberCheckVo( - totalCount = totalCount, - inoperableCount = totalCount - ) - } else { - // 永久期限 不允许再续期 - val groupCountOfPermanentExpiredTime = listMemberGroupsDetails( - projectCode = projectCode, - memberId = targetMember.id, - memberType = targetMember.type, - groupIds = groupIdsOfDirectJoined - ).filter { - // iam用的是秒级时间戳 - it.expiredAt == PERMANENT_EXPIRED_TIME / 1000 - }.size - BatchOperateGroupMemberCheckVo( - totalCount = totalCount, - inoperableCount = groupCountOfPermanentExpiredTime + groupCountOfTemplateJoined - ) - } - } - } - - BatchOperateType.HANDOVER -> { - // 已过期(除唯一管理员组)或通过模板加入的不允许移交 - with(conditionReq) { - val finalGroupIds = groupIdsOfDirectJoined.toMutableList() - val uniqueManagerGroupIds = authResourceGroupMemberDao.listProjectUniqueManagerGroups( - dslContext = dslContext, - projectCode = projectCode, - iamGroupIds = groupIdsOfDirectJoined - ) - // 去除唯一管理员组 - if (uniqueManagerGroupIds.isNotEmpty()) { - finalGroupIds.removeAll(uniqueManagerGroupIds) - } - val groupCountOfExpired = listMemberGroupsDetails( - projectCode = projectCode, - memberId = targetMember.id, - memberType = targetMember.type, - groupIds = finalGroupIds - ).filter { - // iam用的是秒级时间戳 - it.expiredAt < System.currentTimeMillis() / 1000 - }.size - BatchOperateGroupMemberCheckVo( - totalCount = totalCount, - inoperableCount = groupCountOfTemplateJoined + groupCountOfExpired - ) - } - } - - else -> { - BatchOperateGroupMemberCheckVo( - totalCount = totalCount, - inoperableCount = groupCountOfTemplateJoined - ) - } - } - } - - override fun removeMemberFromProject( - userId: String, - projectCode: String, - removeMemberFromProjectReq: RemoveMemberFromProjectReq - ): List { - logger.info("remove member from project $userId|$projectCode|$removeMemberFromProjectReq") - return with(removeMemberFromProjectReq) { - val memberType = targetMember.type - val isNeedToHandover = handoverTo != null - if (memberType == ManagerScopesEnum.getType(ManagerScopesEnum.USER) && isNeedToHandover) { - removeMemberFromProjectReq.checkHandoverTo() - val handoverMemberDTO = GroupMemberHandoverConditionReq( - allSelection = true, - targetMember = targetMember, - handoverTo = handoverTo!! - ) - batchOperateGroupMembers( - projectCode = projectCode, - conditionReq = handoverMemberDTO, - operateGroupMemberTask = ::handoverTask - ) - permissionAuthorizationService.resetAllResourceAuthorization( - operator = userId, - projectCode = projectCode, - condition = ResetAllResourceAuthorizationReq( - projectCode = projectCode, - handoverFrom = removeMemberFromProjectReq.targetMember.id, - handoverTo = removeMemberFromProjectReq.handoverTo!!.id, - preCheck = false, - checkPermission = false - ) - ) - } else { - val removeMemberDTO = GroupMemberCommonConditionReq( - allSelection = true, - targetMember = targetMember - ) - batchOperateGroupMembers( - projectCode = projectCode, - conditionReq = removeMemberDTO, - operateGroupMemberTask = ::deleteTask - ) - } - - if (memberType == ManagerScopesEnum.getType(ManagerScopesEnum.USER)) { - // 查询用户还存在那些组织中 - val userDeptInfos = deptService.getUserInfo( - userId = "admin", - name = targetMember.id - )?.deptInfo?.map { it.name!! } - if (userDeptInfos != null) { - return authResourceGroupMemberDao.isMembersInProject( - dslContext = dslContext, - projectCode = projectCode, - memberNames = userDeptInfos, - memberType = ManagerScopesEnum.getType(ManagerScopesEnum.DEPARTMENT) - ) - } - } - return emptyList() - } - } - - override fun removeMemberFromProjectCheck( - userId: String, - projectCode: String, - removeMemberFromProjectReq: RemoveMemberFromProjectReq - ): Boolean { - val targetMember = removeMemberFromProjectReq.targetMember - val isMemberHasNoPermission = batchOperateGroupMembersCheck( - userId = userId, - projectCode = projectCode, - batchOperateType = BatchOperateType.HANDOVER, - conditionReq = GroupMemberCommonConditionReq( - allSelection = true, - targetMember = removeMemberFromProjectReq.targetMember - ) - ).let { it.totalCount == it.inoperableCount } - - val isMemberHasNoAuthorizations = - if (targetMember.type == ManagerScopesEnum.getType(ManagerScopesEnum.USER)) { - permissionAuthorizationService.listResourceAuthorizations( - condition = ResourceAuthorizationConditionRequest( - projectCode = projectCode, - handoverFrom = targetMember.id - ) - ).count == 0L - } else { - true - } - return isMemberHasNoPermission && isMemberHasNoAuthorizations - } - - private fun handoverTask( - projectCode: String, - groupId: Int, - handoverMemberDTO: GroupMemberHandoverConditionReq, - expiredAt: Long - ) { - logger.info( - "handover group member $projectCode|$groupId|" + - "${handoverMemberDTO.targetMember}|${handoverMemberDTO.handoverTo}" - ) - val currentTimeSeconds = System.currentTimeMillis() / 1000 - var finalExpiredAt = expiredAt - when { - // 若权限已过期,如果是唯一管理员组,允许交接,交接人将获得半年权限;其他的直接删除。 - expiredAt < currentTimeSeconds -> { - val isUniqueManagerGroup = authResourceGroupMemberDao.listProjectUniqueManagerGroups( - dslContext = dslContext, - projectCode = projectCode, - iamGroupIds = listOf(groupId) - ).isNotEmpty() - if (isUniqueManagerGroup) { - finalExpiredAt = currentTimeSeconds + TimeUnit.DAYS.toSeconds(180) - } else { - deleteTask( - projectCode = projectCode, - groupId = groupId, - removeMemberDTO = GroupMemberCommonConditionReq( - targetMember = handoverMemberDTO.targetMember - ), - expiredAt = finalExpiredAt - ) - return - } - } - // 若交接人已经在用户组内,无需交接。 - authResourceGroupMemberDao.isMemberInGroup( - dslContext = dslContext, - projectCode = projectCode, - iamGroupId = groupId, - memberId = handoverMemberDTO.handoverTo.id - ) -> { - deleteTask( - projectCode = projectCode, - groupId = groupId, - removeMemberDTO = GroupMemberCommonConditionReq( - targetMember = handoverMemberDTO.targetMember - ), - expiredAt = finalExpiredAt - ) - return - } - } - - val members = listOf( - ManagerMember( - handoverMemberDTO.handoverTo.type, - handoverMemberDTO.handoverTo.id - ) - ) - if (finalExpiredAt < currentTimeSeconds) { - throw ErrorCodeException( - errorCode = AuthMessageCode.INVALID_EXPIRED_PERM_NOT_ALLOW_TO_HANDOVER - ) - } - - addIamGroupMember( - groupId = groupId, - members = members, - expiredAt = finalExpiredAt - ) - deleteIamGroupMembers( - groupId = groupId, - type = handoverMemberDTO.targetMember.type, - memberIds = listOf(handoverMemberDTO.targetMember.id) - ) - authResourceGroupMemberDao.handoverGroupMembers( - dslContext = dslContext, - projectCode = projectCode, - iamGroupId = groupId, - handoverFrom = handoverMemberDTO.targetMember, - handoverTo = handoverMemberDTO.handoverTo, - expiredTime = DateTimeUtil.convertTimestampToLocalDateTime(finalExpiredAt) - ) - } - - private fun batchOperateGroupMembers( - projectCode: String, - conditionReq: T, - operateGroupMemberTask: ( - projectCode: String, - groupId: Int, - conditionReq: T, - expiredAt: Long - ) -> Unit - ): Boolean { - val groupIds = getGroupIdsByCondition( - projectCode = projectCode, - commonCondition = conditionReq - ).first - val targetMember = conditionReq.targetMember - val memberGroupsDetailsList = listMemberGroupsDetails( - projectCode = projectCode, - memberId = targetMember.id, - memberType = targetMember.type, - groupIds = groupIds - ) - val outOfSyncGroupIds = mutableListOf() - val futures = groupIds.map { groupId -> - CompletableFuture.supplyAsync( - { - val memberGroupsDetails = memberGroupsDetailsList.firstOrNull { it.id == groupId } - if (memberGroupsDetails == null) { - logger.warn( - "The data is out of sync, and the record no longer exists in the iam.$groupId" - ) - outOfSyncGroupIds.add(groupId) - return@supplyAsync - } - val expiredAt = memberGroupsDetails.expiredAt - RetryUtils.retry(3) { - operateGroupMemberTask.invoke( - projectCode, - groupId, - conditionReq, - expiredAt - ) - } - }, executorService - ) - } - handleFutures( - projectCode = projectCode, - outOfSyncGroupIds = outOfSyncGroupIds, - futures = futures - ) - return true - } - - private fun handleFutures( - projectCode: String, - outOfSyncGroupIds: List, - futures: List> - ) { - try { - CompletableFuture.allOf(*futures.toTypedArray()).join() - // 存在iam那边已经把用户组下成员删除,但蓝盾数据库未同步问题 - outOfSyncGroupIds.forEach { - syncIamGroupMemberService.syncIamGroupMember( - projectCode = projectCode, - iamGroupId = it - ) - } - } catch (ignore: Exception) { - logger.warn("batch operate group members failed", ignore) - throw ErrorCodeException( - errorCode = AuthMessageCode.ERROR_BATCH_OPERATE_GROUP_MEMBERS - ) - } - } - - private fun getGroupIdsByCondition( - projectCode: String, - commonCondition: GroupMemberCommonConditionReq - ): Pair, List> /*直接加入,模板加入*/ { - val finalResourceGroupMembers = mutableListOf() - with(commonCondition) { - val resourceGroupMembersByCondition = when { - // 全选 - allSelection -> { - listResourceGroupMembers( - projectCode = projectCode, - memberId = commonCondition.targetMember.id - ).second - } - // 全选某些资源类型用户组 - resourceTypes.isNotEmpty() -> { - resourceTypes.flatMap { resourceType -> - listResourceGroupMembers( - projectCode = projectCode, - memberId = commonCondition.targetMember.id, - resourceType = resourceType - ).second - } - } - - else -> { - emptyList() - } - } - - if (resourceGroupMembersByCondition.isNotEmpty()) { - finalResourceGroupMembers.addAll(resourceGroupMembersByCondition) - } - - // Select specific groups individually - if (groupIds.isNotEmpty()) { - val resourceGroupMembersOfSelect = listResourceGroupMembers( - projectCode = projectCode, - memberId = commonCondition.targetMember.id, - iamGroupIds = groupIds - ).second - finalResourceGroupMembers.addAll(resourceGroupMembersOfSelect) - } - - val (groupIdsOfDirectJoined, groupInfoIdsOfTemplateJoined) = finalResourceGroupMembers.partition { - it.memberType != ManagerScopesEnum.getType(ManagerScopesEnum.TEMPLATE) - }.run { - first.map { it.iamGroupId }.toMutableList() to second.map { it.iamGroupId }.toMutableList() - } - - // When batch removing, if the user is the only manager of the group, ignore and do not transfer - if (excludedUniqueManagerGroup) { - val excludedUniqueManagerGroupIds = authResourceGroupMemberDao.listProjectUniqueManagerGroups( - dslContext = dslContext, - projectCode = projectCode, - iamGroupIds = groupIdsOfDirectJoined - ) - groupIdsOfDirectJoined.removeAll { - excludedUniqueManagerGroupIds.contains(it) - } - } - return Pair(groupIdsOfDirectJoined, groupInfoIdsOfTemplateJoined) - } - } - - private fun listMemberGroupsDetails( - projectCode: String, - memberId: String, - memberType: String, - groupIds: List - ): List { - val memberGroupsDetailsList = mutableListOf() - val groupIdsChunk = groupIds.chunked(100) - val futures = groupIdsChunk.map { - CompletableFuture.supplyAsync( - { - memberGroupsDetailsList.addAll( - // 若离职,则从数据库获取用户加入组的过期时间,调用iam接口会报错。 - // 虽然数据库的过期时间可能不是最新的。 - if (memberType == ManagerScopesEnum.getType(ManagerScopesEnum.USER) && - deptService.isUserDeparted(userId = memberId)) { - val records = authResourceGroupMemberDao.listMemberGroupDetail( - dslContext = dslContext, - projectCode = projectCode, - memberId = memberId, - iamTemplateIds = emptyList(), - iamGroupIds = it - ) - records.map { record -> - MemberGroupDetailsResponse().apply { - id = record.iamGroupId - expiredAt = record.expiredTime.timestamp() - } - } - } else { - iamV2ManagerService.listMemberGroupsDetails( - memberType, - memberId, - it.joinToString(",") - ) - } - ) - }, executorService - ) - } - try { - CompletableFuture.allOf(*futures.toTypedArray()).join() - } catch (ignore: Exception) { - logger.warn("list member groups details failed!$ignore") - throw ignore - } - return memberGroupsDetailsList - } - - // 查询成员所在资源用户组列表,直接加入+通过用户组(模板)加入 - @Suppress("LongParameterList") - override fun listResourceGroupMembers( - projectCode: String, - memberId: String, - resourceType: String?, - iamGroupIds: List?, - minExpiredAt: Long?, - maxExpiredAt: Long?, - start: Int?, - limit: Int? - ): Pair> { - // 获取用户加入的项目级用户组模板ID - val iamTemplateIds = listProjectMemberGroupTemplateIds( - projectCode = projectCode, - memberId = memberId - ) - val minExpiredTime = minExpiredAt?.let { DateTimeUtil.convertTimestampToLocalDateTime(it / 1000) } - val maxExpiredTime = maxExpiredAt?.let { DateTimeUtil.convertTimestampToLocalDateTime(it / 1000) } - val count = authResourceGroupMemberDao.countMemberGroup( - dslContext = dslContext, - projectCode = projectCode, - memberId = memberId, - iamTemplateIds = iamTemplateIds, - resourceType = resourceType, - iamGroupIds = iamGroupIds, - minExpiredAt = minExpiredTime, - maxExpiredAt = maxExpiredTime - )[resourceType] ?: 0L - val resourceGroupMembers = authResourceGroupMemberDao.listMemberGroupDetail( - dslContext = dslContext, - projectCode = projectCode, - memberId = memberId, - iamTemplateIds = iamTemplateIds, - resourceType = resourceType, - iamGroupIds = iamGroupIds, - minExpiredAt = minExpiredTime, - maxExpiredAt = maxExpiredTime, - offset = start, - limit = limit - ) - return Pair(count, resourceGroupMembers) - } - - override fun listMemberGroupIdsInProject( - projectCode: String, - memberId: String - ): List { - // 获取用户加入的项目级用户组模板ID - val iamTemplateIds = listProjectMemberGroupTemplateIds( - projectCode = projectCode, - memberId = memberId - ) - return authResourceGroupMemberDao.listMemberGroupIdsInProject( - dslContext = dslContext, - projectCode = projectCode, - memberId = memberId, - iamTemplateIds = iamTemplateIds - ) - } - - // 获取用户加入的项目级用户组模板ID - private fun listProjectMemberGroupTemplateIds( - projectCode: String, - memberId: String - ): List { - // 查询项目下包含该成员的组列表 - val projectGroupIds = authResourceGroupMemberDao.listResourceGroupMember( - dslContext = dslContext, - projectCode = projectCode, - resourceType = AuthResourceType.PROJECT.value, - memberId = memberId - ).map { it.iamGroupId.toString() } - // 通过项目组ID获取人员模板ID - return authResourceGroupDao.listByRelationId( - dslContext = dslContext, - projectCode = projectCode, - iamGroupIds = projectGroupIds - ).filter { it.iamTemplateId != null } - .map { it.iamTemplateId.toString() } - } - private fun MutableList.removeDepartedMembers(): List { val userMemberIds = this.filter { it.type == ManagerScopesEnum.getType(ManagerScopesEnum.USER) }.map { it.id } if (userMemberIds.isEmpty()) return this @@ -1349,8 +663,5 @@ class RbacPermissionResourceMemberService( private val AUTO_RENEWAL_EXPIRED_AT = TimeUnit.DAYS.toSeconds(180) private val executorService = Executors.newFixedThreadPool(30) - - // 永久过期时间 - private const val PERMANENT_EXPIRED_TIME = 4102444800000L } } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceValidateService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceValidateService.kt index c0baf8abee1..beaaf8312d2 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceValidateService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceValidateService.kt @@ -30,6 +30,7 @@ package com.tencent.devops.auth.provider.rbac.service import com.tencent.devops.auth.constant.AuthMessageCode import com.tencent.devops.auth.pojo.dto.PermissionBatchValidateDTO +import com.tencent.devops.auth.pojo.enum.OperateChannel import com.tencent.devops.auth.service.iam.PermissionResourceValidateService import com.tencent.devops.auth.service.iam.PermissionService import com.tencent.devops.common.api.exception.ErrorCodeException @@ -152,6 +153,40 @@ class RbacPermissionResourceValidateService( return true } + override fun validateUserProjectPermissionByChannel( + userId: String, + projectCode: String, + operateChannel: OperateChannel + ) { + if (operateChannel == OperateChannel.PERSONAL) { + // 个人视角校验 + val hasVisitPermission = permissionService.validateUserResourcePermission( + userId = userId, + resourceType = AuthResourceType.PROJECT.value, + action = RbacAuthUtils.buildAction(AuthPermission.VISIT, AuthResourceType.PROJECT), + projectCode = projectCode + ) + if (!hasVisitPermission) { + throw PermissionForbiddenException( + message = "The user does not have permission to visit the project!" + ) + } + } else { + // 管理员视角校验 + val hasProjectManagePermission = permissionService.validateUserResourcePermission( + userId = userId, + resourceType = AuthResourceType.PROJECT.value, + action = RbacAuthUtils.buildAction(AuthPermission.MANAGE, AuthResourceType.PROJECT), + projectCode = projectCode + ) + if (!hasProjectManagePermission) { + throw PermissionForbiddenException( + message = I18nUtil.getCodeLanMessage(AuthMessageCode.ERROR_AUTH_NO_MANAGE_PERMISSION) + ) + } + } + } + private fun checkProjectApprovalStatus(resourceType: String, resourceCode: String) { if (resourceType == AuthResourceType.PROJECT.value) { val projectInfo = diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionResourceGroupAndMemberFacadeService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionResourceGroupAndMemberFacadeService.kt index 289455d5856..27a9ada5151 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionResourceGroupAndMemberFacadeService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionResourceGroupAndMemberFacadeService.kt @@ -1,8 +1,17 @@ package com.tencent.devops.auth.provider.sample.service +import com.tencent.devops.auth.pojo.AuthResourceGroupMember import com.tencent.devops.auth.pojo.ResourceMemberInfo import com.tencent.devops.auth.pojo.dto.IamGroupIdsQueryConditionDTO +import com.tencent.devops.auth.pojo.enum.BatchOperateType +import com.tencent.devops.auth.pojo.enum.OperateChannel +import com.tencent.devops.auth.pojo.request.GroupMemberCommonConditionReq +import com.tencent.devops.auth.pojo.request.GroupMemberHandoverConditionReq +import com.tencent.devops.auth.pojo.request.GroupMemberRenewalConditionReq +import com.tencent.devops.auth.pojo.request.GroupMemberSingleRenewalReq import com.tencent.devops.auth.pojo.request.ProjectMembersQueryConditionReq +import com.tencent.devops.auth.pojo.request.RemoveMemberFromProjectReq +import com.tencent.devops.auth.pojo.vo.BatchOperateGroupMemberCheckVo import com.tencent.devops.auth.pojo.vo.GroupDetailsInfoVo import com.tencent.devops.auth.pojo.vo.MemberGroupCountWithPermissionsVo import com.tencent.devops.auth.service.iam.PermissionResourceGroupAndMemberFacadeService @@ -20,6 +29,7 @@ class SamplePermissionResourceGroupAndMemberFacadeService : PermissionResourceGr relatedResourceType: String?, relatedResourceCode: String?, action: String?, + operateChannel: OperateChannel?, start: Int?, limit: Int? ): SQLPage = SQLPage(0, emptyList()) @@ -32,14 +42,82 @@ class SamplePermissionResourceGroupAndMemberFacadeService : PermissionResourceGr maxExpiredAt: Long?, relatedResourceType: String?, relatedResourceCode: String?, - action: String? + action: String?, + operateChannel: OperateChannel? ): List = emptyList() override fun listIamGroupIdsByConditions( condition: IamGroupIdsQueryConditionDTO ): List = emptyList() + override fun listMemberGroupIdsInProject( + projectCode: String, + memberId: String + ): List = emptyList() + + override fun listResourceGroupMembers( + projectCode: String, + memberId: String, + resourceType: String?, + iamGroupIds: List?, + excludeIamGroupIds: List?, + minExpiredAt: Long?, + maxExpiredAt: Long?, + operateChannel: OperateChannel?, + start: Int?, + limit: Int? + ): Pair> = Pair(0, emptyList()) + override fun listProjectMembersByComplexConditions( conditionReq: ProjectMembersQueryConditionReq ): SQLPage = SQLPage(0, emptyList()) + + override fun listInvalidAuthorizationsAfterOperatedGroups( + projectCode: String, + iamGroupIds: List, + memberId: String + ): Pair, List> = Pair(emptyList(), emptyList()) + + override fun renewalGroupMember( + userId: String, + projectCode: String, + renewalConditionReq: GroupMemberSingleRenewalReq + ): Boolean = true + + override fun batchRenewalGroupMembersFromManager( + userId: String, + projectCode: String, + renewalConditionReq: GroupMemberRenewalConditionReq + ): Boolean = true + + override fun batchHandoverGroupMembersFromManager( + userId: String, + projectCode: String, + handoverMemberDTO: GroupMemberHandoverConditionReq + ): Boolean = true + + override fun batchDeleteResourceGroupMembersFromManager( + userId: String, + projectCode: String, + removeMemberDTO: GroupMemberCommonConditionReq + ): Boolean = true + + override fun batchOperateGroupMembersCheck( + userId: String, + projectCode: String, + batchOperateType: BatchOperateType, + conditionReq: GroupMemberCommonConditionReq + ): BatchOperateGroupMemberCheckVo = BatchOperateGroupMemberCheckVo(totalCount = 0) + + override fun removeMemberFromProject( + userId: String, + projectCode: String, + removeMemberFromProjectReq: RemoveMemberFromProjectReq + ): List = emptyList() + + override fun removeMemberFromProjectCheck( + userId: String, + projectCode: String, + removeMemberFromProjectReq: RemoveMemberFromProjectReq + ): Boolean = true } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionResourceGroupPermissionService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionResourceGroupPermissionService.kt index 1688b7133dc..997ad7c9ab6 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionResourceGroupPermissionService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionResourceGroupPermissionService.kt @@ -86,6 +86,12 @@ class SamplePermissionResourceGroupPermissionService : PermissionResourceGroupPe action: String ): Boolean = true + override fun isGroupsHasProjectLevelPermission( + projectCode: String, + filterIamGroupIds: List, + action: String + ): Boolean = true + override fun listGroupResourcesWithPermission( projectCode: String, filterIamGroupIds: List, diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionResourceMemberService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionResourceMemberService.kt index c412788f26e..79d4ada40a7 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionResourceMemberService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionResourceMemberService.kt @@ -1,16 +1,8 @@ package com.tencent.devops.auth.provider.sample.service import com.tencent.bk.sdk.iam.dto.manager.ManagerMember -import com.tencent.devops.auth.pojo.AuthResourceGroupMember import com.tencent.devops.auth.pojo.ResourceMemberInfo import com.tencent.devops.auth.pojo.dto.GroupMemberRenewalDTO -import com.tencent.devops.auth.pojo.enum.BatchOperateType -import com.tencent.devops.auth.pojo.request.GroupMemberCommonConditionReq -import com.tencent.devops.auth.pojo.request.GroupMemberHandoverConditionReq -import com.tencent.devops.auth.pojo.request.GroupMemberRenewalConditionReq -import com.tencent.devops.auth.pojo.request.GroupMemberSingleRenewalReq -import com.tencent.devops.auth.pojo.request.RemoveMemberFromProjectReq -import com.tencent.devops.auth.pojo.vo.BatchOperateGroupMemberCheckVo import com.tencent.devops.auth.pojo.vo.ResourceMemberCountVO import com.tencent.devops.auth.service.iam.PermissionResourceMemberService import com.tencent.devops.common.api.model.SQLPage @@ -70,64 +62,18 @@ class SamplePermissionResourceMemberService : PermissionResourceMemberService { memberRenewalDTO: GroupMemberRenewalDTO ): Boolean = true - override fun renewalGroupMember( - userId: String, - projectCode: String, - renewalConditionReq: GroupMemberSingleRenewalReq - ): Boolean = true - override fun renewalIamGroupMembers( groupId: Int, members: List, expiredAt: Long ): Boolean = true - override fun batchRenewalGroupMembers( - userId: String, - projectCode: String, - renewalConditionReq: GroupMemberRenewalConditionReq - ): Boolean = true - - override fun batchDeleteResourceGroupMembers( - userId: String, - projectCode: String, - removeMemberDTO: GroupMemberCommonConditionReq - ): Boolean = true - override fun deleteIamGroupMembers( groupId: Int, type: String, memberIds: List ): Boolean = true - override fun batchHandoverGroupMembers( - userId: String, - projectCode: String, - handoverMemberDTO: GroupMemberHandoverConditionReq - ): Boolean = true - - override fun batchOperateGroupMembersCheck( - userId: String, - projectCode: String, - batchOperateType: BatchOperateType, - conditionReq: GroupMemberCommonConditionReq - ): BatchOperateGroupMemberCheckVo = BatchOperateGroupMemberCheckVo( - totalCount = 0, - inoperableCount = 0 - ) - - override fun removeMemberFromProject( - userId: String, - projectCode: String, - removeMemberFromProjectReq: RemoveMemberFromProjectReq - ): List = emptyList() - - override fun removeMemberFromProjectCheck( - userId: String, - projectCode: String, - removeMemberFromProjectReq: RemoveMemberFromProjectReq - ): Boolean = true - override fun addGroupMember( projectCode: String, memberId: String, @@ -136,9 +82,11 @@ class SamplePermissionResourceMemberService : PermissionResourceMemberService { iamGroupId: Int ): Boolean = true - override fun addIamGroupMember(groupId: Int, members: List, expiredAt: Long): Boolean { - TODO("Not yet implemented") - } + override fun addIamGroupMember( + groupId: Int, + members: List, + expiredAt: Long + ): Boolean = true override fun getProjectMemberCount(projectCode: String): ResourceMemberCountVO = ResourceMemberCountVO( @@ -161,20 +109,4 @@ class SamplePermissionResourceMemberService : PermissionResourceMemberService { override fun addDepartedFlagToMembers( records: List ): List = emptyList() - - override fun listResourceGroupMembers( - projectCode: String, - memberId: String, - resourceType: String?, - iamGroupIds: List?, - minExpiredAt: Long?, - maxExpiredAt: Long?, - start: Int?, - limit: Int? - ): Pair> = Pair(0, emptyList()) - - override fun listMemberGroupIdsInProject( - projectCode: String, - memberId: String - ): List = emptyList() } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionResourceValidateService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionResourceValidateService.kt index b2ba564a4cf..6ff90235c55 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionResourceValidateService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionResourceValidateService.kt @@ -29,6 +29,7 @@ package com.tencent.devops.auth.provider.sample.service import com.tencent.devops.auth.pojo.dto.PermissionBatchValidateDTO +import com.tencent.devops.auth.pojo.enum.OperateChannel import com.tencent.devops.auth.service.iam.PermissionResourceValidateService class SamplePermissionResourceValidateService : PermissionResourceValidateService { @@ -46,4 +47,12 @@ class SamplePermissionResourceValidateService : PermissionResourceValidateServic resourceType: String, resourceCode: String ): Boolean = true + + override fun validateUserProjectPermissionByChannel( + userId: String, + projectCode: String, + operateChannel: OperateChannel + ) { + return + } } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/service/ServiceResourceMemberResourceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/service/ServiceResourceMemberResourceImpl.kt index 02c0636974f..ff178f35ab1 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/service/ServiceResourceMemberResourceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/service/ServiceResourceMemberResourceImpl.kt @@ -2,6 +2,7 @@ package com.tencent.devops.auth.resources.service import com.tencent.devops.auth.api.service.ServiceResourceMemberResource import com.tencent.devops.auth.pojo.request.GroupMemberSingleRenewalReq +import com.tencent.devops.auth.service.iam.PermissionResourceGroupAndMemberFacadeService import com.tencent.devops.auth.service.iam.PermissionResourceMemberService import com.tencent.devops.common.api.pojo.Result import com.tencent.devops.common.auth.api.pojo.BkAuthGroup @@ -14,8 +15,9 @@ import com.tencent.devops.project.pojo.ProjectDeleteUserInfo import java.util.concurrent.TimeUnit @RestResource -class ServiceResourceMemberResourceImpl constructor( - private val permissionResourceMemberService: PermissionResourceMemberService +class ServiceResourceMemberResourceImpl( + private val permissionResourceMemberService: PermissionResourceMemberService, + private val permissionResourceGroupAndMemberFacadeService: PermissionResourceGroupAndMemberFacadeService ) : ServiceResourceMemberResource { @BkApiPermission([BkApiHandleType.API_OPEN_TOKEN_CHECK]) override fun getResourceGroupMembers( @@ -107,7 +109,7 @@ class ServiceResourceMemberResourceImpl constructor( renewalConditionReq: GroupMemberSingleRenewalReq ): Result { return Result( - permissionResourceMemberService.renewalGroupMember( + permissionResourceGroupAndMemberFacadeService.renewalGroupMember( userId = userId, projectCode = projectCode, renewalConditionReq = renewalConditionReq diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceGroupResourceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceGroupResourceImpl.kt index 4c99458fb86..b03e24a3c12 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceGroupResourceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceGroupResourceImpl.kt @@ -33,6 +33,7 @@ import com.tencent.devops.auth.api.user.UserAuthResourceGroupResource import com.tencent.devops.auth.pojo.ResourceMemberInfo import com.tencent.devops.auth.pojo.dto.GroupMemberRenewalDTO import com.tencent.devops.auth.pojo.dto.RenameGroupDTO +import com.tencent.devops.auth.pojo.enum.OperateChannel import com.tencent.devops.auth.pojo.request.GroupMemberCommonConditionReq import com.tencent.devops.auth.pojo.vo.GroupDetailsInfoVo import com.tencent.devops.auth.pojo.vo.IamGroupPoliciesVo @@ -40,6 +41,7 @@ import com.tencent.devops.auth.service.iam.PermissionResourceGroupAndMemberFacad import com.tencent.devops.auth.service.iam.PermissionResourceGroupPermissionService import com.tencent.devops.auth.service.iam.PermissionResourceGroupService import com.tencent.devops.auth.service.iam.PermissionResourceMemberService +import com.tencent.devops.auth.service.iam.PermissionResourceValidateService import com.tencent.devops.common.api.model.SQLPage import com.tencent.devops.common.api.pojo.Result import com.tencent.devops.common.auth.api.BkManagerCheck @@ -51,7 +53,8 @@ class UserAuthResourceGroupResourceImpl @Autowired constructor( private val permissionResourceGroupService: PermissionResourceGroupService, private val permissionResourceMemberService: PermissionResourceMemberService, private val permissionResourceGroupAndMemberFacadeService: PermissionResourceGroupAndMemberFacadeService, - private val permissionResourceGroupPermissionService: PermissionResourceGroupPermissionService + private val permissionResourceGroupPermissionService: PermissionResourceGroupPermissionService, + private val permissionResourceValidateService: PermissionResourceValidateService ) : UserAuthResourceGroupResource { override fun getGroupPolicies( userId: String, @@ -69,7 +72,6 @@ class UserAuthResourceGroupResourceImpl @Autowired constructor( ) } - @BkManagerCheck override fun getMemberGroupsDetails( userId: String, projectId: String, @@ -81,9 +83,16 @@ class UserAuthResourceGroupResourceImpl @Autowired constructor( relatedResourceType: String?, relatedResourceCode: String?, action: String?, + operateChannel: OperateChannel?, start: Int, limit: Int ): Result> { + permissionResourceValidateService.validateUserProjectPermissionByChannel( + userId = userId, + projectCode = projectId, + operateChannel = operateChannel ?: OperateChannel.MANAGER + ) + return Result( permissionResourceGroupAndMemberFacadeService.getMemberGroupsDetails( projectId = projectId, @@ -126,7 +135,7 @@ class UserAuthResourceGroupResourceImpl @Autowired constructor( groupId: Int ): Result { return Result( - permissionResourceMemberService.batchDeleteResourceGroupMembers( + permissionResourceGroupAndMemberFacadeService.batchDeleteResourceGroupMembersFromManager( userId = userId, projectCode = projectId, removeMemberDTO = GroupMemberCommonConditionReq( diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceMemberResourceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceMemberResourceImpl.kt index bd76fea6919..fd01f260d00 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceMemberResourceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceMemberResourceImpl.kt @@ -3,6 +3,7 @@ package com.tencent.devops.auth.resources.user import com.tencent.devops.auth.api.user.UserAuthResourceMemberResource import com.tencent.devops.auth.pojo.ResourceMemberInfo import com.tencent.devops.auth.pojo.enum.BatchOperateType +import com.tencent.devops.auth.pojo.enum.OperateChannel import com.tencent.devops.auth.pojo.request.GroupMemberCommonConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberHandoverConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberRenewalConditionReq @@ -14,6 +15,7 @@ import com.tencent.devops.auth.pojo.vo.GroupDetailsInfoVo import com.tencent.devops.auth.pojo.vo.MemberGroupCountWithPermissionsVo import com.tencent.devops.auth.service.iam.PermissionResourceGroupAndMemberFacadeService import com.tencent.devops.auth.service.iam.PermissionResourceMemberService +import com.tencent.devops.auth.service.iam.PermissionResourceValidateService import com.tencent.devops.auth.service.iam.PermissionService import com.tencent.devops.common.api.model.SQLPage import com.tencent.devops.common.api.pojo.Result @@ -27,7 +29,8 @@ import com.tencent.devops.common.web.RestResource class UserAuthResourceMemberResourceImpl( private val permissionResourceMemberService: PermissionResourceMemberService, private val permissionService: PermissionService, - private val permissionResourceGroupAndMemberFacadeService: PermissionResourceGroupAndMemberFacadeService + private val permissionResourceGroupAndMemberFacadeService: PermissionResourceGroupAndMemberFacadeService, + private val permissionResourceValidateService: PermissionResourceValidateService ) : UserAuthResourceMemberResource { override fun listProjectMembers( userId: String, @@ -81,7 +84,7 @@ class UserAuthResourceMemberResourceImpl( projectId: String, renewalConditionReq: GroupMemberSingleRenewalReq ): Result { - permissionResourceMemberService.renewalGroupMember( + permissionResourceGroupAndMemberFacadeService.renewalGroupMember( userId = userId, projectCode = projectId, renewalConditionReq = renewalConditionReq @@ -96,13 +99,13 @@ class UserAuthResourceMemberResourceImpl( } @BkManagerCheck - override fun batchRenewalGroupMembers( + override fun batchRenewalGroupMembersFromManager( userId: String, projectId: String, renewalConditionReq: GroupMemberRenewalConditionReq ): Result { return Result( - permissionResourceMemberService.batchRenewalGroupMembers( + permissionResourceGroupAndMemberFacadeService.batchRenewalGroupMembersFromManager( userId = userId, projectCode = projectId, renewalConditionReq = renewalConditionReq @@ -111,13 +114,13 @@ class UserAuthResourceMemberResourceImpl( } @BkManagerCheck - override fun batchRemoveGroupMembers( + override fun batchRemoveGroupMembersFromManager( userId: String, projectId: String, removeMemberDTO: GroupMemberCommonConditionReq ): Result { return Result( - permissionResourceMemberService.batchDeleteResourceGroupMembers( + permissionResourceGroupAndMemberFacadeService.batchDeleteResourceGroupMembersFromManager( userId = userId, projectCode = projectId, removeMemberDTO = removeMemberDTO @@ -126,13 +129,13 @@ class UserAuthResourceMemberResourceImpl( } @BkManagerCheck - override fun batchHandoverGroupMembers( + override fun batchHandoverGroupMembersFromManager( userId: String, projectId: String, handoverMemberDTO: GroupMemberHandoverConditionReq ): Result { return Result( - permissionResourceMemberService.batchHandoverGroupMembers( + permissionResourceGroupAndMemberFacadeService.batchHandoverGroupMembersFromManager( userId = userId, projectCode = projectId, handoverMemberDTO = handoverMemberDTO @@ -148,7 +151,7 @@ class UserAuthResourceMemberResourceImpl( conditionReq: GroupMemberCommonConditionReq ): Result { return Result( - permissionResourceMemberService.batchOperateGroupMembersCheck( + permissionResourceGroupAndMemberFacadeService.batchOperateGroupMembersCheck( userId = userId, projectCode = projectId, batchOperateType = batchOperateType, @@ -164,7 +167,7 @@ class UserAuthResourceMemberResourceImpl( removeMemberFromProjectReq: RemoveMemberFromProjectReq ): Result> { return Result( - permissionResourceMemberService.removeMemberFromProject( + permissionResourceGroupAndMemberFacadeService.removeMemberFromProject( userId = userId, projectCode = projectId, removeMemberFromProjectReq = removeMemberFromProjectReq @@ -179,7 +182,7 @@ class UserAuthResourceMemberResourceImpl( removeMemberFromProjectReq: RemoveMemberFromProjectReq ): Result { return Result( - permissionResourceMemberService.removeMemberFromProjectCheck( + permissionResourceGroupAndMemberFacadeService.removeMemberFromProjectCheck( userId = userId, projectCode = projectId, removeMemberFromProjectReq = removeMemberFromProjectReq @@ -187,7 +190,6 @@ class UserAuthResourceMemberResourceImpl( ) } - @BkManagerCheck override fun getMemberGroupCount( userId: String, projectId: String, @@ -197,8 +199,14 @@ class UserAuthResourceMemberResourceImpl( maxExpiredAt: Long?, relatedResourceType: String?, relatedResourceCode: String?, - action: String? + action: String?, + operateChannel: OperateChannel? ): Result> { + permissionResourceValidateService.validateUserProjectPermissionByChannel( + userId = userId, + projectCode = projectId, + operateChannel = operateChannel ?: OperateChannel.MANAGER + ) return Result( permissionResourceGroupAndMemberFacadeService.getMemberGroupsCount( projectCode = projectId, diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt index dac016a70d2..bbde2b535c4 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt @@ -30,7 +30,7 @@ import org.slf4j.LoggerFactory import org.springframework.stereotype.Service @Service -class PermissionAuthorizationServiceImpl constructor( +class PermissionAuthorizationServiceImpl( private val dslContext: DSLContext, private val authAuthorizationDao: AuthAuthorizationDao, private val client: Client, @@ -352,6 +352,7 @@ class PermissionAuthorizationServiceImpl constructor( resourceAuthorizationHandoverDTOs = resourceAuthorizationHandoverDTOs ).data } + AuthResourceType.CODE_REPERTORY.value -> { client.get(ServiceRepositoryAuthorizationResource::class).resetRepositoryAuthorization( projectId = projectId, @@ -359,6 +360,7 @@ class PermissionAuthorizationServiceImpl constructor( resourceAuthorizationHandoverDTOs = resourceAuthorizationHandoverDTOs ).data } + AuthResourceType.ENVIRONMENT_ENV_NODE.value -> { client.get(ServiceEnvNodeAuthorizationResource::class).resetEnvNodeAuthorization( projectId = projectId, @@ -366,6 +368,7 @@ class PermissionAuthorizationServiceImpl constructor( resourceAuthorizationHandoverDTOs = resourceAuthorizationHandoverDTOs ).data } + else -> { null } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionResourceGroupAndMemberFacadeService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionResourceGroupAndMemberFacadeService.kt index 4a591487e58..7d621e79f30 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionResourceGroupAndMemberFacadeService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionResourceGroupAndMemberFacadeService.kt @@ -1,15 +1,26 @@ package com.tencent.devops.auth.service.iam +import com.tencent.devops.auth.pojo.AuthResourceGroupMember import com.tencent.devops.auth.pojo.ResourceMemberInfo import com.tencent.devops.auth.pojo.dto.IamGroupIdsQueryConditionDTO +import com.tencent.devops.auth.pojo.enum.BatchOperateType +import com.tencent.devops.auth.pojo.enum.OperateChannel +import com.tencent.devops.auth.pojo.request.GroupMemberCommonConditionReq +import com.tencent.devops.auth.pojo.request.GroupMemberHandoverConditionReq +import com.tencent.devops.auth.pojo.request.GroupMemberRenewalConditionReq +import com.tencent.devops.auth.pojo.request.GroupMemberSingleRenewalReq import com.tencent.devops.auth.pojo.request.ProjectMembersQueryConditionReq +import com.tencent.devops.auth.pojo.request.RemoveMemberFromProjectReq +import com.tencent.devops.auth.pojo.vo.BatchOperateGroupMemberCheckVo import com.tencent.devops.auth.pojo.vo.GroupDetailsInfoVo import com.tencent.devops.auth.pojo.vo.MemberGroupCountWithPermissionsVo import com.tencent.devops.common.api.model.SQLPage interface PermissionResourceGroupAndMemberFacadeService { /** - * 查询成员所在资源用户组详情,直接加入+通过用户组(模板)加入 + * 查询成员所在资源用户组详情 + * 管理员视角返回用户直接加入/模板加入的用户组 + * 个人视角返回用户直接加入/模板加入/组织加入的用户组 * */ fun getMemberGroupsDetails( projectId: String, @@ -22,12 +33,15 @@ interface PermissionResourceGroupAndMemberFacadeService { relatedResourceType: String? = null, relatedResourceCode: String? = null, action: String? = null, + operateChannel: OperateChannel? = OperateChannel.MANAGER, start: Int? = null, limit: Int? = null ): SQLPage /** * 获取用户有权限的用户组数量 + * 管理员视角返回用户直接加入/模板加入的用户组 + * 个人视角返回用户直接加入/模板加入/组织加入的用户组 * */ fun getMemberGroupsCount( projectCode: String, @@ -37,7 +51,8 @@ interface PermissionResourceGroupAndMemberFacadeService { maxExpiredAt: Long?, relatedResourceType: String?, relatedResourceCode: String?, - action: String? + action: String?, + operateChannel: OperateChannel? = OperateChannel.MANAGER ): List /** @@ -47,10 +62,92 @@ interface PermissionResourceGroupAndMemberFacadeService { condition: IamGroupIdsQueryConditionDTO ): List + /** + * 获取用户在该项目加入的组 + * */ + fun listMemberGroupIdsInProject( + projectCode: String, + memberId: String + ): List + + /** + * 查询成员所在资源用户组列表 + * 管理员视角返回用户直接加入/模板加入的用户组 + * 个人视角返回用户直接加入/模板加入/组织加入的用户组 + * */ + fun listResourceGroupMembers( + projectCode: String, + memberId: String, + resourceType: String? = null, + iamGroupIds: List? = null, + excludeIamGroupIds: List? = null, + minExpiredAt: Long? = null, + maxExpiredAt: Long? = null, + operateChannel: OperateChannel? = OperateChannel.MANAGER, + start: Int? = null, + limit: Int? = null + ): Pair> + /** * 根据复杂条件进行搜索,用于用户管理界面 * */ fun listProjectMembersByComplexConditions( conditionReq: ProjectMembersQueryConditionReq ): SQLPage + + /** + * 为了避免流水线代持人权限失效,需要对用户退出/交接用户组进行检查。 + * 返回结果: + * 1、引起代持人权限失效的用户组。 + * 2、引起代持人权限失效的流水线。 + **/ + fun listInvalidAuthorizationsAfterOperatedGroups( + projectCode: String, + iamGroupIds: List, + memberId: String + ): Pair/*引起代持人权限失效的用户组*/, List/*引起代持人权限失效的流水线*/> + + // 无需审批版本 + fun renewalGroupMember( + userId: String, + projectCode: String, + renewalConditionReq: GroupMemberSingleRenewalReq + ): Boolean + + fun batchRenewalGroupMembersFromManager( + userId: String, + projectCode: String, + renewalConditionReq: GroupMemberRenewalConditionReq + ): Boolean + + fun batchHandoverGroupMembersFromManager( + userId: String, + projectCode: String, + handoverMemberDTO: GroupMemberHandoverConditionReq + ): Boolean + + fun batchDeleteResourceGroupMembersFromManager( + userId: String, + projectCode: String, + removeMemberDTO: GroupMemberCommonConditionReq + ): Boolean + + fun batchOperateGroupMembersCheck( + userId: String, + projectCode: String, + batchOperateType: BatchOperateType, + conditionReq: GroupMemberCommonConditionReq + ): BatchOperateGroupMemberCheckVo + + fun removeMemberFromProject( + userId: String, + projectCode: String, + removeMemberFromProjectReq: RemoveMemberFromProjectReq + ): List + + fun removeMemberFromProjectCheck( + userId: String, + projectCode: String, + removeMemberFromProjectReq: RemoveMemberFromProjectReq + ): Boolean } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionResourceGroupPermissionService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionResourceGroupPermissionService.kt index 0172b4516c2..9063615cc7e 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionResourceGroupPermissionService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionResourceGroupPermissionService.kt @@ -91,6 +91,15 @@ interface PermissionResourceGroupPermissionService { action: String ): Boolean + /** + * 是否用户拥有项目级别权限,如整个项目流水线执行权限/项目的管理权限等。 + * */ + fun isGroupsHasProjectLevelPermission( + projectCode: String, + filterIamGroupIds: List, + action: String + ): Boolean + /** * 获取用户组有权限的资源 * */ diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionResourceMemberService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionResourceMemberService.kt index 91073660f2f..7b4aa254ddc 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionResourceMemberService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionResourceMemberService.kt @@ -1,16 +1,8 @@ package com.tencent.devops.auth.service.iam import com.tencent.bk.sdk.iam.dto.manager.ManagerMember -import com.tencent.devops.auth.pojo.AuthResourceGroupMember import com.tencent.devops.auth.pojo.ResourceMemberInfo import com.tencent.devops.auth.pojo.dto.GroupMemberRenewalDTO -import com.tencent.devops.auth.pojo.enum.BatchOperateType -import com.tencent.devops.auth.pojo.request.GroupMemberCommonConditionReq -import com.tencent.devops.auth.pojo.request.GroupMemberHandoverConditionReq -import com.tencent.devops.auth.pojo.request.GroupMemberRenewalConditionReq -import com.tencent.devops.auth.pojo.request.GroupMemberSingleRenewalReq -import com.tencent.devops.auth.pojo.request.RemoveMemberFromProjectReq -import com.tencent.devops.auth.pojo.vo.BatchOperateGroupMemberCheckVo import com.tencent.devops.auth.pojo.vo.ResourceMemberCountVO import com.tencent.devops.common.api.model.SQLPage import com.tencent.devops.common.auth.api.pojo.BkAuthGroup @@ -50,25 +42,6 @@ interface PermissionResourceMemberService { fun addDepartedFlagToMembers(records: List): List - fun listResourceGroupMembers( - projectCode: String, - memberId: String, - resourceType: String? = null, - iamGroupIds: List? = null, - minExpiredAt: Long? = null, - maxExpiredAt: Long? = null, - start: Int? = null, - limit: Int? = null - ): Pair> - - /** - * 获取用户在该项目加入的组 - * */ - fun listMemberGroupIdsInProject( - projectCode: String, - memberId: String - ): List - fun batchDeleteResourceGroupMembers( projectCode: String, iamGroupId: Int, @@ -76,43 +49,12 @@ interface PermissionResourceMemberService { departments: List? = emptyList() ): Boolean - fun batchDeleteResourceGroupMembers( - userId: String, - projectCode: String, - removeMemberDTO: GroupMemberCommonConditionReq - ): Boolean - fun deleteIamGroupMembers( groupId: Int, type: String, memberIds: List ): Boolean - fun batchHandoverGroupMembers( - userId: String, - projectCode: String, - handoverMemberDTO: GroupMemberHandoverConditionReq - ): Boolean - - fun batchOperateGroupMembersCheck( - userId: String, - projectCode: String, - batchOperateType: BatchOperateType, - conditionReq: GroupMemberCommonConditionReq - ): BatchOperateGroupMemberCheckVo - - fun removeMemberFromProject( - userId: String, - projectCode: String, - removeMemberFromProjectReq: RemoveMemberFromProjectReq - ): List - - fun removeMemberFromProjectCheck( - userId: String, - projectCode: String, - removeMemberFromProjectReq: RemoveMemberFromProjectReq - ): Boolean - fun roleCodeToIamGroupId( projectCode: String, roleCode: String @@ -134,25 +76,12 @@ interface PermissionResourceMemberService { memberRenewalDTO: GroupMemberRenewalDTO ): Boolean - // 无需审批版本 - fun renewalGroupMember( - userId: String, - projectCode: String, - renewalConditionReq: GroupMemberSingleRenewalReq - ): Boolean - fun renewalIamGroupMembers( groupId: Int, members: List, expiredAt: Long ): Boolean - fun batchRenewalGroupMembers( - userId: String, - projectCode: String, - renewalConditionReq: GroupMemberRenewalConditionReq - ): Boolean - fun addGroupMember( projectCode: String, memberId: String, diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionResourceValidateService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionResourceValidateService.kt index e81196b7eec..2f0478edd23 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionResourceValidateService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionResourceValidateService.kt @@ -29,6 +29,7 @@ package com.tencent.devops.auth.service.iam import com.tencent.devops.auth.pojo.dto.PermissionBatchValidateDTO +import com.tencent.devops.auth.pojo.enum.OperateChannel interface PermissionResourceValidateService { fun batchValidateUserResourcePermission( @@ -46,4 +47,13 @@ interface PermissionResourceValidateService { resourceType: String, resourceCode: String ): Boolean + + /** + * 根据渠道来校验用户权限,主要用户管理界面/个人视角 + */ + fun validateUserProjectPermissionByChannel( + userId: String, + projectCode: String, + operateChannel: OperateChannel + ) } diff --git a/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationConditionRequest.kt b/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationConditionRequest.kt index d5f8241e220..05498e044d3 100644 --- a/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationConditionRequest.kt +++ b/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationConditionRequest.kt @@ -12,6 +12,10 @@ open class ResourceAuthorizationConditionRequest( open val resourceType: String? = null, @get:Schema(title = "资源名称") open val resourceName: String? = null, + @get:Schema(title = "过滤资源ID列表") + open val filterResourceCodes: List? = null, + @get:Schema(title = "排除资源ID列表") + open val excludeResourceCodes: List? = null, @get:Schema(title = "授予人") open val handoverFrom: String? = null, @get:Schema(title = "greaterThanHandoverTime") diff --git a/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationHandoverConditionRequest.kt b/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationHandoverConditionRequest.kt index 21fd1979736..d8f4e1bdde0 100644 --- a/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationHandoverConditionRequest.kt +++ b/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationHandoverConditionRequest.kt @@ -12,6 +12,10 @@ data class ResourceAuthorizationHandoverConditionRequest( override val resourceType: String, @get:Schema(title = "资源名称") override val resourceName: String? = null, + @get:Schema(title = "过滤资源ID列表") + override val filterResourceCodes: List? = null, + @get:Schema(title = "排除资源ID列表") + override val excludeResourceCodes: List? = null, @get:Schema(title = "授予人") override val handoverFrom: String? = null, @get:Schema(title = "greaterThanHandoverTime") @@ -38,6 +42,8 @@ data class ResourceAuthorizationHandoverConditionRequest( projectCode = projectCode, resourceType = resourceType, resourceName = resourceName, + filterResourceCodes = filterResourceCodes, + excludeResourceCodes = excludeResourceCodes, handoverFrom = handoverFrom, greaterThanHandoverTime = greaterThanHandoverTime, lessThanHandoverTime = lessThanHandoverTime, diff --git a/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationResponse.kt b/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationResponse.kt index 0c396b8c198..3b4062e55ec 100644 --- a/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationResponse.kt +++ b/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationResponse.kt @@ -5,6 +5,8 @@ import io.swagger.v3.oas.annotations.media.Schema @Schema(title = "资源授权返回体") @Suppress("LongParameterList") data class ResourceAuthorizationResponse( + @get:Schema(title = "ID") + val id: Long, @get:Schema(title = "项目ID") val projectCode: String, @get:Schema(title = "资源类型") From 906ab3ee8797604bbf2399876d69d798b1c357a0 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Mon, 11 Nov 2024 14:41:03 +0800 Subject: [PATCH 02/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rbac/config/RbacAuthConfiguration.kt | 12 +++++----- ... RbacPermissionManageFacadeServiceImpl.kt} | 6 ++--- .../MigratePermissionHandoverService.kt | 6 ++--- .../sample/config/MockAuthConfiguration.kt | 8 +++---- ...=> SamplePermissionManageFacadeService.kt} | 4 ++-- .../ServiceResourceGroupResourceImpl.kt | 6 ++--- .../ServiceResourceMemberResourceImpl.kt | 6 ++--- .../user/UserAuthResourceGroupResourceImpl.kt | 8 +++---- .../UserAuthResourceMemberResourceImpl.kt | 24 +++++++++---------- ...ce.kt => PermissionManageFacadeService.kt} | 18 ++++++++++++-- 10 files changed, 56 insertions(+), 42 deletions(-) rename src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/{RbacPermissionResourceGroupAndMemberFacadeServiceImpl.kt => RbacPermissionManageFacadeServiceImpl.kt} (99%) rename src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/{SamplePermissionResourceGroupAndMemberFacadeService.kt => SamplePermissionManageFacadeService.kt} (95%) rename src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/{PermissionResourceGroupAndMemberFacadeService.kt => PermissionManageFacadeService.kt} (94%) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/config/RbacAuthConfiguration.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/config/RbacAuthConfiguration.kt index bea9b0d81f8..3b791cd6444 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/config/RbacAuthConfiguration.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/config/RbacAuthConfiguration.kt @@ -66,7 +66,7 @@ import com.tencent.devops.auth.provider.rbac.service.RbacPermissionExtService import com.tencent.devops.auth.provider.rbac.service.RbacPermissionItsmCallbackService import com.tencent.devops.auth.provider.rbac.service.RbacPermissionProjectService import com.tencent.devops.auth.provider.rbac.service.RbacPermissionResourceCallbackService -import com.tencent.devops.auth.provider.rbac.service.RbacPermissionResourceGroupAndMemberFacadeServiceImpl +import com.tencent.devops.auth.provider.rbac.service.RbacPermissionManageFacadeServiceImpl import com.tencent.devops.auth.provider.rbac.service.RbacPermissionResourceGroupPermissionService import com.tencent.devops.auth.provider.rbac.service.RbacPermissionResourceGroupService import com.tencent.devops.auth.provider.rbac.service.RbacPermissionResourceGroupSyncService @@ -94,7 +94,7 @@ import com.tencent.devops.auth.service.PermissionAuthorizationService import com.tencent.devops.auth.service.ResourceService import com.tencent.devops.auth.service.SuperManagerService import com.tencent.devops.auth.service.iam.MigrateCreatorFixService -import com.tencent.devops.auth.service.iam.PermissionResourceGroupAndMemberFacadeService +import com.tencent.devops.auth.service.iam.PermissionManageFacadeService import com.tencent.devops.auth.service.iam.PermissionResourceGroupPermissionService import com.tencent.devops.auth.service.iam.PermissionResourceGroupService import com.tencent.devops.auth.service.iam.PermissionResourceGroupSyncService @@ -199,7 +199,7 @@ class RbacAuthConfiguration { ) @Bean - fun permissionResourceGroupAndMemberFacadeService( + fun permissionFacadeService( permissionResourceGroupService: PermissionResourceGroupService, groupPermissionService: PermissionResourceGroupPermissionService, permissionResourceMemberService: PermissionResourceMemberService, @@ -212,7 +212,7 @@ class RbacAuthConfiguration { permissionAuthorizationService: PermissionAuthorizationService, syncIamGroupMemberService: PermissionResourceGroupSyncService, authAuthorizationDao: AuthAuthorizationDao - ) = RbacPermissionResourceGroupAndMemberFacadeServiceImpl( + ) = RbacPermissionManageFacadeServiceImpl( permissionResourceGroupService = permissionResourceGroupService, groupPermissionService = groupPermissionService, permissionResourceMemberService = permissionResourceMemberService, @@ -593,13 +593,13 @@ class RbacAuthConfiguration { authResourceService: AuthResourceService, authResourceGroupMemberService: PermissionResourceMemberService, dslContext: DSLContext, - resourceGroupAndMemberFacadeService: PermissionResourceGroupAndMemberFacadeService + permissionManageFacadeService: PermissionManageFacadeService ) = MigratePermissionHandoverService( permissionResourceMemberService = permissionResourceMemberService, authResourceGroupDao = authResourceGroupDao, authResourceService = authResourceService, dslContext = dslContext, - resourceGroupAndMemberFacadeService = resourceGroupAndMemberFacadeService + permissionManageFacadeService = permissionManageFacadeService ) @Bean diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupAndMemberFacadeServiceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt similarity index 99% rename from src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupAndMemberFacadeServiceImpl.kt rename to src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt index 45c30ba701f..dac5718a82c 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupAndMemberFacadeServiceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt @@ -28,7 +28,7 @@ import com.tencent.devops.auth.pojo.vo.GroupDetailsInfoVo import com.tencent.devops.auth.pojo.vo.MemberGroupCountWithPermissionsVo import com.tencent.devops.auth.service.DeptService import com.tencent.devops.auth.service.PermissionAuthorizationService -import com.tencent.devops.auth.service.iam.PermissionResourceGroupAndMemberFacadeService +import com.tencent.devops.auth.service.iam.PermissionManageFacadeService import com.tencent.devops.auth.service.iam.PermissionResourceGroupPermissionService import com.tencent.devops.auth.service.iam.PermissionResourceGroupService import com.tencent.devops.auth.service.iam.PermissionResourceGroupSyncService @@ -52,7 +52,7 @@ import java.util.concurrent.CompletableFuture import java.util.concurrent.Executors import java.util.concurrent.TimeUnit -class RbacPermissionResourceGroupAndMemberFacadeServiceImpl( +class RbacPermissionManageFacadeServiceImpl( private val permissionResourceGroupService: PermissionResourceGroupService, private val groupPermissionService: PermissionResourceGroupPermissionService, private val permissionResourceMemberService: PermissionResourceMemberService, @@ -65,7 +65,7 @@ class RbacPermissionResourceGroupAndMemberFacadeServiceImpl( private val authAuthorizationDao: AuthAuthorizationDao, private val syncIamGroupMemberService: PermissionResourceGroupSyncService, private val permissionAuthorizationService: PermissionAuthorizationService -) : PermissionResourceGroupAndMemberFacadeService { +) : PermissionManageFacadeService { override fun getMemberGroupsDetails( projectId: String, memberId: String, diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/migrate/MigratePermissionHandoverService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/migrate/MigratePermissionHandoverService.kt index e7597f6ccc1..dd14d20be28 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/migrate/MigratePermissionHandoverService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/migrate/MigratePermissionHandoverService.kt @@ -32,7 +32,7 @@ import com.tencent.devops.auth.dao.AuthResourceGroupDao import com.tencent.devops.auth.pojo.dto.PermissionHandoverDTO import com.tencent.devops.auth.pojo.enum.JoinedType import com.tencent.devops.auth.provider.rbac.service.AuthResourceService -import com.tencent.devops.auth.service.iam.PermissionResourceGroupAndMemberFacadeService +import com.tencent.devops.auth.service.iam.PermissionManageFacadeService import com.tencent.devops.auth.service.iam.PermissionResourceMemberService import com.tencent.devops.common.auth.api.AuthResourceType import com.tencent.devops.common.auth.api.pojo.DefaultGroupType @@ -43,7 +43,7 @@ class MigratePermissionHandoverService( private val permissionResourceMemberService: PermissionResourceMemberService, private val authResourceGroupDao: AuthResourceGroupDao, private val authResourceService: AuthResourceService, - private val resourceGroupAndMemberFacadeService: PermissionResourceGroupAndMemberFacadeService, + private val permissionManageFacadeService: PermissionManageFacadeService, private val dslContext: DSLContext ) { fun handoverPermissions(permissionHandoverDTO: PermissionHandoverDTO) { @@ -114,7 +114,7 @@ class MigratePermissionHandoverService( ) } // 交接用户组权限 - val userJoinedGroups = resourceGroupAndMemberFacadeService.getMemberGroupsDetails( + val userJoinedGroups = permissionManageFacadeService.getMemberGroupsDetails( projectId = projectCode, memberId = handoverFrom ).records.filter { it.joinedType == JoinedType.DIRECT }.map { it.groupId } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/config/MockAuthConfiguration.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/config/MockAuthConfiguration.kt index 84587ca37b7..517846766be 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/config/MockAuthConfiguration.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/config/MockAuthConfiguration.kt @@ -10,7 +10,7 @@ import com.tencent.devops.auth.provider.sample.service.SamplePermissionApplyServ import com.tencent.devops.auth.provider.sample.service.SamplePermissionExtService import com.tencent.devops.auth.provider.sample.service.SamplePermissionItsmCallbackService import com.tencent.devops.auth.provider.sample.service.SamplePermissionMigrateService -import com.tencent.devops.auth.provider.sample.service.SamplePermissionResourceGroupAndMemberFacadeService +import com.tencent.devops.auth.provider.sample.service.SamplePermissionManageFacadeService import com.tencent.devops.auth.provider.sample.service.SamplePermissionResourceGroupPermissionService import com.tencent.devops.auth.provider.sample.service.SamplePermissionResourceGroupService import com.tencent.devops.auth.provider.sample.service.SamplePermissionResourceGroupSyncService @@ -30,7 +30,7 @@ import com.tencent.devops.auth.service.iam.PermissionExtService import com.tencent.devops.auth.service.iam.PermissionItsmCallbackService import com.tencent.devops.auth.service.iam.PermissionMigrateService import com.tencent.devops.auth.service.iam.PermissionProjectService -import com.tencent.devops.auth.service.iam.PermissionResourceGroupAndMemberFacadeService +import com.tencent.devops.auth.service.iam.PermissionManageFacadeService import com.tencent.devops.auth.service.iam.PermissionResourceGroupPermissionService import com.tencent.devops.auth.service.iam.PermissionResourceGroupService import com.tencent.devops.auth.service.iam.PermissionResourceGroupSyncService @@ -86,8 +86,8 @@ class MockAuthConfiguration { fun samplePermissionResourceGroupService() = SamplePermissionResourceGroupService() @Bean - @ConditionalOnMissingBean(PermissionResourceGroupAndMemberFacadeService::class) - fun samplePermissionResourceGroupAndMemberFacadeService() = SamplePermissionResourceGroupAndMemberFacadeService() + @ConditionalOnMissingBean(PermissionManageFacadeService::class) + fun samplePermissionManageFacadeService() = SamplePermissionManageFacadeService() @Bean @ConditionalOnMissingBean(PermissionResourceGroupPermissionService::class) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionResourceGroupAndMemberFacadeService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionManageFacadeService.kt similarity index 95% rename from src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionResourceGroupAndMemberFacadeService.kt rename to src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionManageFacadeService.kt index 27a9ada5151..f3e9313db7e 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionResourceGroupAndMemberFacadeService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionManageFacadeService.kt @@ -14,10 +14,10 @@ import com.tencent.devops.auth.pojo.request.RemoveMemberFromProjectReq import com.tencent.devops.auth.pojo.vo.BatchOperateGroupMemberCheckVo import com.tencent.devops.auth.pojo.vo.GroupDetailsInfoVo import com.tencent.devops.auth.pojo.vo.MemberGroupCountWithPermissionsVo -import com.tencent.devops.auth.service.iam.PermissionResourceGroupAndMemberFacadeService +import com.tencent.devops.auth.service.iam.PermissionManageFacadeService import com.tencent.devops.common.api.model.SQLPage -class SamplePermissionResourceGroupAndMemberFacadeService : PermissionResourceGroupAndMemberFacadeService { +class SamplePermissionManageFacadeService : PermissionManageFacadeService { override fun getMemberGroupsDetails( projectId: String, memberId: String, diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/service/ServiceResourceGroupResourceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/service/ServiceResourceGroupResourceImpl.kt index cea4a8350a8..52fde466e35 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/service/ServiceResourceGroupResourceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/service/ServiceResourceGroupResourceImpl.kt @@ -5,7 +5,7 @@ import com.tencent.devops.auth.pojo.dto.GroupAddDTO import com.tencent.devops.auth.pojo.request.CustomGroupCreateReq import com.tencent.devops.auth.pojo.vo.GroupDetailsInfoVo import com.tencent.devops.auth.pojo.vo.GroupPermissionDetailVo -import com.tencent.devops.auth.service.iam.PermissionResourceGroupAndMemberFacadeService +import com.tencent.devops.auth.service.iam.PermissionManageFacadeService import com.tencent.devops.auth.service.iam.PermissionResourceGroupPermissionService import com.tencent.devops.auth.service.iam.PermissionResourceGroupService import com.tencent.devops.common.api.model.SQLPage @@ -17,7 +17,7 @@ import com.tencent.devops.common.web.RestResource class ServiceResourceGroupResourceImpl( val permissionResourceGroupService: PermissionResourceGroupService, val resourceGroupPermissionService: PermissionResourceGroupPermissionService, - val resourceGroupAndMemberFacadeService: PermissionResourceGroupAndMemberFacadeService + val permissionManageFacadeService: PermissionManageFacadeService ) : ServiceResourceGroupResource { override fun getGroupPermissionDetail( projectCode: String, @@ -45,7 +45,7 @@ class ServiceResourceGroupResourceImpl( limit: Int? ): Result> { return Result( - resourceGroupAndMemberFacadeService.getMemberGroupsDetails( + permissionManageFacadeService.getMemberGroupsDetails( projectId = projectCode, resourceType = resourceType, memberId = memberId, diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/service/ServiceResourceMemberResourceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/service/ServiceResourceMemberResourceImpl.kt index ff178f35ab1..aadd867c2b1 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/service/ServiceResourceMemberResourceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/service/ServiceResourceMemberResourceImpl.kt @@ -2,7 +2,7 @@ package com.tencent.devops.auth.resources.service import com.tencent.devops.auth.api.service.ServiceResourceMemberResource import com.tencent.devops.auth.pojo.request.GroupMemberSingleRenewalReq -import com.tencent.devops.auth.service.iam.PermissionResourceGroupAndMemberFacadeService +import com.tencent.devops.auth.service.iam.PermissionManageFacadeService import com.tencent.devops.auth.service.iam.PermissionResourceMemberService import com.tencent.devops.common.api.pojo.Result import com.tencent.devops.common.auth.api.pojo.BkAuthGroup @@ -17,7 +17,7 @@ import java.util.concurrent.TimeUnit @RestResource class ServiceResourceMemberResourceImpl( private val permissionResourceMemberService: PermissionResourceMemberService, - private val permissionResourceGroupAndMemberFacadeService: PermissionResourceGroupAndMemberFacadeService + private val permissionManageFacadeService: PermissionManageFacadeService ) : ServiceResourceMemberResource { @BkApiPermission([BkApiHandleType.API_OPEN_TOKEN_CHECK]) override fun getResourceGroupMembers( @@ -109,7 +109,7 @@ class ServiceResourceMemberResourceImpl( renewalConditionReq: GroupMemberSingleRenewalReq ): Result { return Result( - permissionResourceGroupAndMemberFacadeService.renewalGroupMember( + permissionManageFacadeService.renewalGroupMember( userId = userId, projectCode = projectCode, renewalConditionReq = renewalConditionReq diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceGroupResourceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceGroupResourceImpl.kt index b03e24a3c12..2d389901bb1 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceGroupResourceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceGroupResourceImpl.kt @@ -37,7 +37,7 @@ import com.tencent.devops.auth.pojo.enum.OperateChannel import com.tencent.devops.auth.pojo.request.GroupMemberCommonConditionReq import com.tencent.devops.auth.pojo.vo.GroupDetailsInfoVo import com.tencent.devops.auth.pojo.vo.IamGroupPoliciesVo -import com.tencent.devops.auth.service.iam.PermissionResourceGroupAndMemberFacadeService +import com.tencent.devops.auth.service.iam.PermissionManageFacadeService import com.tencent.devops.auth.service.iam.PermissionResourceGroupPermissionService import com.tencent.devops.auth.service.iam.PermissionResourceGroupService import com.tencent.devops.auth.service.iam.PermissionResourceMemberService @@ -52,7 +52,7 @@ import org.springframework.beans.factory.annotation.Autowired class UserAuthResourceGroupResourceImpl @Autowired constructor( private val permissionResourceGroupService: PermissionResourceGroupService, private val permissionResourceMemberService: PermissionResourceMemberService, - private val permissionResourceGroupAndMemberFacadeService: PermissionResourceGroupAndMemberFacadeService, + private val permissionManageFacadeService: PermissionManageFacadeService, private val permissionResourceGroupPermissionService: PermissionResourceGroupPermissionService, private val permissionResourceValidateService: PermissionResourceValidateService ) : UserAuthResourceGroupResource { @@ -94,7 +94,7 @@ class UserAuthResourceGroupResourceImpl @Autowired constructor( ) return Result( - permissionResourceGroupAndMemberFacadeService.getMemberGroupsDetails( + permissionManageFacadeService.getMemberGroupsDetails( projectId = projectId, resourceType = resourceType, memberId = memberId, @@ -135,7 +135,7 @@ class UserAuthResourceGroupResourceImpl @Autowired constructor( groupId: Int ): Result { return Result( - permissionResourceGroupAndMemberFacadeService.batchDeleteResourceGroupMembersFromManager( + permissionManageFacadeService.batchDeleteResourceGroupMembersFromManager( userId = userId, projectCode = projectId, removeMemberDTO = GroupMemberCommonConditionReq( diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceMemberResourceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceMemberResourceImpl.kt index fd01f260d00..023cd3c7c1a 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceMemberResourceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceMemberResourceImpl.kt @@ -13,7 +13,7 @@ import com.tencent.devops.auth.pojo.request.RemoveMemberFromProjectReq import com.tencent.devops.auth.pojo.vo.BatchOperateGroupMemberCheckVo import com.tencent.devops.auth.pojo.vo.GroupDetailsInfoVo import com.tencent.devops.auth.pojo.vo.MemberGroupCountWithPermissionsVo -import com.tencent.devops.auth.service.iam.PermissionResourceGroupAndMemberFacadeService +import com.tencent.devops.auth.service.iam.PermissionManageFacadeService import com.tencent.devops.auth.service.iam.PermissionResourceMemberService import com.tencent.devops.auth.service.iam.PermissionResourceValidateService import com.tencent.devops.auth.service.iam.PermissionService @@ -29,7 +29,7 @@ import com.tencent.devops.common.web.RestResource class UserAuthResourceMemberResourceImpl( private val permissionResourceMemberService: PermissionResourceMemberService, private val permissionService: PermissionService, - private val permissionResourceGroupAndMemberFacadeService: PermissionResourceGroupAndMemberFacadeService, + private val permissionManageFacadeService: PermissionManageFacadeService, private val permissionResourceValidateService: PermissionResourceValidateService ) : UserAuthResourceMemberResource { override fun listProjectMembers( @@ -72,7 +72,7 @@ class UserAuthResourceMemberResourceImpl( projectMembersQueryConditionReq: ProjectMembersQueryConditionReq ): Result> { return Result( - permissionResourceGroupAndMemberFacadeService.listProjectMembersByComplexConditions( + permissionManageFacadeService.listProjectMembersByComplexConditions( conditionReq = projectMembersQueryConditionReq ) ) @@ -84,13 +84,13 @@ class UserAuthResourceMemberResourceImpl( projectId: String, renewalConditionReq: GroupMemberSingleRenewalReq ): Result { - permissionResourceGroupAndMemberFacadeService.renewalGroupMember( + permissionManageFacadeService.renewalGroupMember( userId = userId, projectCode = projectId, renewalConditionReq = renewalConditionReq ) return Result( - permissionResourceGroupAndMemberFacadeService.getMemberGroupsDetails( + permissionManageFacadeService.getMemberGroupsDetails( projectId = projectId, memberId = renewalConditionReq.targetMember.id, iamGroupIds = listOf(renewalConditionReq.groupId) @@ -105,7 +105,7 @@ class UserAuthResourceMemberResourceImpl( renewalConditionReq: GroupMemberRenewalConditionReq ): Result { return Result( - permissionResourceGroupAndMemberFacadeService.batchRenewalGroupMembersFromManager( + permissionManageFacadeService.batchRenewalGroupMembersFromManager( userId = userId, projectCode = projectId, renewalConditionReq = renewalConditionReq @@ -120,7 +120,7 @@ class UserAuthResourceMemberResourceImpl( removeMemberDTO: GroupMemberCommonConditionReq ): Result { return Result( - permissionResourceGroupAndMemberFacadeService.batchDeleteResourceGroupMembersFromManager( + permissionManageFacadeService.batchDeleteResourceGroupMembersFromManager( userId = userId, projectCode = projectId, removeMemberDTO = removeMemberDTO @@ -135,7 +135,7 @@ class UserAuthResourceMemberResourceImpl( handoverMemberDTO: GroupMemberHandoverConditionReq ): Result { return Result( - permissionResourceGroupAndMemberFacadeService.batchHandoverGroupMembersFromManager( + permissionManageFacadeService.batchHandoverGroupMembersFromManager( userId = userId, projectCode = projectId, handoverMemberDTO = handoverMemberDTO @@ -151,7 +151,7 @@ class UserAuthResourceMemberResourceImpl( conditionReq: GroupMemberCommonConditionReq ): Result { return Result( - permissionResourceGroupAndMemberFacadeService.batchOperateGroupMembersCheck( + permissionManageFacadeService.batchOperateGroupMembersCheck( userId = userId, projectCode = projectId, batchOperateType = batchOperateType, @@ -167,7 +167,7 @@ class UserAuthResourceMemberResourceImpl( removeMemberFromProjectReq: RemoveMemberFromProjectReq ): Result> { return Result( - permissionResourceGroupAndMemberFacadeService.removeMemberFromProject( + permissionManageFacadeService.removeMemberFromProject( userId = userId, projectCode = projectId, removeMemberFromProjectReq = removeMemberFromProjectReq @@ -182,7 +182,7 @@ class UserAuthResourceMemberResourceImpl( removeMemberFromProjectReq: RemoveMemberFromProjectReq ): Result { return Result( - permissionResourceGroupAndMemberFacadeService.removeMemberFromProjectCheck( + permissionManageFacadeService.removeMemberFromProjectCheck( userId = userId, projectCode = projectId, removeMemberFromProjectReq = removeMemberFromProjectReq @@ -208,7 +208,7 @@ class UserAuthResourceMemberResourceImpl( operateChannel = operateChannel ?: OperateChannel.MANAGER ) return Result( - permissionResourceGroupAndMemberFacadeService.getMemberGroupsCount( + permissionManageFacadeService.getMemberGroupsCount( projectCode = projectId, memberId = memberId, groupName = groupName, diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionResourceGroupAndMemberFacadeService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionManageFacadeService.kt similarity index 94% rename from src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionResourceGroupAndMemberFacadeService.kt rename to src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionManageFacadeService.kt index 7d621e79f30..1004c429b47 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionResourceGroupAndMemberFacadeService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionManageFacadeService.kt @@ -16,7 +16,10 @@ import com.tencent.devops.auth.pojo.vo.GroupDetailsInfoVo import com.tencent.devops.auth.pojo.vo.MemberGroupCountWithPermissionsVo import com.tencent.devops.common.api.model.SQLPage -interface PermissionResourceGroupAndMemberFacadeService { +/** + * 权限管理门面类 + */ +interface PermissionManageFacadeService { /** * 查询成员所在资源用户组详情 * 管理员视角返回用户直接加入/模板加入的用户组 @@ -107,25 +110,36 @@ interface PermissionResourceGroupAndMemberFacadeService { memberId: String ): Pair/*引起代持人权限失效的用户组*/, List/*引起代持人权限失效的流水线*/> - // 无需审批版本 + /** + * 续期用户权限-无需审批版本 + * */ fun renewalGroupMember( userId: String, projectCode: String, renewalConditionReq: GroupMemberSingleRenewalReq ): Boolean + /** + * 批量续期用户权限-管理员视角 + * */ fun batchRenewalGroupMembersFromManager( userId: String, projectCode: String, renewalConditionReq: GroupMemberRenewalConditionReq ): Boolean + /** + * 批量交接-管理员视角 + * */ fun batchHandoverGroupMembersFromManager( userId: String, projectCode: String, handoverMemberDTO: GroupMemberHandoverConditionReq ): Boolean + /** + * 批量移除-管理员视角 + * */ fun batchDeleteResourceGroupMembersFromManager( userId: String, projectCode: String, From 36cd09bbd78da7c45902c3075f328c05eefff9a3 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Thu, 14 Nov 2024 18:07:52 +0800 Subject: [PATCH 03/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/api/user/UserAuthHandoverResource.kt | 101 +++ .../user/UserAuthResourceMemberResource.kt | 35 +- .../devops/auth/constant/AuthI18nConstants.kt | 4 + .../devops/auth/constant/AuthMessageCode.kt | 8 + .../devops/auth/pojo/dto/HandoverDetailDTO.kt | 18 + .../pojo/dto/HandoverOverviewCreateDTO.kt | 26 + .../auth/pojo/dto/InvalidAuthorizationsDTO.kt | 11 + .../devops/auth/pojo/enum/HandoverAction.kt | 21 + .../devops/auth/pojo/enum/HandoverStatus.kt | 24 + .../devops/auth/pojo/enum/HandoverType.kt | 18 + .../request/GroupMemberCommonConditionReq.kt | 5 +- .../GroupMemberHandoverConditionReq.kt | 3 - .../request/GroupMemberRemoveConditionReq.kt | 64 ++ .../request/GroupMemberRenewalConditionReq.kt | 3 - .../pojo/request/HandoverDetailsQueryReq.kt | 18 + .../pojo/request/HandoverOverviewQueryReq.kt | 33 + .../pojo/request/HandoverOverviewUpdateReq.kt | 18 + .../pojo/vo/BatchOperateGroupMemberCheckVo.kt | 8 +- .../pojo/vo/HandoverAuthorizationDetailVo.kt | 16 + .../auth/pojo/vo/HandoverGroupDetailVo.kt | 19 + .../devops/auth/pojo/vo/HandoverOverviewVo.kt | 34 + ...rmissionsVo.kt => ResourceType2CountVo.kt} | 7 +- .../devops/auth/dao/AuthHandoverDetailDao.kt | 128 +++ .../auth/dao/AuthHandoverOverviewDao.kt | 137 ++++ .../devops/auth/dao/AuthResourceGroupDao.kt | 8 + .../auth/dao/AuthResourceGroupMemberDao.kt | 49 +- .../rbac/config/RbacAuthConfiguration.kt | 37 +- .../provider/rbac/service/RbacCacheService.kt | 46 +- .../service/RbacPermissionHandoverService.kt | 260 +++++++ .../RbacPermissionManageFacadeServiceImpl.kt | 735 +++++++++++++----- .../RbacPermissionResourceGroupService.kt | 6 +- .../RbacPermissionResourceGroupSyncService.kt | 3 +- .../RbacPermissionResourceMemberService.kt | 26 +- .../rbac/service/RbacPermissionService.kt | 4 +- .../service/migrate/AbMigratePolicyService.kt | 4 +- .../service/migrate/MigrateV0PolicyService.kt | 4 +- .../sample/config/MockAuthConfiguration.kt | 6 + .../SamplePermissionHandoverService.kt | 62 ++ .../SamplePermissionManageFacadeService.kt | 25 +- .../user/UserAuthHandoverResourceImpl.kt | 70 ++ .../user/UserAuthResourceGroupResourceImpl.kt | 8 +- .../UserAuthResourceMemberResourceImpl.kt | 38 +- .../service/PermissionAuthorizationService.kt | 9 + .../PermissionAuthorizationServiceImpl.kt | 61 +- .../service/iam/PermissionHandoverService.kt | 70 ++ .../iam/PermissionManageFacadeService.kt | 34 +- .../lock/HandleHandoverApplicationLock.kt | 45 ++ .../i18n/auth/message_en_US.properties | 10 + .../i18n/auth/message_zh_CN.properties | 11 + support-files/sql/1001_ci_auth_ddl_mysql.sql | 31 + 50 files changed, 2142 insertions(+), 279 deletions(-) create mode 100644 src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthHandoverResource.kt create mode 100644 src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/dto/HandoverDetailDTO.kt create mode 100644 src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/dto/HandoverOverviewCreateDTO.kt create mode 100644 src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/dto/InvalidAuthorizationsDTO.kt create mode 100644 src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/HandoverAction.kt create mode 100644 src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/HandoverStatus.kt create mode 100644 src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/HandoverType.kt create mode 100644 src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberRemoveConditionReq.kt create mode 100644 src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverDetailsQueryReq.kt create mode 100644 src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverOverviewQueryReq.kt create mode 100644 src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverOverviewUpdateReq.kt create mode 100644 src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/HandoverAuthorizationDetailVo.kt create mode 100644 src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/HandoverGroupDetailVo.kt create mode 100644 src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/HandoverOverviewVo.kt rename src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/{MemberGroupCountWithPermissionsVo.kt => ResourceType2CountVo.kt} (63%) create mode 100644 src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthHandoverDetailDao.kt create mode 100644 src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthHandoverOverviewDao.kt create mode 100644 src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverService.kt create mode 100644 src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionHandoverService.kt create mode 100644 src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthHandoverResourceImpl.kt create mode 100644 src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionHandoverService.kt create mode 100644 src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/lock/HandleHandoverApplicationLock.kt diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthHandoverResource.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthHandoverResource.kt new file mode 100644 index 00000000000..7624c00df3c --- /dev/null +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthHandoverResource.kt @@ -0,0 +1,101 @@ +package com.tencent.devops.auth.api.user + +import com.tencent.devops.auth.pojo.request.HandoverDetailsQueryReq +import com.tencent.devops.auth.pojo.request.HandoverOverviewQueryReq +import com.tencent.devops.auth.pojo.request.HandoverOverviewUpdateReq +import com.tencent.devops.auth.pojo.vo.HandoverAuthorizationDetailVo +import com.tencent.devops.auth.pojo.vo.HandoverGroupDetailVo +import com.tencent.devops.auth.pojo.vo.HandoverOverviewVo +import com.tencent.devops.auth.pojo.vo.ResourceType2CountVo +import com.tencent.devops.common.api.auth.AUTH_HEADER_USER_ID +import com.tencent.devops.common.api.auth.AUTH_HEADER_USER_ID_DEFAULT_VALUE +import com.tencent.devops.common.api.model.SQLPage +import com.tencent.devops.common.api.pojo.Result +import com.tencent.devops.common.auth.api.pojo.ResourceAuthorizationHandoverConditionRequest +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.tags.Tag +import javax.ws.rs.Consumes +import javax.ws.rs.GET +import javax.ws.rs.HeaderParam +import javax.ws.rs.POST +import javax.ws.rs.Path +import javax.ws.rs.PathParam +import javax.ws.rs.Produces +import javax.ws.rs.core.MediaType + +@Tag(name = "USER_RESOURCE_AUTHORIZATION", description = "用户-权限-交接相关") +@Path("/user/auth/handover/") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +interface UserAuthHandoverResource { + @POST + @Path("/{projectId}/handoverAuthorizationsApplication") + @Operation(summary = "交接授权申请") + fun handoverAuthorizationsApplication( + @Parameter(description = "用户ID", required = true, example = AUTH_HEADER_USER_ID_DEFAULT_VALUE) + @HeaderParam(AUTH_HEADER_USER_ID) + userId: String, + @Parameter(description = "项目ID", required = true) + @PathParam("projectId") + projectId: String, + @Parameter(description = "资源授权交接条件实体", required = true) + condition: ResourceAuthorizationHandoverConditionRequest + ): Result + + @POST + @Path("/listHandoverOverviews") + @Operation(summary = "权限交接总览列表") + fun listHandoverOverviews( + @Parameter(description = "用户名", required = true) + @HeaderParam(AUTH_HEADER_USER_ID) + userId: String, + @Parameter(description = "权限交接总览查询", required = true) + queryRequest: HandoverOverviewQueryReq + ): Result> + + @GET + @Path("/{flowNo}/getResourceType2CountOfHandover") + @Operation(summary = "获取资源授权管理") + fun getResourceType2CountOfHandover( + @Parameter(description = "用户名", required = true) + @HeaderParam(AUTH_HEADER_USER_ID) + userId: String, + @Parameter(description = "流程号", required = true) + @PathParam("flowNo") + flowNo: String + ): Result> + + @POST + @Path("/listAuthorizationsOfHandover") + @Operation(summary = "获取交接单中授权相关") + fun listAuthorizationsOfHandover( + @Parameter(description = "用户名", required = true) + @HeaderParam(AUTH_HEADER_USER_ID) + userId: String, + @Parameter(description = "权限交接详细查询请求体", required = true) + queryReq: HandoverDetailsQueryReq + ): Result> + + @POST + @Path("/listGroupsOfHandover") + @Operation(summary = "获取交接单中用户组相关") + fun listGroupsOfHandover( + @Parameter(description = "用户名", required = true) + @HeaderParam(AUTH_HEADER_USER_ID) + userId: String, + @Parameter(description = "权限交接详细查询请求体", required = true) + queryReq: HandoverDetailsQueryReq + ): Result> + + @POST + @Path("/handleHanoverApplication") + @Operation(summary = "处理交接审批单") + fun handleHanoverApplication( + @Parameter(description = "用户名", required = true) + @HeaderParam(AUTH_HEADER_USER_ID) + userId: String, + @Parameter(description = "更新权限交接总览请求体", required = true) + request: HandoverOverviewUpdateReq + ): Result +} diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthResourceMemberResource.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthResourceMemberResource.kt index f5cab40a861..955b0761da6 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthResourceMemberResource.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthResourceMemberResource.kt @@ -5,13 +5,14 @@ import com.tencent.devops.auth.pojo.enum.BatchOperateType import com.tencent.devops.auth.pojo.enum.OperateChannel import com.tencent.devops.auth.pojo.request.GroupMemberCommonConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberHandoverConditionReq +import com.tencent.devops.auth.pojo.request.GroupMemberRemoveConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberRenewalConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberSingleRenewalReq import com.tencent.devops.auth.pojo.request.ProjectMembersQueryConditionReq import com.tencent.devops.auth.pojo.request.RemoveMemberFromProjectReq import com.tencent.devops.auth.pojo.vo.BatchOperateGroupMemberCheckVo import com.tencent.devops.auth.pojo.vo.GroupDetailsInfoVo -import com.tencent.devops.auth.pojo.vo.MemberGroupCountWithPermissionsVo +import com.tencent.devops.auth.pojo.vo.ResourceType2CountVo import com.tencent.devops.common.api.auth.AUTH_HEADER_USER_ID import com.tencent.devops.common.api.model.SQLPage import com.tencent.devops.common.api.pojo.Result @@ -120,7 +121,21 @@ interface UserAuthResourceMemberResource { @PathParam("projectId") projectId: String, @Parameter(description = "批量移除成员请求实体") - removeMemberDTO: GroupMemberCommonConditionReq + removeMemberDTO: GroupMemberRemoveConditionReq + ): Result + + @DELETE + @Path("/batch/personal/remove") + @Operation(summary = "批量退出用户组成员--个人视角") + fun batchRemoveGroupMembersFromPersonal( + @Parameter(description = "用户名", required = true) + @HeaderParam(AUTH_HEADER_USER_ID) + userId: String, + @Parameter(description = "项目ID", required = true) + @PathParam("projectId") + projectId: String, + @Parameter(description = "批量移除成员请求实体") + removeMemberDTO: GroupMemberRemoveConditionReq ): Result @PUT @@ -137,6 +152,20 @@ interface UserAuthResourceMemberResource { handoverMemberDTO: GroupMemberHandoverConditionReq ): Result + @PUT + @Path("/batch/personal/handover") + @Operation(summary = "批量交接用户组成员--个人视角") + fun batchHandoverApplicationFromPersonal( + @Parameter(description = "用户名", required = true) + @HeaderParam(AUTH_HEADER_USER_ID) + userId: String, + @Parameter(description = "项目ID", required = true) + @PathParam("projectId") + projectId: String, + @Parameter(description = "批量交接成员请求实体") + handoverMemberDTO: GroupMemberHandoverConditionReq + ): Result + @POST @Path("/batch/{batchOperateType}/check/") @Operation(summary = "批量操作用户组检查") @@ -216,5 +245,5 @@ interface UserAuthResourceMemberResource { @QueryParam("operateChannel") @Parameter(description = "操作渠道") operateChannel: OperateChannel? - ): Result> + ): Result> } diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/constant/AuthI18nConstants.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/constant/AuthI18nConstants.kt index 4be2b229dfc..eca12bd7ec2 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/constant/AuthI18nConstants.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/constant/AuthI18nConstants.kt @@ -47,4 +47,8 @@ object AuthI18nConstants { const val BK_MEMBER_EXPIRED_AT_DISPLAY_EXPIRED = "bkMemberExpiredAtDisplayExpired" // 有效期: 已过期 const val BK_MEMBER_EXPIRED_AT_DISPLAY_NORMAL = "bkMemberExpiredAtDisplayNormal" // 有效期: {0}天 const val BK_MEMBER_EXPIRED_AT_DISPLAY_PERMANENT = "bkMemberExpiredAtDisplayPermanent" // 有效期: 永久 + + const val BK_APPLY_TO_HANDOVER = "bkApplyToHandover" // 申请移交 + const val BK_HANDOVER_GROUPS = "bkHandoverGroups" // {0}个权限用户组 + const val BK_HANDOVER_AUTHORIZATIONS = "bkHandoverAuthorizations" // {0}个授权 } diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/constant/AuthMessageCode.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/constant/AuthMessageCode.kt index 4b66ce68fbb..8c3d6adb049 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/constant/AuthMessageCode.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/constant/AuthMessageCode.kt @@ -142,4 +142,12 @@ object AuthMessageCode { const val INVALID_EXPIRED_PERM_NOT_ALLOW_TO_HANDOVER = "2121089" // 已过期的权限不允许交接 const val ERROR_USER_INFORMATION_NOT_SYNCED = "2121090" // 请等待第二天用户信息同步后再尝试操作,因为新入职用户的信息尚未同步完成。 + + const val ERROR_HANDOVER_OVERVIEW_NOT_EXIST = "2121091" // 权限交接记录不存在 + const val ERROR_HANDOVER_FINISH = "2121092" // 该交接申请单已被处理,不允许重复操作 + const val ERROR_HANDOVER_REVOKE = "2121093" // 由于您不是该交接申请单的发起人,无法进行撤销操作 + const val ERROR_HANDOVER_APPROVAL = "2121094" // 由于您不是该交接申请单的审批人,无法进行任何操作 + const val ERROR_HANDOVER_HANDLE = "2121095" // 该交接申请单正在被处理中,请耐心等待 + const val ERROR_HANDOVER_AUTHORIZATION = "2121096" // 交接操作不合法,用户没有对应授权的权限 + } diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/dto/HandoverDetailDTO.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/dto/HandoverDetailDTO.kt new file mode 100644 index 00000000000..19e842c289d --- /dev/null +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/dto/HandoverDetailDTO.kt @@ -0,0 +1,18 @@ +package com.tencent.devops.auth.pojo.dto + +import com.tencent.devops.auth.pojo.enum.HandoverType +import io.swagger.v3.oas.annotations.media.Schema + +@Schema(title = "权限交接详细表") +data class HandoverDetailDTO( + @get:Schema(title = "项目ID") + val projectCode: String, + @get:Schema(title = "流程单号") + val flowNo: String, + @get:Schema(title = "授权/组ID") + val itemId: String, + @get:Schema(title = "组/授权资源关联的资源类型") + val resourceType: String, + @get:Schema(title = "交接类型") + val handoverType: HandoverType +) diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/dto/HandoverOverviewCreateDTO.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/dto/HandoverOverviewCreateDTO.kt new file mode 100644 index 00000000000..689a9c5625c --- /dev/null +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/dto/HandoverOverviewCreateDTO.kt @@ -0,0 +1,26 @@ +package com.tencent.devops.auth.pojo.dto + +import com.tencent.devops.auth.pojo.enum.HandoverStatus +import io.swagger.v3.oas.annotations.media.Schema + +@Schema(title = "创建权限交接总览DTO") +data class HandoverOverviewCreateDTO( + @get:Schema(title = "项目ID") + val projectCode: String, + @get:Schema(title = "项目ID") + var title: String, + @get:Schema(title = "流程单号") + var flowNo: String, + @get:Schema(title = "申请人") + val applicant: String, + @get:Schema(title = "审批人") + val approver: String, + @get:Schema(title = "审批结果") + val handoverStatus: HandoverStatus, + @get:Schema(title = "用户组个数") + val groupCount: Int, + @get:Schema(title = "授权个数") + val authorizationCount: Int, + @get:Schema(title = "备注") + val remark: String? = null +) diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/dto/InvalidAuthorizationsDTO.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/dto/InvalidAuthorizationsDTO.kt new file mode 100644 index 00000000000..f49626f8c55 --- /dev/null +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/dto/InvalidAuthorizationsDTO.kt @@ -0,0 +1,11 @@ +package com.tencent.devops.auth.pojo.dto + +import io.swagger.v3.oas.annotations.media.Schema + +@Schema(title = "移除/移交用户组成员导致的无效授权") +data class InvalidAuthorizationsDTO( + @get:Schema(title = "引起代持人权限失效的用户组") + val invalidGroupIds: List, + @get:Schema(title = "引起代持人权限失效的流水线") + val invalidAuthorizations: List +) diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/HandoverAction.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/HandoverAction.kt new file mode 100644 index 00000000000..7f048434a85 --- /dev/null +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/HandoverAction.kt @@ -0,0 +1,21 @@ +package com.tencent.devops.auth.pojo.enum + +enum class HandoverAction(val value: Int) { + // 审批成功 + AGREE(1), + + // 审批驳回 + REJECT(2), + + // 撤销 + REVOKE(3); + + companion object { + fun get(value: Int): HandoverAction { + HandoverAction.values().forEach { + if (value == it.value) return it + } + throw IllegalArgumentException("No enum for constant $value") + } + } +} diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/HandoverStatus.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/HandoverStatus.kt new file mode 100644 index 00000000000..aaf82e6e9ac --- /dev/null +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/HandoverStatus.kt @@ -0,0 +1,24 @@ +package com.tencent.devops.auth.pojo.enum + +enum class HandoverStatus(val value: Int) { + // 审批中 + PENDING(0), + + // 审批成功 + SUCCEED(1), + + // 审批驳回 + REJECT(2), + + // 撤销 + REVOKE(3); + + companion object { + fun get(value: Int): HandoverStatus { + HandoverStatus.values().forEach { + if (value == it.value) return it + } + throw IllegalArgumentException("No enum for constant $value") + } + } +} diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/HandoverType.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/HandoverType.kt new file mode 100644 index 00000000000..37f5267630e --- /dev/null +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/HandoverType.kt @@ -0,0 +1,18 @@ +package com.tencent.devops.auth.pojo.enum + +enum class HandoverType(val value: String) { + // 用户组 + GROUP("group"), + + // 授权 + AUTHORIZATION("authorization"); + + companion object { + fun get(value: String): HandoverType { + HandoverType.values().forEach { + if (value == it.value) return it + } + throw IllegalArgumentException("No enum for constant $value") + } + } +} diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberCommonConditionReq.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberCommonConditionReq.kt index 3261a5f3774..2a82af2f08c 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberCommonConditionReq.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberCommonConditionReq.kt @@ -12,8 +12,6 @@ open class GroupMemberCommonConditionReq( open val resourceTypes: List = emptyList(), @get:Schema(title = "全量选择") open val allSelection: Boolean = false, - @get:Schema(title = "是否排除唯一管理员组") - open var excludedUniqueManagerGroup: Boolean = false, @get:Schema(title = "目标对象") open val targetMember: ResourceMemberInfo, @get:Schema(title = "操作渠道") @@ -21,7 +19,6 @@ open class GroupMemberCommonConditionReq( ) { override fun toString(): String { return "GroupMemberCommonConditionReq(groupIds=$groupIds,resourceTypes=$resourceTypes," + - "allSelection=$allSelection,excludedUniqueManagerGroup=$excludedUniqueManagerGroup," + - "targetMember=$targetMember,operateChannel=$operateChannel)" + "allSelection=$allSelection,targetMember=$targetMember,operateChannel=$operateChannel)" } } diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberHandoverConditionReq.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberHandoverConditionReq.kt index e99d5dd99c5..7e32532c48e 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberHandoverConditionReq.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberHandoverConditionReq.kt @@ -41,8 +41,6 @@ data class GroupMemberHandoverConditionReq( override val resourceTypes: List = emptyList(), @get:Schema(title = "全量选择") override val allSelection: Boolean = false, - @get:Schema(title = "是否排除唯一管理员组") - override var excludedUniqueManagerGroup: Boolean = false, @get:Schema(title = "目标对象") override val targetMember: ResourceMemberInfo, @get:Schema(title = "操作渠道") @@ -53,7 +51,6 @@ data class GroupMemberHandoverConditionReq( groupIds = groupIds, resourceTypes = resourceTypes, allSelection = allSelection, - excludedUniqueManagerGroup = excludedUniqueManagerGroup, operateChannel = operateChannel, targetMember = targetMember ) { diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberRemoveConditionReq.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberRemoveConditionReq.kt new file mode 100644 index 00000000000..1c4e68da1e6 --- /dev/null +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberRemoveConditionReq.kt @@ -0,0 +1,64 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. + * + * A copy of the MIT License is included in this file. + * + * + * Terms of the MIT License: + * --------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.tencent.devops.auth.pojo.request + +import com.tencent.devops.auth.constant.AuthMessageCode.INVALID_HANDOVER_TO +import com.tencent.devops.auth.pojo.ResourceMemberInfo +import com.tencent.devops.auth.pojo.enum.OperateChannel +import com.tencent.devops.common.api.exception.ErrorCodeException +import io.swagger.v3.oas.annotations.media.Schema + +@Schema(title = "用户组成员移除条件请求体") +data class GroupMemberRemoveConditionReq( + @get:Schema(title = "组IDs") + override val groupIds: List = emptyList(), + @get:Schema(title = "全选的资源类型") + override val resourceTypes: List = emptyList(), + @get:Schema(title = "全量选择") + override val allSelection: Boolean = false, + @get:Schema(title = "目标对象") + override val targetMember: ResourceMemberInfo, + @get:Schema(title = "操作渠道") + override val operateChannel: OperateChannel = OperateChannel.MANAGER, + @get:Schema(title = "授予人") + val handoverTo: ResourceMemberInfo? = null +) : GroupMemberCommonConditionReq( + groupIds = groupIds, + resourceTypes = resourceTypes, + allSelection = allSelection, + operateChannel = operateChannel, + targetMember = targetMember +) { + fun checkHandoverTo() { + if (handoverTo == null || handoverTo.id == targetMember.id) { + throw ErrorCodeException( + errorCode = INVALID_HANDOVER_TO + ) + } + } +} diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberRenewalConditionReq.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberRenewalConditionReq.kt index 6ed88f07a21..6dc53591ffa 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberRenewalConditionReq.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/GroupMemberRenewalConditionReq.kt @@ -39,8 +39,6 @@ data class GroupMemberRenewalConditionReq( override val resourceTypes: List = emptyList(), @get:Schema(title = "全量选择") override val allSelection: Boolean = false, - @get:Schema(title = "是否排除唯一管理员组") - override var excludedUniqueManagerGroup: Boolean = false, @get:Schema(title = "目标对象") override val targetMember: ResourceMemberInfo, @get:Schema(title = "操作渠道") @@ -51,7 +49,6 @@ data class GroupMemberRenewalConditionReq( groupIds = groupIds, resourceTypes = resourceTypes, allSelection = allSelection, - excludedUniqueManagerGroup = excludedUniqueManagerGroup, operateChannel = operateChannel, targetMember = targetMember ) diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverDetailsQueryReq.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverDetailsQueryReq.kt new file mode 100644 index 00000000000..1cd3cbb7d3b --- /dev/null +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverDetailsQueryReq.kt @@ -0,0 +1,18 @@ +package com.tencent.devops.auth.pojo.request + +import com.tencent.devops.auth.pojo.enum.HandoverType +import io.swagger.v3.oas.annotations.media.Schema + +@Schema(title = "权限交接详细查询请求体") +data class HandoverDetailsQueryReq( + @get:Schema(title = "流程单号") + val flowNo: String, + @get:Schema(title = "组/授权资源关联的资源类型") + val resourceType: String, + @get:Schema(title = "交接类型") + val handoverType: HandoverType, + @get:Schema(title = "第几页") + val page: Int, + @get:Schema(title = "每页大小") + val pageSize: Int +) diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverOverviewQueryReq.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverOverviewQueryReq.kt new file mode 100644 index 00000000000..b31bf6bcb47 --- /dev/null +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverOverviewQueryReq.kt @@ -0,0 +1,33 @@ +package com.tencent.devops.auth.pojo.request + +import com.tencent.devops.auth.pojo.enum.HandoverStatus +import com.tencent.devops.auth.pojo.enum.HandoverType +import io.swagger.v3.oas.annotations.media.Schema + +@Schema(title = "权限交接总览查询") +data class HandoverOverviewQueryReq( + @get:Schema(title = "成员ID") + val memberID: String, + @get:Schema(title = "项目ID") + val projectCode: String? = null, + @get:Schema(title = "项目ID") + val title: String? = null, + @get:Schema(title = "流程单号") + val flowNo: String? = null, + @get:Schema(title = "申请人") + val applicant: String? = null, + @get:Schema(title = "审批人") + val approver: String? = null, + @get:Schema(title = "审批结果") + val handoverStatus: HandoverStatus? = null, + @get:Schema(title = "最小提单时间") + val minCreatedTime: Long? = null, + @get:Schema(title = "最打提单时间") + val maxCreatedTime: Long? = null, + @get:Schema(title = "交接类型") + val handoverType: HandoverType? = null, + @get:Schema(title = "限制") + val limit: Int? = null, + @get:Schema(title = "起始值") + val offset: Int? = null +) diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverOverviewUpdateReq.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverOverviewUpdateReq.kt new file mode 100644 index 00000000000..c5a41e594f2 --- /dev/null +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverOverviewUpdateReq.kt @@ -0,0 +1,18 @@ +package com.tencent.devops.auth.pojo.request + +import com.tencent.devops.auth.pojo.enum.HandoverAction +import io.swagger.v3.oas.annotations.media.Schema + +@Schema(title = "更新权限交接总览请求体") +data class HandoverOverviewUpdateReq( + @get:Schema(title = "项目ID") + val projectCode: String, + @get:Schema(title = "项目ID") + val flowNo: String, + @get:Schema(title = "操作人") + val operator: String, + @get:Schema(title = "审批操作") + val handoverAction: HandoverAction, + @get:Schema(title = "备注") + val remark: String? = null +) diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/BatchOperateGroupMemberCheckVo.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/BatchOperateGroupMemberCheckVo.kt index 501eb12299c..7972171ac94 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/BatchOperateGroupMemberCheckVo.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/BatchOperateGroupMemberCheckVo.kt @@ -6,6 +6,12 @@ import io.swagger.v3.oas.annotations.media.Schema data class BatchOperateGroupMemberCheckVo( @get:Schema(title = "总数") val totalCount: Int, + @get:Schema(title = "可操作的数量") + val operableCount: Int? = null, @get:Schema(title = "无法操作的数量") - val inoperableCount: Int? = null + val inoperableCount: Int? = null, + @get:Schema(title = "唯一管理员组的数量") + val uniqueManagerCount: Int? = null, + @get:Schema(title = "无效的流水线授权数量") + val invalidPipelineAuthorizationCount: Int? = null ) diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/HandoverAuthorizationDetailVo.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/HandoverAuthorizationDetailVo.kt new file mode 100644 index 00000000000..0828981a8d4 --- /dev/null +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/HandoverAuthorizationDetailVo.kt @@ -0,0 +1,16 @@ +package com.tencent.devops.auth.pojo.vo + +import com.tencent.devops.auth.pojo.enum.HandoverType +import io.swagger.v3.oas.annotations.media.Schema + +@Schema(title = "授权交接详细表") +data class HandoverAuthorizationDetailVo( + @get:Schema(title = "授权资源ID") + val resourceCode: String, + @get:Schema(title = "授权资源名称") + val resourceName: String, + @get:Schema(title = "交接类型") + val handoverType: HandoverType, + @get:Schema(title = "授权人") + val handoverFrom: String +) diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/HandoverGroupDetailVo.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/HandoverGroupDetailVo.kt new file mode 100644 index 00000000000..6a6e3e40e82 --- /dev/null +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/HandoverGroupDetailVo.kt @@ -0,0 +1,19 @@ +package com.tencent.devops.auth.pojo.vo + +import io.swagger.v3.oas.annotations.media.Schema + +@Schema(title = "用户组交接详细返回体") +data class HandoverGroupDetailVo( + @get:Schema(title = "项目ID") + val projectCode: String, + @get:Schema(title = "组ID") + val iamGroupId: Int, + @get:Schema(title = "组名称") + val groupName: String, + @get:Schema(title = "组描述") + val groupDesc: String? = null, + @get:Schema(title = "关联的资源ID") + val resourceCode: String, + @get:Schema(title = "关联的资源名称") + val resourceName: String +) diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/HandoverOverviewVo.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/HandoverOverviewVo.kt new file mode 100644 index 00000000000..9c44a521394 --- /dev/null +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/HandoverOverviewVo.kt @@ -0,0 +1,34 @@ +package com.tencent.devops.auth.pojo.vo + +import com.tencent.devops.auth.pojo.enum.HandoverStatus +import io.swagger.v3.oas.annotations.media.Schema + +@Schema(title = "权限交接总览返回体") +data class HandoverOverviewVo( + @get:Schema(title = "ID") + val id: Long, + @get:Schema(title = "项目ID") + val projectCode: String, + @get:Schema(title = "标题") + val title: String, + @get:Schema(title = "流程单号") + val flowNo: String, + @get:Schema(title = "申请人") + val applicant: String, + @get:Schema(title = "审批人") + val approver: String, + @get:Schema(title = "审批结果") + val handoverStatus: HandoverStatus, + @get:Schema(title = "用户组个数") + val groupCount: Int, + @get:Schema(title = "授权个数") + val authorizationCount: Int, + @get:Schema(title = "最后修改人") + val lastOperator: String? = null, + @get:Schema(title = "是否可以撤销,提单为当前用户并且单据处于审批中") + val canRevoke: Boolean? = null, + @get:Schema(title = "是否可以审批,审批人为当前用户并且单据处于审批中") + val canApproval: Boolean? = null, + @get:Schema(title = "备注") + val remark: String? = null +) diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/MemberGroupCountWithPermissionsVo.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/ResourceType2CountVo.kt similarity index 63% rename from src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/MemberGroupCountWithPermissionsVo.kt rename to src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/ResourceType2CountVo.kt index 293d3646046..49d6a24ff37 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/MemberGroupCountWithPermissionsVo.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/ResourceType2CountVo.kt @@ -1,13 +1,16 @@ package com.tencent.devops.auth.pojo.vo +import com.tencent.devops.auth.pojo.enum.HandoverType import io.swagger.v3.oas.annotations.media.Schema @Schema(title = "用户有权限的用户组数量") -data class MemberGroupCountWithPermissionsVo( +data class ResourceType2CountVo( @get:Schema(title = "资源类型") val resourceType: String, @get:Schema(title = "资源类型名") val resourceTypeName: String, @get:Schema(title = "数量") - val count: Long + val count: Long, + @get:Schema(title = "类型") + val type: HandoverType = HandoverType.GROUP ) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthHandoverDetailDao.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthHandoverDetailDao.kt new file mode 100644 index 00000000000..a78efd6aaab --- /dev/null +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthHandoverDetailDao.kt @@ -0,0 +1,128 @@ +package com.tencent.devops.auth.dao + +import com.tencent.devops.auth.pojo.dto.HandoverDetailDTO +import com.tencent.devops.auth.pojo.enum.HandoverType +import com.tencent.devops.model.auth.tables.TAuthHandoverDetail +import com.tencent.devops.model.auth.tables.records.TAuthHandoverDetailRecord +import org.jooq.Condition +import org.jooq.DSLContext +import org.jooq.impl.DSL.count +import org.springframework.stereotype.Repository + +@Repository +class AuthHandoverDetailDao { + fun batchCreate( + dslContext: DSLContext, + handoverDetailDTOs: List + ) { + with(TAuthHandoverDetail.T_AUTH_HANDOVER_DETAIL) { + handoverDetailDTOs.forEach { + dslContext.insertInto( + this, + PROJECT_CODE, + FLOW_NO, + ITEM_ID, + RESOURCE_TYPE, + HANDOVER_TYPE + ).values( + it.projectCode, + it.flowNo, + it.itemId, + it.resourceType, + it.handoverType.value + ).execute() + } + } + } + + fun list( + dslContext: DSLContext, + projectCode: String, + flowNo: String, + resourceType: String?, + handoverType: HandoverType? + ): List { + with(TAuthHandoverDetail.T_AUTH_HANDOVER_DETAIL) { + return dslContext.selectFrom(this) + .where( + buildQueryConditions( + projectCode = projectCode, + flowNo = flowNo, + resourceType = resourceType, + handoverType = handoverType + ) + ).fetch().map { it.convert() } + } + } + + fun count( + dslContext: DSLContext, + projectCode: String, + flowNo: String, + resourceType: String?, + handoverType: HandoverType? + ): Long { + with(TAuthHandoverDetail.T_AUTH_HANDOVER_DETAIL) { + return dslContext.selectCount().from(this) + .where( + buildQueryConditions( + projectCode = projectCode, + flowNo = flowNo, + resourceType = resourceType, + handoverType = handoverType + ) + ).fetchOne(0, Long::class.java)!! + } + } + + fun countWithResourceType( + dslContext: DSLContext, + projectCode: String, + flowNo: String, + handoverType: HandoverType? + ): Map { + with(TAuthHandoverDetail.T_AUTH_HANDOVER_DETAIL) { + return dslContext.select(RESOURCE_TYPE, count()) + .from(this) + .where( + buildQueryConditions( + projectCode = projectCode, + flowNo = flowNo, + resourceType = null, + handoverType = handoverType + ) + ).groupBy(RESOURCE_TYPE) + .fetch().map { Pair(it.value1(), it.value2().toLong()) }.toMap() + } + } + + private fun buildQueryConditions( + projectCode: String, + flowNo: String, + resourceType: String?, + handoverType: HandoverType? + ): List { + with(TAuthHandoverDetail.T_AUTH_HANDOVER_DETAIL) { + val conditions = mutableListOf() + conditions.add(PROJECT_CODE.eq(projectCode)) + conditions.add(FLOW_NO.eq(flowNo)) + resourceType?.let { + conditions.add(RESOURCE_TYPE.eq(resourceType)) + } + handoverType?.let { + conditions.add(HANDOVER_TYPE.eq(handoverType.value)) + } + return conditions + } + } + + private fun TAuthHandoverDetailRecord.convert(): HandoverDetailDTO { + return HandoverDetailDTO( + projectCode = projectCode, + flowNo = flowNo, + itemId = itemId, + resourceType = resourceType, + handoverType = HandoverType.get(handoverType) + ) + } +} diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthHandoverOverviewDao.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthHandoverOverviewDao.kt new file mode 100644 index 00000000000..c32effc9cb1 --- /dev/null +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthHandoverOverviewDao.kt @@ -0,0 +1,137 @@ +package com.tencent.devops.auth.dao + +import com.tencent.devops.auth.pojo.dto.HandoverOverviewCreateDTO +import com.tencent.devops.auth.pojo.enum.HandoverStatus +import com.tencent.devops.auth.pojo.request.HandoverOverviewQueryReq +import com.tencent.devops.auth.pojo.request.HandoverOverviewUpdateReq +import com.tencent.devops.auth.pojo.vo.HandoverOverviewVo +import com.tencent.devops.common.api.util.DateTimeUtil +import com.tencent.devops.model.auth.tables.TAuthHandoverOverview +import com.tencent.devops.model.auth.tables.records.TAuthHandoverOverviewRecord +import org.jooq.Condition +import org.jooq.DSLContext +import org.springframework.stereotype.Repository +import java.time.LocalDateTime + +@Repository +class AuthHandoverOverviewDao { + fun create( + dslContext: DSLContext, + overviewDTO: HandoverOverviewCreateDTO + ) { + with(TAuthHandoverOverview.T_AUTH_HANDOVER_OVERVIEW) { + dslContext.insertInto( + this, + PROJECT_CODE, + TITLE, + FLOW_NO, + APPLICANT, + APPROVER, + STATUS, + GROUP_COUNT, + AUTHORIZATION_COUNT, + REMARK + ).values( + overviewDTO.projectCode, + overviewDTO.title, + overviewDTO.flowNo, + overviewDTO.applicant, + overviewDTO.approver, + overviewDTO.handoverStatus.value, + overviewDTO.groupCount, + overviewDTO.authorizationCount, + overviewDTO.remark + ).execute() + } + } + + fun update( + dslContext: DSLContext, + overviewDTO: HandoverOverviewUpdateReq + ) { + with(TAuthHandoverOverview.T_AUTH_HANDOVER_OVERVIEW) { + dslContext.update(this) + .set(STATUS, overviewDTO.handoverAction.value) + .let { if (overviewDTO.remark != null) it.set(REMARK, overviewDTO.remark) else it } + .set(UPDATE_TIME, LocalDateTime.now()) + .set(LAST_OPERATOR, overviewDTO.operator) + .where(FLOW_NO.eq(overviewDTO.flowNo)) + .and(PROJECT_CODE.eq(overviewDTO.projectCode)) + .execute() + } + } + + fun get( + dslContext: DSLContext, + flowNo: String + ): HandoverOverviewVo? { + return with(TAuthHandoverOverview.T_AUTH_HANDOVER_OVERVIEW) { + dslContext.selectFrom(this) + .where(FLOW_NO.eq(flowNo)) + .fetchAny()?.convert() + } + } + + fun list( + dslContext: DSLContext, + queryRequest: HandoverOverviewQueryReq + ): List { + return with(TAuthHandoverOverview.T_AUTH_HANDOVER_OVERVIEW) { + dslContext.selectFrom(this) + .where(buildQueryConditions(queryRequest)) + .let { + if (queryRequest.limit != null && queryRequest.offset != null) + it.limit(queryRequest.limit).offset(queryRequest.offset) + else + it + }.fetch().map { it.convert(queryRequest.memberID) } + } + } + + fun count( + dslContext: DSLContext, + queryRequest: HandoverOverviewQueryReq + ): Long { + return with(TAuthHandoverOverview.T_AUTH_HANDOVER_OVERVIEW) { + dslContext.selectCount().from(this) + .where(buildQueryConditions(queryRequest)) + .fetchOne(0, Long::class.java)!! + } + } + + private fun buildQueryConditions( + queryRequest: HandoverOverviewQueryReq + ): List { + with(TAuthHandoverOverview.T_AUTH_HANDOVER_OVERVIEW) { + val conditions = mutableListOf() + conditions.add(APPROVER.eq(queryRequest.memberID).or(APPLICANT.eq(queryRequest.memberID))) + queryRequest.projectCode?.let { conditions.add(PROJECT_CODE.eq(queryRequest.projectCode)) } + queryRequest.title?.let { conditions.add(TITLE.like("%${queryRequest.title}%")) } + queryRequest.flowNo?.let { conditions.add(FLOW_NO.eq(queryRequest.flowNo)) } + queryRequest.applicant?.let { conditions.add(APPLICANT.like("%${queryRequest.applicant}%")) } + queryRequest.approver?.let { conditions.add(APPROVER.like("%${queryRequest.approver}%")) } + queryRequest.handoverStatus?.let { conditions.add(STATUS.eq(queryRequest.handoverStatus!!.value)) } + queryRequest.minCreatedTime?.let { conditions.add(CREATE_TIME.ge(DateTimeUtil.convertTimestampToLocalDateTime(it / 1000))) } + queryRequest.maxCreatedTime?.let { conditions.add(CREATE_TIME.le(DateTimeUtil.convertTimestampToLocalDateTime(it / 1000))) } + return conditions + } + } + + fun TAuthHandoverOverviewRecord.convert(memberId: String? = null): HandoverOverviewVo { + return HandoverOverviewVo( + id = id, + projectCode = projectCode, + title = title, + flowNo = flowNo, + applicant = applicant, + approver = approver, + handoverStatus = HandoverStatus.get(status), + groupCount = groupCount, + authorizationCount = authorizationCount, + lastOperator = lastOperator, + canRevoke = memberId?.let { memberId == applicant && status == HandoverStatus.PENDING.value }, + canApproval = memberId?.let { memberId == approver && status == HandoverStatus.PENDING.value }, + remark = remark + ) + } +} diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupDao.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupDao.kt index e18db590fd8..263af0b1d00 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupDao.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupDao.kt @@ -368,6 +368,7 @@ class AuthResourceGroupDao { dslContext: DSLContext, projectCode: String, resourceType: String, + iamGroupIds: List? = null, offset: Int, limit: Int ): List { @@ -375,6 +376,13 @@ class AuthResourceGroupDao { val records = dslContext.selectFrom(this) .where(PROJECT_CODE.eq(projectCode)) .and(RESOURCE_TYPE.eq(resourceType)) + .let { + if (!iamGroupIds.isNullOrEmpty()) { + it.and(RELATION_ID.`in`(iamGroupIds)) + } else { + it + } + } .offset(offset) .limit(limit) .fetch() diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupMemberDao.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupMemberDao.kt index f279039dab4..1ad65f22ba9 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupMemberDao.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupMemberDao.kt @@ -27,10 +27,10 @@ package com.tencent.devops.auth.dao -import com.tencent.bk.sdk.iam.constants.ManagerScopesEnum import com.tencent.devops.auth.pojo.AuthResourceGroupMember import com.tencent.devops.auth.pojo.ResourceMemberInfo import com.tencent.devops.auth.pojo.dto.ProjectMembersQueryConditionDTO +import com.tencent.devops.auth.pojo.enum.MemberType import com.tencent.devops.common.auth.api.pojo.BkAuthGroup import com.tencent.devops.model.auth.tables.TAuthResourceAuthorization import com.tencent.devops.model.auth.tables.TAuthResourceGroupMember @@ -418,17 +418,17 @@ class AuthResourceGroupMemberDao { with(projectMembersQueryConditionDTO) { conditions.add(PROJECT_CODE.eq(projectCode)) if (queryTemplate == false) { - conditions.add(MEMBER_TYPE.notEqual(ManagerScopesEnum.getType(ManagerScopesEnum.TEMPLATE))) + conditions.add(MEMBER_TYPE.notEqual(MemberType.TEMPLATE.type)) } else { - conditions.add(MEMBER_TYPE.eq(ManagerScopesEnum.getType(ManagerScopesEnum.TEMPLATE))) + conditions.add(MEMBER_TYPE.eq(MemberType.TEMPLATE.type)) } memberType?.let { type -> conditions.add(MEMBER_TYPE.eq(type)) } userName?.let { name -> - conditions.add(MEMBER_TYPE.eq(ManagerScopesEnum.getType(ManagerScopesEnum.USER))) + conditions.add(MEMBER_TYPE.eq(MemberType.USER.type)) conditions.add(MEMBER_ID.like("%$name%").or(MEMBER_NAME.like("%$name%"))) } deptName?.let { name -> - conditions.add(MEMBER_TYPE.eq(ManagerScopesEnum.getType(ManagerScopesEnum.DEPARTMENT))) + conditions.add(MEMBER_TYPE.eq(MemberType.DEPARTMENT.type)) conditions.add(MEMBER_NAME.like("%$name%")) } minExpiredTime?.let { minTime -> conditions.add(EXPIRED_TIME.ge(minTime)) } @@ -494,7 +494,7 @@ class AuthResourceGroupMemberDao { ) .from(tResourceGroupMember) .where(tResourceGroupMember.PROJECT_CODE.eq(projectCode)) - .and(tResourceGroupMember.MEMBER_TYPE.notEqual(ManagerScopesEnum.getType(ManagerScopesEnum.TEMPLATE))) + .and(tResourceGroupMember.MEMBER_TYPE.notEqual(MemberType.TEMPLATE.type)) .groupBy(tResourceGroupMember.MEMBER_ID) .unionAll( dslContext.select( @@ -523,11 +523,11 @@ class AuthResourceGroupMemberDao { conditions.add(memberTypeField.eq(memberType)) } if (userName != null) { - conditions.add(memberTypeField.eq(ManagerScopesEnum.getType(ManagerScopesEnum.USER))) + conditions.add(memberTypeField.eq(MemberType.USER.type)) conditions.add(memberId.like("%$userName%").or(memberName.like("%$userName%"))) } if (deptName != null) { - conditions.add(memberTypeField.eq(ManagerScopesEnum.getType(ManagerScopesEnum.DEPARTMENT))) + conditions.add(memberTypeField.eq(MemberType.DEPARTMENT.type)) conditions.add(memberName.like("%$deptName%")) } return conditions @@ -639,23 +639,24 @@ class AuthResourceGroupMemberDao { with(TAuthResourceGroupMember.T_AUTH_RESOURCE_GROUP_MEMBER) { conditions.add(PROJECT_CODE.eq(projectCode)) conditions.add( + // 获取直接加入 (MEMBER_ID.eq(memberId).and( - MEMBER_TYPE.`in`( - listOf( - ManagerScopesEnum.getType(ManagerScopesEnum.USER), - ManagerScopesEnum.getType(ManagerScopesEnum.DEPARTMENT) - ) - ) - )) - .or( - MEMBER_ID.`in`(iamTemplateIds) - .and(MEMBER_TYPE.eq(ManagerScopesEnum.getType(ManagerScopesEnum.TEMPLATE))) - ) - .or( - MEMBER_ID.`in`(memberDeptInfos) - .and(MEMBER_TYPE.eq(ManagerScopesEnum.getType(ManagerScopesEnum.DEPARTMENT))) - ) - ) + MEMBER_TYPE.`in`(listOf(MemberType.USER.type, MemberType.DEPARTMENT.type)) + )).let { + // 获取模板加入 + if (iamTemplateIds.isNotEmpty()) { + it.or(MEMBER_ID.`in`(iamTemplateIds).and(MEMBER_TYPE.eq(MemberType.TEMPLATE.type))) + } else { + it + } + }.let { + // 获取组织加入 + if (!memberDeptInfos.isNullOrEmpty()) { + it.or(MEMBER_ID.`in`(memberDeptInfos).and(MEMBER_TYPE.eq(MemberType.DEPARTMENT.type))) + } else { + it + } + }) resourceType?.let { conditions.add(RESOURCE_TYPE.eq(resourceType)) } minExpiredAt?.let { conditions.add(EXPIRED_TIME.ge(minExpiredAt)) } maxExpiredAt?.let { conditions.add(EXPIRED_TIME.le(maxExpiredAt)) } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/config/RbacAuthConfiguration.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/config/RbacAuthConfiguration.kt index 3b791cd6444..d129208b7bf 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/config/RbacAuthConfiguration.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/config/RbacAuthConfiguration.kt @@ -44,6 +44,8 @@ import com.tencent.bk.sdk.iam.service.v2.impl.V2ManagerServiceImpl import com.tencent.bk.sdk.iam.service.v2.impl.V2PolicyServiceImpl import com.tencent.devops.auth.dao.AuthActionDao import com.tencent.devops.auth.dao.AuthAuthorizationDao +import com.tencent.devops.auth.dao.AuthHandoverDetailDao +import com.tencent.devops.auth.dao.AuthHandoverOverviewDao import com.tencent.devops.auth.dao.AuthMigrationDao import com.tencent.devops.auth.dao.AuthMonitorSpaceDao import com.tencent.devops.auth.dao.AuthResourceDao @@ -63,10 +65,11 @@ import com.tencent.devops.auth.provider.rbac.service.RbacPermissionApplyService import com.tencent.devops.auth.provider.rbac.service.RbacPermissionAuthMonitorSpaceService import com.tencent.devops.auth.provider.rbac.service.RbacPermissionAuthorizationScopesService import com.tencent.devops.auth.provider.rbac.service.RbacPermissionExtService +import com.tencent.devops.auth.provider.rbac.service.RbacPermissionHandoverService import com.tencent.devops.auth.provider.rbac.service.RbacPermissionItsmCallbackService +import com.tencent.devops.auth.provider.rbac.service.RbacPermissionManageFacadeServiceImpl import com.tencent.devops.auth.provider.rbac.service.RbacPermissionProjectService import com.tencent.devops.auth.provider.rbac.service.RbacPermissionResourceCallbackService -import com.tencent.devops.auth.provider.rbac.service.RbacPermissionManageFacadeServiceImpl import com.tencent.devops.auth.provider.rbac.service.RbacPermissionResourceGroupPermissionService import com.tencent.devops.auth.provider.rbac.service.RbacPermissionResourceGroupService import com.tencent.devops.auth.provider.rbac.service.RbacPermissionResourceGroupSyncService @@ -94,6 +97,7 @@ import com.tencent.devops.auth.service.PermissionAuthorizationService import com.tencent.devops.auth.service.ResourceService import com.tencent.devops.auth.service.SuperManagerService import com.tencent.devops.auth.service.iam.MigrateCreatorFixService +import com.tencent.devops.auth.service.iam.PermissionHandoverService import com.tencent.devops.auth.service.iam.PermissionManageFacadeService import com.tencent.devops.auth.service.iam.PermissionResourceGroupPermissionService import com.tencent.devops.auth.service.iam.PermissionResourceGroupService @@ -208,10 +212,12 @@ class RbacAuthConfiguration { dslContext: DSLContext, deptService: DeptService, iamV2ManagerService: V2ManagerService, - rbacCacheService: RbacCacheService, permissionAuthorizationService: PermissionAuthorizationService, syncIamGroupMemberService: PermissionResourceGroupSyncService, - authAuthorizationDao: AuthAuthorizationDao + authAuthorizationDao: AuthAuthorizationDao, + permissionHandoverService: PermissionHandoverService, + rbacCacheService: RbacCacheService, + redisOperation: RedisOperation ) = RbacPermissionManageFacadeServiceImpl( permissionResourceGroupService = permissionResourceGroupService, groupPermissionService = groupPermissionService, @@ -221,10 +227,12 @@ class RbacAuthConfiguration { dslContext = dslContext, deptService = deptService, iamV2ManagerService = iamV2ManagerService, - rbacCacheService = rbacCacheService, permissionAuthorizationService = permissionAuthorizationService, syncIamGroupMemberService = syncIamGroupMemberService, - authAuthorizationDao = authAuthorizationDao + authAuthorizationDao = authAuthorizationDao, + permissionHandoverService = permissionHandoverService, + rbacCacheService = rbacCacheService, + redisOperation = redisOperation ) @Bean @@ -602,6 +610,25 @@ class RbacAuthConfiguration { permissionManageFacadeService = permissionManageFacadeService ) + @Bean + fun permissionHandoverService( + dslContext: DSLContext, + handoverOverviewDao: AuthHandoverOverviewDao, + handoverDetailDao: AuthHandoverDetailDao, + authorizationDao: AuthAuthorizationDao, + authResourceGroupDao: AuthResourceGroupDao, + rbacCacheService: RbacCacheService, + redisOperation: RedisOperation + ) = RbacPermissionHandoverService( + dslContext = dslContext, + handoverOverviewDao = handoverOverviewDao, + handoverDetailDao = handoverDetailDao, + authorizationDao = authorizationDao, + authResourceGroupDao = authResourceGroupDao, + rbacCacheService = rbacCacheService, + redisOperation = redisOperation + ) + @Bean fun systemService( iamConfiguration: IamConfiguration, diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacCacheService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacCacheService.kt index 1a9f467e7b7..d0e9b02ec98 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacCacheService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacCacheService.kt @@ -3,18 +3,21 @@ package com.tencent.devops.auth.provider.rbac.service import com.fasterxml.jackson.core.type.TypeReference import com.github.benmanes.caffeine.cache.Caffeine import com.tencent.bk.sdk.iam.config.IamConfiguration -import com.tencent.bk.sdk.iam.constants.ManagerScopesEnum import com.tencent.bk.sdk.iam.dto.SubjectDTO import com.tencent.bk.sdk.iam.dto.V2QueryPolicyDTO import com.tencent.bk.sdk.iam.dto.action.ActionDTO import com.tencent.bk.sdk.iam.dto.resource.V2ResourceNode import com.tencent.bk.sdk.iam.service.PolicyService +import com.tencent.devops.auth.constant.AuthI18nConstants import com.tencent.devops.auth.constant.AuthMessageCode import com.tencent.devops.auth.dao.AuthActionDao import com.tencent.devops.auth.dao.AuthResourceGroupConfigDao import com.tencent.devops.auth.dao.AuthResourceTypeDao import com.tencent.devops.auth.pojo.AuthGroupConfigAction +import com.tencent.devops.auth.pojo.enum.HandoverType +import com.tencent.devops.auth.pojo.enum.MemberType import com.tencent.devops.auth.pojo.vo.ActionInfoVo +import com.tencent.devops.auth.pojo.vo.ResourceType2CountVo import com.tencent.devops.auth.pojo.vo.ResourceTypeInfoVo import com.tencent.devops.auth.service.AuthProjectUserMetricsService import com.tencent.devops.common.api.exception.ErrorCodeException @@ -22,6 +25,7 @@ import com.tencent.devops.common.api.util.JsonUtil import com.tencent.devops.common.auth.api.AuthPermission import com.tencent.devops.common.auth.api.AuthResourceType import com.tencent.devops.common.auth.rbac.utils.RbacAuthUtils +import com.tencent.devops.common.web.utils.I18nUtil import org.jooq.DSLContext import org.slf4j.LoggerFactory import java.util.concurrent.TimeUnit @@ -190,7 +194,7 @@ class RbacCacheService constructor( val subject = SubjectDTO.builder() .id(userId) - .type(ManagerScopesEnum.getType(ManagerScopesEnum.USER)) + .type(MemberType.USER.type) .build() val queryPolicyDTO = V2QueryPolicyDTO.builder().system(iamConfiguration.systemId) .subject(subject) @@ -213,4 +217,42 @@ class RbacCacheService constructor( ) } } + + fun convertResourceType2Count( + resourceType2Count: Map, + type: HandoverType = HandoverType.GROUP + ): List { + val memberGroupCountList = mutableListOf() + // 项目排在第一位 + resourceType2Count[AuthResourceType.PROJECT.value]?.let { projectCount -> + memberGroupCountList.add( + ResourceType2CountVo( + resourceType = AuthResourceType.PROJECT.value, + resourceTypeName = I18nUtil.getCodeLanMessage( + messageCode = AuthResourceType.PROJECT.value + AuthI18nConstants.RESOURCE_TYPE_NAME_SUFFIX + ), + count = projectCount, + type = type + ) + ) + } + + listResourceTypes() + .filter { it.resourceType != AuthResourceType.PROJECT.value } + .forEach { resourceTypeInfoVo -> + resourceType2Count[resourceTypeInfoVo.resourceType]?.let { count -> + val memberGroupCount = ResourceType2CountVo( + resourceType = resourceTypeInfoVo.resourceType, + resourceTypeName = I18nUtil.getCodeLanMessage( + messageCode = resourceTypeInfoVo.resourceType + AuthI18nConstants.RESOURCE_TYPE_NAME_SUFFIX, + defaultMessage = resourceTypeInfoVo.name + ), + count = count, + type = type + ) + memberGroupCountList.add(memberGroupCount) + } + } + return memberGroupCountList + } } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverService.kt new file mode 100644 index 00000000000..6b233a582d3 --- /dev/null +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverService.kt @@ -0,0 +1,260 @@ +package com.tencent.devops.auth.provider.rbac.service + +import com.tencent.devops.auth.constant.AuthI18nConstants +import com.tencent.devops.auth.constant.AuthMessageCode +import com.tencent.devops.auth.dao.AuthAuthorizationDao +import com.tencent.devops.auth.dao.AuthHandoverDetailDao +import com.tencent.devops.auth.dao.AuthHandoverOverviewDao +import com.tencent.devops.auth.dao.AuthResourceGroupDao +import com.tencent.devops.auth.pojo.dto.HandoverDetailDTO +import com.tencent.devops.auth.pojo.dto.HandoverOverviewCreateDTO +import com.tencent.devops.auth.pojo.request.HandoverOverviewUpdateReq +import com.tencent.devops.auth.pojo.enum.HandoverType +import com.tencent.devops.auth.pojo.request.HandoverDetailsQueryReq +import com.tencent.devops.auth.pojo.request.HandoverOverviewQueryReq +import com.tencent.devops.auth.pojo.vo.HandoverAuthorizationDetailVo +import com.tencent.devops.auth.pojo.vo.HandoverGroupDetailVo +import com.tencent.devops.auth.pojo.vo.HandoverOverviewVo +import com.tencent.devops.auth.pojo.vo.ResourceType2CountVo +import com.tencent.devops.auth.service.iam.PermissionHandoverService +import com.tencent.devops.common.api.exception.ErrorCodeException +import com.tencent.devops.common.api.model.SQLPage +import com.tencent.devops.common.api.util.DateTimeUtil +import com.tencent.devops.common.api.util.PageUtil +import com.tencent.devops.common.auth.api.pojo.ResourceAuthorizationConditionRequest +import com.tencent.devops.common.redis.RedisOperation +import com.tencent.devops.common.web.utils.I18nUtil +import org.jooq.DSLContext +import org.jooq.impl.DSL +import org.slf4j.LoggerFactory +import java.time.LocalDateTime + +class RbacPermissionHandoverService( + private val dslContext: DSLContext, + private val handoverOverviewDao: AuthHandoverOverviewDao, + private val handoverDetailDao: AuthHandoverDetailDao, + private val authorizationDao: AuthAuthorizationDao, + private val authResourceGroupDao: AuthResourceGroupDao, + private val rbacCacheService: RbacCacheService, + private val redisOperation: RedisOperation +) : PermissionHandoverService { + override fun createHandoverApplication( + overview: HandoverOverviewCreateDTO, + details: List + ) { + logger.info("create handover application:{}|{}", overview, details) + // todo 发送邮件/devops-notices通知 + + dslContext.transaction { configuration -> + val transactionContext = DSL.using(configuration) + handoverOverviewDao.create( + dslContext = transactionContext, + overviewDTO = overview + ) + handoverDetailDao.batchCreate( + dslContext = transactionContext, + handoverDetailDTOs = details + ) + } + } + + override fun generateTitle( + groupCount: Int, + authorizationCount: Int + ): String { + return I18nUtil.getCodeLanMessage(messageCode = AuthI18nConstants.BK_APPLY_TO_HANDOVER).let { + if (groupCount > 0) { + it.plus(I18nUtil.getCodeLanMessage(AuthI18nConstants.BK_HANDOVER_GROUPS, params = arrayOf(groupCount.toString()))).plus(",") + } else { + it + } + }.let { + if (authorizationCount > 0) { + it.plus( + I18nUtil.getCodeLanMessage(AuthI18nConstants.BK_HANDOVER_AUTHORIZATIONS, params = arrayOf(authorizationCount.toString())) + ) + } else { + it + } + } + } + + /** + * 生成格式如 REQ2024111300001 + * REQ 固定前缀 + * 20241113 表示日期 + * 00001 表示当天第几个单号 + * */ + override fun generateFlowNo(): String { + val currentTime = DateTimeUtil.toDateTime(LocalDateTime.now(), DateTimeUtil.YYYYMMDD) + val incrementedValue = redisOperation.increment(String.format(FLOW_NO_KEY, currentTime), 1) + val formattedIncrementedValue = String.format("%05d", incrementedValue) + return FLOW_NO_PREFIX + currentTime + formattedIncrementedValue + } + + override fun updateHandoverApplication(overview: HandoverOverviewUpdateReq) { + logger.info("update handover application:{}", overview) + handoverOverviewDao.update( + dslContext = dslContext, + overviewDTO = overview + ) + } + + override fun getHandoverOverview(flowNo: String): HandoverOverviewVo { + return handoverOverviewDao.get( + dslContext = dslContext, + flowNo = flowNo + ) ?: throw ErrorCodeException( + errorCode = AuthMessageCode.ERROR_HANDOVER_OVERVIEW_NOT_EXIST + ) + } + + override fun listHandoverOverviews( + queryRequest: HandoverOverviewQueryReq + ): SQLPage { + val records = handoverOverviewDao.list( + dslContext = dslContext, + queryRequest = queryRequest + ) + val count = handoverOverviewDao.count( + dslContext = dslContext, + queryRequest = queryRequest + ) + return SQLPage( + records = records, + count = count + ) + } + + override fun listAuthorizationsOfHandover( + queryReq: HandoverDetailsQueryReq + ): SQLPage { + val overview = getHandoverOverview(queryReq.flowNo) + val resourceCodes = handoverDetailDao.list( + dslContext = dslContext, + projectCode = overview.projectCode, + flowNo = queryReq.flowNo, + resourceType = queryReq.resourceType, + handoverType = queryReq.handoverType + ).map { it.itemId } + val count = handoverDetailDao.count( + dslContext = dslContext, + projectCode = overview.projectCode, + flowNo = queryReq.flowNo, + resourceType = queryReq.resourceType, + handoverType = queryReq.handoverType + ) + val records = authorizationDao.list( + dslContext = dslContext, + condition = ResourceAuthorizationConditionRequest( + projectCode = overview.projectCode, + resourceType = queryReq.resourceType, + filterResourceCodes = resourceCodes, + page = queryReq.page, + pageSize = queryReq.pageSize + ) + ).map { + HandoverAuthorizationDetailVo( + resourceCode = it.resourceCode, + resourceName = it.resourceName, + handoverType = queryReq.handoverType, + handoverFrom = overview.applicant + ) + } + return SQLPage(records = records, count = count) + } + + override fun listGroupsOfHandover( + queryReq: HandoverDetailsQueryReq + ): SQLPage { + val handoverOverview = getHandoverOverview(queryReq.flowNo) + val iamGroupIdsByHandover = listHandoverDetails( + projectCode = handoverOverview.projectCode, + flowNo = queryReq.flowNo, + resourceType = queryReq.resourceType, + handoverType = HandoverType.GROUP + ).map { it.itemId } + if (iamGroupIdsByHandover.isEmpty()) + return SQLPage(0, emptyList()) + val convertPageSizeToSQLLimit = PageUtil.convertPageSizeToSQLLimit( + page = queryReq.page, + pageSize = queryReq.pageSize + ) + val records = authResourceGroupDao.listGroupByResourceType( + dslContext = dslContext, + projectCode = handoverOverview.projectCode, + resourceType = queryReq.resourceType, + iamGroupIds = iamGroupIdsByHandover, + offset = convertPageSizeToSQLLimit.offset, + limit = convertPageSizeToSQLLimit.limit + ).map { + HandoverGroupDetailVo( + projectCode = it.projectCode, + iamGroupId = it.relationId, + groupName = it.groupName, + groupDesc = it.description, + resourceCode = it.resourceCode, + resourceName = it.resourceName + ) + } + return SQLPage( + count = iamGroupIdsByHandover.size.toLong(), + records = records + ) + } + + override fun getResourceType2CountOfHandover(flowNo: String): List { + val handoverOverview = getHandoverOverview(flowNo) + val resourceType2CountWithGroup = handoverDetailDao.countWithResourceType( + dslContext = dslContext, + projectCode = handoverOverview.projectCode, + flowNo = flowNo, + handoverType = HandoverType.GROUP + ) + val resourceType2CountWithAuthorization = handoverDetailDao.countWithResourceType( + dslContext = dslContext, + projectCode = handoverOverview.projectCode, + flowNo = flowNo, + handoverType = HandoverType.AUTHORIZATION + ) + val result = mutableListOf() + if (resourceType2CountWithGroup.isNotEmpty()) { + result.addAll( + rbacCacheService.convertResourceType2Count( + resourceType2Count = resourceType2CountWithGroup, + type = HandoverType.GROUP + ) + ) + } + if (resourceType2CountWithAuthorization.isNotEmpty()) { + result.addAll( + rbacCacheService.convertResourceType2Count( + resourceType2Count = resourceType2CountWithAuthorization, + type = HandoverType.AUTHORIZATION + ) + ) + } + return result + } + + override fun listHandoverDetails( + projectCode: String, + flowNo: String, + resourceType: String?, + handoverType: HandoverType? + ): List { + return handoverDetailDao.list( + dslContext = dslContext, + projectCode = projectCode, + flowNo = flowNo, + resourceType = resourceType, + handoverType = handoverType + ) + } + + companion object { + private val logger = LoggerFactory.getLogger(RbacPermissionHandoverService::class.java) + private const val FLOW_NO_PREFIX = "REQ" + private const val FLOW_NO_KEY = "AUTH:HANDOVER:FLOW:NO:%s" + } +} diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt index dac5718a82c..3fa1caded28 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt @@ -6,33 +6,49 @@ import com.tencent.bk.sdk.iam.dto.response.MemberGroupDetailsResponse import com.tencent.bk.sdk.iam.service.v2.V2ManagerService import com.tencent.devops.auth.constant.AuthI18nConstants import com.tencent.devops.auth.constant.AuthMessageCode +import com.tencent.devops.auth.constant.AuthMessageCode.ERROR_HANDOVER_APPROVAL +import com.tencent.devops.auth.constant.AuthMessageCode.ERROR_HANDOVER_FINISH +import com.tencent.devops.auth.constant.AuthMessageCode.ERROR_HANDOVER_HANDLE +import com.tencent.devops.auth.constant.AuthMessageCode.ERROR_HANDOVER_REVOKE import com.tencent.devops.auth.dao.AuthAuthorizationDao import com.tencent.devops.auth.dao.AuthResourceGroupDao import com.tencent.devops.auth.dao.AuthResourceGroupMemberDao import com.tencent.devops.auth.pojo.AuthResourceGroupMember import com.tencent.devops.auth.pojo.ResourceMemberInfo +import com.tencent.devops.auth.pojo.dto.HandoverDetailDTO +import com.tencent.devops.auth.pojo.dto.HandoverOverviewCreateDTO import com.tencent.devops.auth.pojo.dto.IamGroupIdsQueryConditionDTO +import com.tencent.devops.auth.pojo.dto.InvalidAuthorizationsDTO import com.tencent.devops.auth.pojo.dto.ProjectMembersQueryConditionDTO import com.tencent.devops.auth.pojo.enum.BatchOperateType +import com.tencent.devops.auth.pojo.enum.HandoverAction +import com.tencent.devops.auth.pojo.enum.HandoverStatus +import com.tencent.devops.auth.pojo.enum.HandoverType import com.tencent.devops.auth.pojo.enum.JoinedType +import com.tencent.devops.auth.pojo.enum.MemberType import com.tencent.devops.auth.pojo.enum.OperateChannel import com.tencent.devops.auth.pojo.enum.RemoveMemberButtonControl import com.tencent.devops.auth.pojo.request.GroupMemberCommonConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberHandoverConditionReq +import com.tencent.devops.auth.pojo.request.GroupMemberRemoveConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberRenewalConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberSingleRenewalReq +import com.tencent.devops.auth.pojo.request.HandoverOverviewUpdateReq import com.tencent.devops.auth.pojo.request.ProjectMembersQueryConditionReq import com.tencent.devops.auth.pojo.request.RemoveMemberFromProjectReq import com.tencent.devops.auth.pojo.vo.BatchOperateGroupMemberCheckVo import com.tencent.devops.auth.pojo.vo.GroupDetailsInfoVo -import com.tencent.devops.auth.pojo.vo.MemberGroupCountWithPermissionsVo +import com.tencent.devops.auth.pojo.vo.HandoverOverviewVo +import com.tencent.devops.auth.pojo.vo.ResourceType2CountVo import com.tencent.devops.auth.service.DeptService import com.tencent.devops.auth.service.PermissionAuthorizationService +import com.tencent.devops.auth.service.iam.PermissionHandoverService import com.tencent.devops.auth.service.iam.PermissionManageFacadeService import com.tencent.devops.auth.service.iam.PermissionResourceGroupPermissionService import com.tencent.devops.auth.service.iam.PermissionResourceGroupService import com.tencent.devops.auth.service.iam.PermissionResourceGroupSyncService import com.tencent.devops.auth.service.iam.PermissionResourceMemberService +import com.tencent.devops.auth.service.lock.HandleHandoverApplicationLock import com.tencent.devops.common.api.exception.ErrorCodeException import com.tencent.devops.common.api.model.SQLPage import com.tencent.devops.common.api.util.DateTimeUtil @@ -43,6 +59,9 @@ import com.tencent.devops.common.auth.api.AuthResourceType import com.tencent.devops.common.auth.api.ResourceTypeId import com.tencent.devops.common.auth.api.pojo.ResetAllResourceAuthorizationReq import com.tencent.devops.common.auth.api.pojo.ResourceAuthorizationConditionRequest +import com.tencent.devops.common.auth.api.pojo.ResourceAuthorizationHandoverConditionRequest +import com.tencent.devops.common.auth.enums.HandoverChannelCode +import com.tencent.devops.common.redis.RedisOperation import com.tencent.devops.common.service.utils.RetryUtils import com.tencent.devops.common.web.utils.I18nUtil import com.tencent.devops.model.auth.tables.records.TAuthResourceGroupRecord @@ -61,10 +80,12 @@ class RbacPermissionManageFacadeServiceImpl( private val dslContext: DSLContext, private val deptService: DeptService, private val iamV2ManagerService: V2ManagerService, - private val rbacCacheService: RbacCacheService, private val authAuthorizationDao: AuthAuthorizationDao, private val syncIamGroupMemberService: PermissionResourceGroupSyncService, - private val permissionAuthorizationService: PermissionAuthorizationService + private val permissionAuthorizationService: PermissionAuthorizationService, + private val permissionHandoverService: PermissionHandoverService, + private val rbacCacheService: RbacCacheService, + private val redisOperation: RedisOperation ) : PermissionManageFacadeService { override fun getMemberGroupsDetails( projectId: String, @@ -149,11 +170,11 @@ class RbacPermissionManageFacadeServiceImpl( val groupMemberDetailMap = mutableMapOf() // 直接加入的用户 val userGroupIds = resourceGroupMembers - .filter { it.memberType == ManagerScopesEnum.getType(ManagerScopesEnum.USER) } + .filter { it.memberType == MemberType.USER.type } .map { it.iamGroupId } if (userGroupIds.isNotEmpty()) { iamV2ManagerService.listMemberGroupsDetails( - ManagerScopesEnum.getType(ManagerScopesEnum.USER), + MemberType.USER.type, memberId, userGroupIds.joinToString(",") ).forEach { @@ -162,11 +183,11 @@ class RbacPermissionManageFacadeServiceImpl( } // 直接加入的组织 val deptGroupIds = resourceGroupMembers - .filter { it.memberType == ManagerScopesEnum.getType(ManagerScopesEnum.DEPARTMENT) } + .filter { it.memberType == MemberType.DEPARTMENT.type } .map { it.iamGroupId } if (deptGroupIds.isNotEmpty()) { iamV2ManagerService.listMemberGroupsDetails( - ManagerScopesEnum.getType(ManagerScopesEnum.DEPARTMENT), + MemberType.DEPARTMENT.type, memberId, deptGroupIds.joinToString(",") ).forEach { @@ -174,12 +195,12 @@ class RbacPermissionManageFacadeServiceImpl( } } // 人员模板加入的组 - resourceGroupMembers.filter { it.memberType == ManagerScopesEnum.getType(ManagerScopesEnum.TEMPLATE) } + resourceGroupMembers.filter { it.memberType == MemberType.TEMPLATE.type } .groupBy({ it.memberId }, { it.iamGroupId.toString() }) .forEach { (iamTemplateId, iamGroupIds) -> if (iamGroupIds.isEmpty()) return@forEach iamV2ManagerService.listMemberGroupsDetails( - ManagerScopesEnum.getType(ManagerScopesEnum.TEMPLATE), + MemberType.TEMPLATE.type, iamTemplateId, iamGroupIds.joinToString(",") ).forEach { @@ -231,7 +252,7 @@ class RbacPermissionManageFacadeServiceImpl( expiredAt = expiredAt, joinedTime = joinedTime, removeMemberButtonControl = when { - authResourceGroupMember.memberType == ManagerScopesEnum.getType(ManagerScopesEnum.TEMPLATE) -> + authResourceGroupMember.memberType == MemberType.TEMPLATE.type -> RemoveMemberButtonControl.TEMPLATE resourceGroup.resourceType == AuthResourceType.PROJECT.value && @@ -245,8 +266,8 @@ class RbacPermissionManageFacadeServiceImpl( RemoveMemberButtonControl.OTHER }, joinedType = when (authResourceGroupMember.memberType) { - ManagerScopesEnum.getType(ManagerScopesEnum.TEMPLATE) -> JoinedType.TEMPLATE - ManagerScopesEnum.getType(ManagerScopesEnum.DEPARTMENT) -> JoinedType.DEPARTMENT + MemberType.TEMPLATE.type -> JoinedType.TEMPLATE + MemberType.DEPARTMENT.type -> JoinedType.DEPARTMENT else -> JoinedType.DIRECT }, operator = "" @@ -263,32 +284,12 @@ class RbacPermissionManageFacadeServiceImpl( relatedResourceCode: String?, action: String?, operateChannel: OperateChannel? - ): List { - // 查询项目下包含该成员的组列表 - val projectGroupIds = authResourceGroupMemberDao.listResourceGroupMember( - dslContext = dslContext, - projectCode = projectCode, - resourceType = AuthResourceType.PROJECT.value, - memberId = memberId - ).map { it.iamGroupId.toString() } - // 通过项目组ID获取人员模板ID - val iamTemplateId = authResourceGroupDao.listByRelationId( - dslContext = dslContext, + ): List { + val (iamTemplateIds, memberDeptInfos) = getMemberTemplateIdsAndDeptInfos( projectCode = projectCode, - iamGroupIds = projectGroupIds - ).filter { it.iamTemplateId != null } - .map { it.iamTemplateId.toString() } - // 获取用户部门信息 - val memberDeptInfos = if (operateChannel == OperateChannel.PERSONAL) { - deptService.getUserInfo( - userId = "admin", - name = memberId - )?.deptInfo ?: return emptyList() - deptService.getUserDeptInfo(memberId).toList() - } else { - emptyList() - } - + memberId = memberId, + operateChannel = operateChannel + ) val iamGroupIdsByConditions = listIamGroupIdsByConditions( condition = IamGroupIdsQueryConditionDTO( projectCode = projectCode, @@ -303,43 +304,32 @@ class RbacPermissionManageFacadeServiceImpl( dslContext = dslContext, projectCode = projectCode, memberId = memberId, - iamTemplateIds = iamTemplateId, + iamTemplateIds = iamTemplateIds, iamGroupIds = iamGroupIdsByConditions, minExpiredAt = minExpiredAt?.let { DateTimeUtil.convertTimestampToLocalDateTime(it / 1000) }, maxExpiredAt = maxExpiredAt?.let { DateTimeUtil.convertTimestampToLocalDateTime(it / 1000) }, memberDeptInfos = memberDeptInfos ) - val memberGroupCountList = mutableListOf() - // 项目排在第一位 - memberGroupCountMap[AuthResourceType.PROJECT.value]?.let { projectCount -> - memberGroupCountList.add( - MemberGroupCountWithPermissionsVo( - resourceType = AuthResourceType.PROJECT.value, - resourceTypeName = I18nUtil.getCodeLanMessage( - messageCode = AuthResourceType.PROJECT.value + AuthI18nConstants.RESOURCE_TYPE_NAME_SUFFIX - ), - count = projectCount - ) - ) - } - - rbacCacheService.listResourceTypes() - .filter { it.resourceType != AuthResourceType.PROJECT.value } - .forEach { resourceTypeInfoVo -> - memberGroupCountMap[resourceTypeInfoVo.resourceType]?.let { count -> - val memberGroupCount = MemberGroupCountWithPermissionsVo( - resourceType = resourceTypeInfoVo.resourceType, - resourceTypeName = I18nUtil.getCodeLanMessage( - messageCode = resourceTypeInfoVo.resourceType + AuthI18nConstants.RESOURCE_TYPE_NAME_SUFFIX, - defaultMessage = resourceTypeInfoVo.name - ), - count = count - ) - memberGroupCountList.add(memberGroupCount) - } - } + return rbacCacheService.convertResourceType2Count(memberGroupCountMap) + } - return memberGroupCountList + private fun getMemberTemplateIdsAndDeptInfos( + projectCode: String, + memberId: String, + operateChannel: OperateChannel? + ): Pair, List> { + // 获取用户加入的项目级用户组模板ID + val iamTemplateIds = listProjectMemberGroupTemplateIds( + projectCode = projectCode, + memberId = memberId + ) + // 获取用户部门信息 + val memberDeptInfos = if (operateChannel == OperateChannel.PERSONAL) { + getMemberDeptInfos(memberId) + } else { + emptyList() + } + return Pair(iamTemplateIds, memberDeptInfos) } override fun listIamGroupIdsByConditions(condition: IamGroupIdsQueryConditionDTO): List { @@ -398,17 +388,12 @@ class RbacPermissionManageFacadeServiceImpl( start: Int?, limit: Int? ): Pair> { - // 获取用户加入的项目级用户组模板ID - val iamTemplateIds = listProjectMemberGroupTemplateIds( + // 获取用户的部门信息以及加入的项目级别用户组模板ID + val (iamTemplateIds, memberDeptInfos) = getMemberTemplateIdsAndDeptInfos( projectCode = projectCode, - memberId = memberId + memberId = memberId, + operateChannel = operateChannel ) - // 获取用户所属组织 - val memberDeptInfos = if (operateChannel == OperateChannel.PERSONAL) { - getMemberDeptInfos(memberId) - } else { - emptyList() - } val minExpiredTime = minExpiredAt?.let { DateTimeUtil.convertTimestampToLocalDateTime(it / 1000) } val maxExpiredTime = maxExpiredAt?.let { DateTimeUtil.convertTimestampToLocalDateTime(it / 1000) } @@ -475,87 +460,50 @@ class RbacPermissionManageFacadeServiceImpl( private fun getGroupIdsByGroupMemberCondition( projectCode: String, commonCondition: GroupMemberCommonConditionReq - ): Map> { - val finalResourceGroupMembers = mutableListOf() - with(commonCondition) { - // 1.根据条件筛选出用户组 - val resourceGroupMembersByCondition = when { - // 全选 - allSelection -> { + ): Map> { + val finalMemberGroups = mutableListOf() + + val resourceGroupMembersByCondition = when { + commonCondition.allSelection -> { + listResourceGroupMembers( + projectCode = projectCode, + memberId = commonCondition.targetMember.id, + operateChannel = commonCondition.operateChannel + ).second + } + + commonCondition.resourceTypes.isNotEmpty() -> { + commonCondition.resourceTypes.flatMap { resourceType -> listResourceGroupMembers( projectCode = projectCode, memberId = commonCondition.targetMember.id, + resourceType = resourceType, operateChannel = commonCondition.operateChannel ).second } - // 全选某些资源类型用户组 - resourceTypes.isNotEmpty() -> { - resourceTypes.flatMap { resourceType -> - listResourceGroupMembers( - projectCode = projectCode, - memberId = commonCondition.targetMember.id, - resourceType = resourceType, - operateChannel = commonCondition.operateChannel - ).second - } - } - - else -> { - emptyList() - } - } - - if (resourceGroupMembersByCondition.isNotEmpty()) { - finalResourceGroupMembers.addAll(resourceGroupMembersByCondition) } - if (groupIds.isNotEmpty()) { - val resourceGroupMembersOfSelect = listResourceGroupMembers( - projectCode = projectCode, - memberId = commonCondition.targetMember.id, - iamGroupIds = groupIds - ).second - finalResourceGroupMembers.addAll(resourceGroupMembersOfSelect) - } - - // 2.进行分类,直接/模板/部门加入 - val groupIdsOfDirectJoined = finalResourceGroupMembers.filter { - it.memberType == ManagerScopesEnum.getType(ManagerScopesEnum.TEMPLATE) - }.map { it.iamGroupId }.toMutableList() + else -> emptyList() + } - val groupInfoIdsOfTemplateJoined = finalResourceGroupMembers.filter { - it.memberType == ManagerScopesEnum.getType(ManagerScopesEnum.USER) - }.map { it.iamGroupId }.toMutableList() + finalMemberGroups.addAll(resourceGroupMembersByCondition) - val groupInfoIdsOfDepartmentJoined = finalResourceGroupMembers.filter { - it.memberType == ManagerScopesEnum.getType(ManagerScopesEnum.DEPARTMENT) - }.map { it.iamGroupId }.toMutableList() + if (commonCondition.groupIds.isNotEmpty()) { + val groupsOfSelect = listResourceGroupMembers( + projectCode = projectCode, + memberId = commonCondition.targetMember.id, + iamGroupIds = commonCondition.groupIds, + operateChannel = commonCondition.operateChannel + ).second + finalMemberGroups.addAll(groupsOfSelect) + } - // 3.根据条件排除用户组。 - // 3.1 排除唯一管理组(将用户移出用户组时,需进行排除) - if (excludedUniqueManagerGroup) { - val excludedUniqueManagerGroupIds = authResourceGroupMemberDao.listProjectUniqueManagerGroups( - dslContext = dslContext, - projectCode = projectCode, - iamGroupIds = groupIdsOfDirectJoined - ) - groupIdsOfDirectJoined.removeAll { - excludedUniqueManagerGroupIds.contains(it) - } - } - // 4.组装返回结果。 - val result = mutableMapOf>() - if (groupIdsOfDirectJoined.isNotEmpty()) { - result[ManagerScopesEnum.USER] = groupIdsOfDirectJoined - } - if (groupInfoIdsOfTemplateJoined.isNotEmpty()) { - result[ManagerScopesEnum.TEMPLATE] = groupInfoIdsOfTemplateJoined - } - if (groupInfoIdsOfDepartmentJoined.isNotEmpty()) { - result[ManagerScopesEnum.DEPARTMENT] = groupInfoIdsOfTemplateJoined - } - return result + // 分类 + val result = mutableMapOf>() + finalMemberGroups.groupBy { it.memberType }.forEach { (memberType, groups) -> + result[MemberType.get(memberType)] = groups.map { it.iamGroupId } } + return result } override fun listProjectMembersByComplexConditions( @@ -648,9 +596,8 @@ class RbacPermissionManageFacadeServiceImpl( projectCode: String, iamGroupIds: List, memberId: String - ): Pair, List> { + ): InvalidAuthorizationsDTO { logger.info("list invalid authorizations after operated groups:$projectCode|$iamGroupIds|$memberId") - deptService.getUserInfo(memberId, memberId) ?: return Pair(emptyList(), emptyList()) // 1.筛选出本次退出/交接中包含流水线执行权限的用户组 val operatedGroupsWithExecutePerm = groupPermissionService.listGroupsByPermissionConditions( projectCode = projectCode, @@ -688,7 +635,7 @@ class RbacPermissionManageFacadeServiceImpl( // 3.1.若用户在未退出的组中拥有整个项目的流水线执行权限,则本次不会对任何的流水线代持人权限造成影响。 if (hasAllPipelineExecutePermAfterOperateGroups) - return Pair(emptyList(), emptyList()) + return InvalidAuthorizationsDTO(emptyList(), emptyList()) // 3.2.若没有的话,查询本次退出/交接的用户组中是否包含项目级别的流水线执行权限。 val hasAllPipelineExecutePermInOperateGroups = groupPermissionService.isGroupsHasProjectLevelPermission( @@ -754,9 +701,12 @@ class RbacPermissionManageFacadeServiceImpl( } logger.debug("pipelines without authorization:{}", pipelinesWithoutAuthorization) if (pipelinesWithoutAuthorization.isNotEmpty()) { - return Pair(operatedGroupsWithExecutePerm, pipelinesWithoutAuthorization) + return InvalidAuthorizationsDTO( + invalidGroupIds = operatedGroupsWithExecutePerm, + invalidAuthorizations = pipelinesWithoutAuthorization + ) } - return Pair(emptyList(), emptyList()) + return InvalidAuthorizationsDTO(emptyList(), emptyList()) } override fun renewalGroupMember( @@ -786,8 +736,7 @@ class RbacPermissionManageFacadeServiceImpl( ) { logger.info("renewal group member ${renewalConditionReq.targetMember}|$projectCode|$groupId|$expiredAt") val targetMember = renewalConditionReq.targetMember - if (targetMember.type == ManagerScopesEnum.getType(ManagerScopesEnum.USER) && - deptService.isUserDeparted(targetMember.id)) { + if (targetMember.type == MemberType.USER.type && deptService.isUserDeparted(targetMember.id)) { return } val secondsOfRenewalDuration = TimeUnit.DAYS.toSeconds(renewalConditionReq.renewalDuration.toLong()) @@ -838,28 +787,284 @@ class RbacPermissionManageFacadeServiceImpl( projectCode: String, handoverMemberDTO: GroupMemberHandoverConditionReq ): Boolean { - logger.info("batch handover group members $userId|$projectCode|$handoverMemberDTO") + logger.info("batch handover group members from manager $userId|$projectCode|$handoverMemberDTO") handoverMemberDTO.checkHandoverTo() + // 若交接对象是部门,直接进行交接 + if (handoverMemberDTO.targetMember.type == MemberType.DEPARTMENT.type) { + batchOperateGroupMembers( + projectCode = projectCode, + conditionReq = handoverMemberDTO, + operateGroupMemberTask = ::handoverTask + ) + } + // 若操作对象是用户,需要将被影响流水线授权一并交接给授权人 + val groupIds = getGroupIdsByGroupMemberCondition( + projectCode = projectCode, + commonCondition = handoverMemberDTO + )[MemberType.USER] ?: return true + // 交接用户组 batchOperateGroupMembers( projectCode = projectCode, conditionReq = handoverMemberDTO, operateGroupMemberTask = ::handoverTask ) + // 获取导致流水线代持人权限受到影响的流水线,并进行交接 + val invalidPipelines = listInvalidAuthorizationsAfterOperatedGroups( + projectCode = projectCode, + iamGroupIds = groupIds, + memberId = handoverMemberDTO.targetMember.id + ).invalidAuthorizations + if (invalidPipelines.isNotEmpty()) { + // 交接授权 + permissionAuthorizationService.resetResourceAuthorizationByResourceType( + operator = userId, + projectCode = projectCode, + condition = ResourceAuthorizationHandoverConditionRequest( + projectCode = projectCode, + resourceType = ResourceTypeId.PIPELINE, + filterResourceCodes = invalidPipelines, + handoverChannel = HandoverChannelCode.MANAGER, + handoverFrom = handoverMemberDTO.targetMember.id, + handoverTo = handoverMemberDTO.handoverTo.id + ) + ) + } + return true + } + + override fun batchHandoverApplicationFromPersonal( + userId: String, + projectCode: String, + handoverMemberDTO: GroupMemberHandoverConditionReq + ): Boolean { + logger.info("batch handover group members from personal $userId|$projectCode|$handoverMemberDTO") + handoverMemberDTO.checkHandoverTo() + // 成员直接加入的组 + val groupIds = getGroupIdsByGroupMemberCondition( + projectCode = projectCode, + commonCondition = handoverMemberDTO + )[MemberType.get(MemberType.USER.type)] + if (groupIds.isNullOrEmpty()) { + return true + } + // 本次操作导致流水线代持人权限受到影响的流水线 + val invalidPipelines = listInvalidAuthorizationsAfterOperatedGroups( + projectCode = projectCode, + iamGroupIds = groupIds, + memberId = handoverMemberDTO.targetMember.id + ).invalidAuthorizations + val resourceGroups = authResourceGroupDao.listByRelationId( + dslContext = dslContext, + projectCode = projectCode, + iamGroupIds = groupIds.map { it.toString() } + ) + + val handoverDetails = mutableListOf() + val flowNo = permissionHandoverService.generateFlowNo() + val title = permissionHandoverService.generateTitle( + groupCount = groupIds.size, + authorizationCount = invalidPipelines.size + ) + resourceGroups.forEach { groupInfo -> + handoverDetails.add( + HandoverDetailDTO( + projectCode = projectCode, + flowNo = flowNo, + itemId = groupInfo.relationId, + resourceType = groupInfo.resourceType, + handoverType = HandoverType.GROUP + ) + ) + } + invalidPipelines.forEach { pipelineId -> + handoverDetails.add( + HandoverDetailDTO( + projectCode = projectCode, + flowNo = flowNo, + itemId = pipelineId, + resourceType = ResourceTypeId.PIPELINE, + handoverType = HandoverType.AUTHORIZATION + ) + ) + } + // 创建交接单 + permissionHandoverService.createHandoverApplication( + overview = HandoverOverviewCreateDTO( + projectCode = projectCode, + flowNo = flowNo, + title = title, + applicant = handoverMemberDTO.targetMember.id, + approver = handoverMemberDTO.handoverTo.id, + handoverStatus = HandoverStatus.PENDING, + groupCount = groupIds.size, + authorizationCount = invalidPipelines.size + ), + details = handoverDetails + ) return true } override fun batchDeleteResourceGroupMembersFromManager( userId: String, projectCode: String, - removeMemberDTO: GroupMemberCommonConditionReq + removeMemberDTO: GroupMemberRemoveConditionReq ): Boolean { logger.info("batch delete group members $userId|$projectCode|$removeMemberDTO") - removeMemberDTO.excludedUniqueManagerGroup = true + // 若操作对象是组织,则直接退出即可。 + if (removeMemberDTO.targetMember.type == MemberType.DEPARTMENT.type) { + batchOperateGroupMembers( + projectCode = projectCode, + conditionReq = removeMemberDTO, + operateGroupMemberTask = ::deleteTask + ) + return true + } + // 以下逻辑是用户类型成员的批量移出组 + // 根据条件获取成员直接加入的用户组 + val groupIds = getGroupIdsByGroupMemberCondition( + projectCode = projectCode, + commonCondition = removeMemberDTO + )[MemberType.USER] ?: return true + // 获取唯一管理员组 + val uniqueManagerGroups = authResourceGroupMemberDao.listProjectUniqueManagerGroups( + dslContext = dslContext, + projectCode = projectCode, + iamGroupIds = groupIds + ) + // 获取导致流水线代持人权限受到影响的用户组及流水线 + val (invalidGroups, invalidPipelines) = + listInvalidAuthorizationsAfterOperatedGroups( + projectCode = projectCode, + iamGroupIds = groupIds, + memberId = removeMemberDTO.targetMember.id + ) + val (toHandoverGroups, toDeleteGroups) = groupIds.partition { + uniqueManagerGroups.contains(it) || invalidGroups.contains(it) + } + // 直接退出的用户组 batchOperateGroupMembers( projectCode = projectCode, - conditionReq = removeMemberDTO, + conditionReq = GroupMemberRemoveConditionReq( + groupIds = toDeleteGroups, + targetMember = removeMemberDTO.targetMember + ), operateGroupMemberTask = ::deleteTask ) + // 交接唯一拥有者、影响代持人权限的用户组以及流水线授权 + if (toHandoverGroups.isNotEmpty()) { + removeMemberDTO.checkHandoverTo() + batchOperateGroupMembers( + projectCode = projectCode, + conditionReq = GroupMemberHandoverConditionReq( + groupIds = toHandoverGroups, + targetMember = removeMemberDTO.targetMember, + handoverTo = removeMemberDTO.handoverTo!! + ), + operateGroupMemberTask = ::handoverTask + ) + permissionAuthorizationService.resetResourceAuthorizationByResourceType( + operator = userId, + projectCode = projectCode, + condition = ResourceAuthorizationHandoverConditionRequest( + projectCode = projectCode, + resourceType = ResourceTypeId.PIPELINE, + filterResourceCodes = invalidPipelines, + handoverChannel = HandoverChannelCode.MANAGER, + handoverFrom = removeMemberDTO.targetMember.id, + handoverTo = removeMemberDTO.handoverTo!!.id + ) + ) + } + return true + } + + override fun batchDeleteResourceGroupMembersFromPersonal( + userId: String, + projectCode: String, + removeMemberDTO: GroupMemberRemoveConditionReq + ): Boolean { + logger.info("batch delete group members from personal $userId|$projectCode|$removeMemberDTO") + // 根据条件获取成员直接加入的用户组 + val groupIds = getGroupIdsByGroupMemberCondition( + projectCode = projectCode, + commonCondition = removeMemberDTO + )[MemberType.USER] ?: return true + // 获取唯一管理员组 + val uniqueManagerGroups = authResourceGroupMemberDao.listProjectUniqueManagerGroups( + dslContext = dslContext, + projectCode = projectCode, + iamGroupIds = groupIds + ) + // 获取导致流水线代持人权限受到影响的用户组及流水线 + val (invalidGroups, invalidPipelines) = + listInvalidAuthorizationsAfterOperatedGroups( + projectCode = projectCode, + iamGroupIds = groupIds, + memberId = removeMemberDTO.targetMember.id + ) + val (toHandoverGroups, toDeleteGroups) = groupIds.partition { + uniqueManagerGroups.contains(it) || invalidGroups.contains(it) + } + // 直接退出的用户组 + batchOperateGroupMembers( + projectCode = projectCode, + conditionReq = GroupMemberRemoveConditionReq( + groupIds = toDeleteGroups, + targetMember = removeMemberDTO.targetMember + ), + operateGroupMemberTask = ::deleteTask + ) + // 交接唯一拥有者、影响代持人权限的用户组以及流水线授权 + if (toHandoverGroups.isNotEmpty()) { + removeMemberDTO.checkHandoverTo() + val resourceGroups = authResourceGroupDao.listByRelationId( + dslContext = dslContext, + projectCode = projectCode, + iamGroupIds = toHandoverGroups.map { it.toString() } + ) + + val handoverDetails = mutableListOf() + val flowNo = permissionHandoverService.generateFlowNo() + val title = permissionHandoverService.generateTitle( + groupCount = groupIds.size, + authorizationCount = invalidPipelines.size + ) + resourceGroups.forEach { groupInfo -> + handoverDetails.add( + HandoverDetailDTO( + projectCode = projectCode, + flowNo = flowNo, + itemId = groupInfo.relationId, + resourceType = groupInfo.resourceType, + handoverType = HandoverType.GROUP + ) + ) + } + invalidPipelines.forEach { pipelineId -> + handoverDetails.add( + HandoverDetailDTO( + projectCode = projectCode, + flowNo = flowNo, + itemId = pipelineId, + resourceType = ResourceTypeId.PIPELINE, + handoverType = HandoverType.AUTHORIZATION + ) + ) + } + permissionHandoverService.createHandoverApplication( + overview = HandoverOverviewCreateDTO( + projectCode = projectCode, + flowNo = flowNo, + title = title, + applicant = removeMemberDTO.targetMember.id, + approver = removeMemberDTO.handoverTo!!.id, + handoverStatus = HandoverStatus.PENDING, + groupCount = toHandoverGroups.size, + authorizationCount = invalidPipelines.size + ), + details = handoverDetails + ) + } return true } @@ -889,7 +1094,7 @@ class RbacPermissionManageFacadeServiceImpl( deleteTask( projectCode = projectCode, groupId = groupId, - removeMemberDTO = GroupMemberCommonConditionReq( + removeMemberDTO = GroupMemberRemoveConditionReq( targetMember = handoverMemberDTO.targetMember ), expiredAt = finalExpiredAt @@ -907,7 +1112,7 @@ class RbacPermissionManageFacadeServiceImpl( deleteTask( projectCode = projectCode, groupId = groupId, - removeMemberDTO = GroupMemberCommonConditionReq( + removeMemberDTO = GroupMemberRemoveConditionReq( targetMember = handoverMemberDTO.targetMember ), expiredAt = finalExpiredAt @@ -951,7 +1156,7 @@ class RbacPermissionManageFacadeServiceImpl( private fun deleteTask( projectCode: String, groupId: Int, - removeMemberDTO: GroupMemberCommonConditionReq, + removeMemberDTO: GroupMemberRemoveConditionReq, expiredAt: Long ) { val targetMember = removeMemberDTO.targetMember @@ -976,33 +1181,68 @@ class RbacPermissionManageFacadeServiceImpl( conditionReq: GroupMemberCommonConditionReq ): BatchOperateGroupMemberCheckVo { logger.info("batch operate group member check|$userId|$projectCode|$batchOperateType|$conditionReq") - // 获取用户加入的用户组 + // 获取成员加入的用户组 val joinedType2GroupIds = getGroupIdsByGroupMemberCondition( projectCode = projectCode, commonCondition = conditionReq ) - val groupIdsOfDirectJoined = joinedType2GroupIds[ManagerScopesEnum.USER] ?: emptyList() - val groupInfoIdsOfTemplateJoined = joinedType2GroupIds[ManagerScopesEnum.TEMPLATE] ?: emptyList() - - val totalCount = groupIdsOfDirectJoined.size + groupInfoIdsOfTemplateJoined.size - val groupCountOfTemplateJoined = groupInfoIdsOfTemplateJoined.size + // 通过组织或者模板加入的用户组 + val groupsOfTemplateOrDeptJoined = when (conditionReq.targetMember.type) { + MemberType.USER.type -> { + listOfNotNull( + joinedType2GroupIds[MemberType.DEPARTMENT], + joinedType2GroupIds[MemberType.TEMPLATE] + ).flatten() + } + else -> joinedType2GroupIds[MemberType.TEMPLATE] ?: emptyList() + } + // 直接加入的组 + val groupsOfDirectlyJoined = joinedType2GroupIds[MemberType.get(conditionReq.targetMember.type)] ?: emptyList() + // 总数 + val totalCount = groupsOfTemplateOrDeptJoined.size + groupsOfDirectlyJoined.size return when (batchOperateType) { BatchOperateType.REMOVE -> { - val groupCountOfUniqueManager = authResourceGroupMemberDao.listProjectUniqueManagerGroups( - dslContext = dslContext, - projectCode = projectCode, - iamGroupIds = groupIdsOfDirectJoined - ).size - BatchOperateGroupMemberCheckVo( - totalCount = totalCount, - inoperableCount = groupCountOfUniqueManager + groupCountOfTemplateJoined - ) + if (conditionReq.targetMember.type == MemberType.DEPARTMENT.type) { + BatchOperateGroupMemberCheckVo( + totalCount = totalCount, + operableCount = groupsOfDirectlyJoined.size, + inoperableCount = groupsOfTemplateOrDeptJoined.size + ) + } else { + val groupsOfUniqueManager = authResourceGroupMemberDao.listProjectUniqueManagerGroups( + dslContext = dslContext, + projectCode = projectCode, + iamGroupIds = groupsOfDirectlyJoined + ) + // 本次操作导致流水线代持人权限受到影响的用户组及流水线 + val (invalidGroups, invalidPipelines) = + listInvalidAuthorizationsAfterOperatedGroups( + projectCode = projectCode, + iamGroupIds = groupsOfDirectlyJoined, + memberId = conditionReq.targetMember.id + ) + // 当批量移出时, + // 直接加入的组中,唯一管理员组/影响流水线代持权限不允许被移出 + // 间接加入的组中,通过组织、模板加入的组不允许被移出 + val groupsOfInOperableWhenBatchRemove = groupsOfDirectlyJoined.count { + groupsOfUniqueManager.contains(it) || invalidGroups.contains(it) + } + groupsOfTemplateOrDeptJoined.size + + BatchOperateGroupMemberCheckVo( + totalCount = totalCount, + operableCount = totalCount - groupsOfInOperableWhenBatchRemove, + inoperableCount = groupsOfInOperableWhenBatchRemove, + uniqueManagerCount = groupsOfUniqueManager.size, + invalidPipelineAuthorizationCount = invalidPipelines.size + ) + } } BatchOperateType.RENEWAL -> { + // 部门/组织加入以及永久权限的组不允许再续期 with(conditionReq) { - val isUserDeparted = targetMember.type == ManagerScopesEnum.getType(ManagerScopesEnum.USER) && + val isUserDeparted = targetMember.type == MemberType.USER.type && deptService.isUserDeparted(targetMember.id) // 离职用户不允许续期 if (isUserDeparted) { @@ -1016,27 +1256,29 @@ class RbacPermissionManageFacadeServiceImpl( projectCode = projectCode, memberId = targetMember.id, memberType = targetMember.type, - groupIds = groupIdsOfDirectJoined + groupIds = groupsOfDirectlyJoined ).filter { // iam用的是秒级时间戳 it.expiredAt == PERMANENT_EXPIRED_TIME / 1000 }.size + val groupsOfInOperableWhenBatchRenewal = groupCountOfPermanentExpiredTime + groupsOfTemplateOrDeptJoined.size BatchOperateGroupMemberCheckVo( totalCount = totalCount, - inoperableCount = groupCountOfPermanentExpiredTime + groupCountOfTemplateJoined + operableCount = totalCount - groupsOfInOperableWhenBatchRenewal, + inoperableCount = groupsOfInOperableWhenBatchRenewal ) } } } BatchOperateType.HANDOVER -> { - // 已过期(除唯一管理员组)或通过模板加入的不允许移交 + // 已过期(除唯一管理员组 )或通过模板/组织加入的不允许移交 with(conditionReq) { - val finalGroupIds = groupIdsOfDirectJoined.toMutableList() + val finalGroupIds = groupsOfDirectlyJoined.toMutableList() val uniqueManagerGroupIds = authResourceGroupMemberDao.listProjectUniqueManagerGroups( dslContext = dslContext, projectCode = projectCode, - iamGroupIds = groupIdsOfDirectJoined + iamGroupIds = groupsOfDirectlyJoined ) // 去除唯一管理员组 if (uniqueManagerGroupIds.isNotEmpty()) { @@ -1051,9 +1293,19 @@ class RbacPermissionManageFacadeServiceImpl( // iam用的是秒级时间戳 it.expiredAt < System.currentTimeMillis() / 1000 }.size + val inoperableCount = groupsOfTemplateOrDeptJoined.size + groupCountOfExpired + // 本次操作导致流水线代持人权限受到影响的流水线 + val invalidPipelines = listInvalidAuthorizationsAfterOperatedGroups( + projectCode = projectCode, + iamGroupIds = groupsOfDirectlyJoined, + memberId = conditionReq.targetMember.id + ).invalidAuthorizations + BatchOperateGroupMemberCheckVo( totalCount = totalCount, - inoperableCount = groupCountOfTemplateJoined + groupCountOfExpired + operableCount = totalCount - inoperableCount, + inoperableCount = groupsOfTemplateOrDeptJoined.size + groupCountOfExpired, + invalidPipelineAuthorizationCount = invalidPipelines.size ) } } @@ -1061,7 +1313,8 @@ class RbacPermissionManageFacadeServiceImpl( else -> { BatchOperateGroupMemberCheckVo( totalCount = totalCount, - inoperableCount = groupCountOfTemplateJoined + inoperableCount = groupsOfTemplateOrDeptJoined.size, + operableCount = groupsOfDirectlyJoined.size ) } } @@ -1076,7 +1329,7 @@ class RbacPermissionManageFacadeServiceImpl( return with(removeMemberFromProjectReq) { val memberType = targetMember.type val isNeedToHandover = handoverTo != null - if (memberType == ManagerScopesEnum.getType(ManagerScopesEnum.USER) && isNeedToHandover) { + if (memberType == MemberType.USER.type && isNeedToHandover) { removeMemberFromProjectReq.checkHandoverTo() val handoverMemberDTO = GroupMemberHandoverConditionReq( allSelection = true, @@ -1100,7 +1353,7 @@ class RbacPermissionManageFacadeServiceImpl( ) ) } else { - val removeMemberDTO = GroupMemberCommonConditionReq( + val removeMemberDTO = GroupMemberRemoveConditionReq( allSelection = true, targetMember = targetMember ) @@ -1111,7 +1364,7 @@ class RbacPermissionManageFacadeServiceImpl( ) } - if (memberType == ManagerScopesEnum.getType(ManagerScopesEnum.USER)) { + if (memberType == MemberType.USER.type) { // 查询用户还存在那些组织中 val userDeptInfos = deptService.getUserInfo( userId = "admin", @@ -1122,7 +1375,7 @@ class RbacPermissionManageFacadeServiceImpl( dslContext = dslContext, projectCode = projectCode, memberNames = userDeptInfos, - memberType = ManagerScopesEnum.getType(ManagerScopesEnum.DEPARTMENT) + memberType = MemberType.DEPARTMENT.type ) } } @@ -1147,7 +1400,7 @@ class RbacPermissionManageFacadeServiceImpl( ).let { it.totalCount == it.inoperableCount } val isMemberHasNoAuthorizations = - if (targetMember.type == ManagerScopesEnum.getType(ManagerScopesEnum.USER)) { + if (targetMember.type == MemberType.USER.type) { permissionAuthorizationService.listResourceAuthorizations( condition = ResourceAuthorizationConditionRequest( projectCode = projectCode, @@ -1160,6 +1413,105 @@ class RbacPermissionManageFacadeServiceImpl( return isMemberHasNoPermission && isMemberHasNoAuthorizations } + override fun handleHanoverApplication(request: HandoverOverviewUpdateReq): Boolean { + val overview = permissionHandoverService.getHandoverOverview(request.flowNo) + logger.info("revoke hanover application:{}|{} ", request, overview) + HandleHandoverApplicationLock(redisOperation, request.flowNo).use { lock -> + if (!lock.tryLock()) { + logger.warn("The handover application is being processed!$request") + throw ErrorCodeException(errorCode = ERROR_HANDOVER_HANDLE) + } + try { + handleHanoverCheck(request = request, overview = overview) + if (request.handoverAction == HandoverAction.AGREE) { + handleHandoverAgreeAction( + request = request, + overview = overview + ) + } + permissionHandoverService.updateHandoverApplication( + overview = request + ) + } catch (e: Exception) { + logger.warn("handle hanover application error,$e|$request") + throw e + } + } + return true + } + + private fun handleHanoverCheck( + request: HandoverOverviewUpdateReq, + overview: HandoverOverviewVo + ) { + if (overview.handoverStatus != HandoverStatus.PENDING) { + throw ErrorCodeException(errorCode = ERROR_HANDOVER_FINISH) + } + if (request.handoverAction == HandoverAction.REVOKE && request.operator != overview.applicant) { + throw ErrorCodeException(errorCode = ERROR_HANDOVER_REVOKE) + } + if (request.handoverAction != HandoverAction.REVOKE && request.operator != overview.approver) { + throw ErrorCodeException(errorCode = ERROR_HANDOVER_APPROVAL) + } + } + + private fun handleHandoverAgreeAction( + request: HandoverOverviewUpdateReq, + overview: HandoverOverviewVo + ) { + val handoverDetails = permissionHandoverService.listHandoverDetails( + projectCode = overview.projectCode, + flowNo = overview.flowNo + ) + val handoverType2Records = handoverDetails.groupBy { it.handoverType } + + // 交接用户组 + val groupsOfHandover = handoverType2Records[HandoverType.GROUP]?.map { it.itemId.toInt() } + if (!groupsOfHandover.isNullOrEmpty()) { + val targetMember = ResourceMemberInfo( + id = overview.applicant, + name = deptService.getMemberInfo(overview.applicant, ManagerScopesEnum.USER).displayName, + type = MemberType.USER.type + ) + val handoverTo = ResourceMemberInfo( + id = overview.approver, + name = deptService.getMemberInfo(overview.approver, ManagerScopesEnum.USER).displayName, + type = MemberType.USER.type + ) + + val groupMemberHandoverConditionReq = GroupMemberHandoverConditionReq( + groupIds = groupsOfHandover, + targetMember = targetMember, + handoverTo = handoverTo + ) + batchOperateGroupMembers( + projectCode = overview.projectCode, + conditionReq = groupMemberHandoverConditionReq, + operateGroupMemberTask = ::handoverTask + ) + } + + // 交接授权 + val authorizationsOfHandover = handoverType2Records[HandoverType.AUTHORIZATION] + if (!authorizationsOfHandover.isNullOrEmpty()) { + val resourceType2Authorizations = authorizationsOfHandover.groupBy { it.resourceType } + resourceType2Authorizations.forEach { (resourceType, authorizations) -> + permissionAuthorizationService.resetResourceAuthorizationByResourceType( + operator = request.operator, + projectCode = overview.projectCode, + condition = ResourceAuthorizationHandoverConditionRequest( + projectCode = overview.projectCode, + resourceType = resourceType, + filterResourceCodes = authorizations.map { it.itemId }, + handoverChannel = HandoverChannelCode.MANAGER, + handoverFrom = overview.applicant, + handoverTo = overview.approver + ) + ) + } + } + } + private fun batchOperateGroupMembers( projectCode: String, conditionReq: T, @@ -1170,11 +1522,11 @@ class RbacPermissionManageFacadeServiceImpl( expiredAt: Long ) -> Unit ): Boolean { - // 直接加入的组 + // 成员直接加入的组 val groupIds = getGroupIdsByGroupMemberCondition( projectCode = projectCode, commonCondition = conditionReq - )[ManagerScopesEnum.USER] + )[MemberType.get(conditionReq.targetMember.type)] if (groupIds.isNullOrEmpty()) { return true } @@ -1232,8 +1584,7 @@ class RbacPermissionManageFacadeServiceImpl( memberGroupsDetailsList.addAll( // 若离职,则从数据库获取用户加入组的过期时间,调用iam接口会报错。 // 虽然数据库的过期时间可能不是最新的。 - if (memberType == ManagerScopesEnum.getType(ManagerScopesEnum.USER) && - deptService.isUserDeparted(userId = memberId)) { + if (memberType == MemberType.USER.type && deptService.isUserDeparted(memberId)) { val records = authResourceGroupMemberDao.listMemberGroupDetail( dslContext = dslContext, projectCode = projectCode, diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupService.kt index 292dba02ec5..87aaf9a7c08 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupService.kt @@ -28,7 +28,6 @@ package com.tencent.devops.auth.provider.rbac.service -import com.tencent.bk.sdk.iam.constants.ManagerScopesEnum import com.tencent.bk.sdk.iam.dto.V2PageInfoDTO import com.tencent.bk.sdk.iam.dto.manager.ManagerRoleGroup import com.tencent.bk.sdk.iam.dto.manager.dto.ManagerRoleGroupDTO @@ -50,6 +49,7 @@ import com.tencent.devops.auth.pojo.dto.GroupAddDTO import com.tencent.devops.auth.pojo.dto.ListGroupConditionDTO import com.tencent.devops.auth.pojo.dto.RenameGroupDTO import com.tencent.devops.auth.pojo.enum.GroupMemberStatus +import com.tencent.devops.auth.pojo.enum.MemberType import com.tencent.devops.auth.pojo.request.CustomGroupCreateReq import com.tencent.devops.auth.pojo.vo.IamGroupInfoVo import com.tencent.devops.auth.pojo.vo.IamGroupMemberInfoVo @@ -181,8 +181,8 @@ class RbacPermissionResourceGroupService @Autowired constructor( dslContext = dslContext, projectCode = condition.projectId ) - val userCount = projectMemberCount[ManagerScopesEnum.getType(ManagerScopesEnum.USER)] ?: 0 - val departmentCount = projectMemberCount[ManagerScopesEnum.getType(ManagerScopesEnum.DEPARTMENT)] ?: 0 + val userCount = projectMemberCount[MemberType.USER.type] ?: 0 + val departmentCount = projectMemberCount[MemberType.DEPARTMENT.type] ?: 0 val allProjectMemberGroup = IamGroupInfoVo( managerId = managerId, defaultGroup = true, diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupSyncService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupSyncService.kt index 29bb6bfdb0e..6fbb4d634f3 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupSyncService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupSyncService.kt @@ -40,6 +40,7 @@ import com.tencent.devops.auth.pojo.AuthResourceGroup import com.tencent.devops.auth.pojo.AuthResourceGroupMember import com.tencent.devops.auth.pojo.enum.ApplyToGroupStatus import com.tencent.devops.auth.pojo.enum.AuthMigrateStatus +import com.tencent.devops.auth.pojo.enum.MemberType import com.tencent.devops.auth.service.iam.PermissionResourceGroupPermissionService import com.tencent.devops.auth.service.iam.PermissionResourceGroupSyncService import com.tencent.devops.auth.service.lock.SyncGroupAndMemberLock @@ -724,7 +725,7 @@ class RbacPermissionResourceGroupSyncService @Autowired constructor( iamGroupId = iamGroupId, memberId = iamGroupTemplate.id, memberName = iamGroupTemplate.name, - memberType = ManagerScopesEnum.getType(ManagerScopesEnum.TEMPLATE), + memberType = MemberType.TEMPLATE.type, expiredTime = expiredTime ) ) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceMemberService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceMemberService.kt index f93cf5cdc67..b0ad89bd245 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceMemberService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceMemberService.kt @@ -128,8 +128,8 @@ class RbacPermissionResourceMemberService( projectCode = projectCode ) return ResourceMemberCountVO( - userCount = projectMemberCount[ManagerScopesEnum.getType(ManagerScopesEnum.USER)] ?: 0, - departmentCount = projectMemberCount[ManagerScopesEnum.getType(ManagerScopesEnum.DEPARTMENT)] ?: 0 + userCount = projectMemberCount[MemberType.USER.type] ?: 0, + departmentCount = projectMemberCount[MemberType.DEPARTMENT.type] ?: 0 ) } @@ -175,7 +175,7 @@ class RbacPermissionResourceMemberService( override fun addDepartedFlagToMembers(records: List): List { val userMembers = records.filter { - it.type == ManagerScopesEnum.getType(ManagerScopesEnum.USER) + it.type == MemberType.USER.type }.map { it.id } val departedMembers = if (userMembers.isNotEmpty()) { deptService.listDepartedMembers( @@ -185,7 +185,7 @@ class RbacPermissionResourceMemberService( return records } return records.map { - if (it.type != ManagerScopesEnum.getType(ManagerScopesEnum.USER)) { + if (it.type != MemberType.USER.type) { it.copy(departed = false) } else { it.copy(departed = departedMembers.contains(it.id)) @@ -201,7 +201,7 @@ class RbacPermissionResourceMemberService( expiredAt: Long, iamGroupId: Int ): Boolean { - if (memberType == ManagerScopesEnum.getType(ManagerScopesEnum.USER) && + if (memberType == MemberType.USER.type && deptService.isUserDeparted(memberId)) { return true } @@ -268,8 +268,8 @@ class RbacPermissionResourceMemberService( iamGroupId = iamGroupId ) // 获取用户组中用户以及部门 - val userType = ManagerScopesEnum.getType(ManagerScopesEnum.USER) - val deptType = ManagerScopesEnum.getType(ManagerScopesEnum.DEPARTMENT) + val userType = MemberType.USER.type + val deptType = MemberType.DEPARTMENT.type val pageInfoDTO = V2PageInfoDTO().apply { pageSize = 1000 page = 1 @@ -404,8 +404,8 @@ class RbacPermissionResourceMemberService( projectCode = projectCode, iamGroupId = iamGroupId ) - val userType = ManagerScopesEnum.getType(ManagerScopesEnum.USER) - val deptType = ManagerScopesEnum.getType(ManagerScopesEnum.DEPARTMENT) + val userType = MemberType.USER.type + val deptType = MemberType.DEPARTMENT.type val allMemberIds = mutableListOf() if (!members.isNullOrEmpty()) { deleteIamGroupMembers( @@ -469,7 +469,7 @@ class RbacPermissionResourceMemberService( val nowTimestamp = System.currentTimeMillis() / 1000 val (members, deptInfoList) = groupMemberInfoList .filter { it.expiredAt > nowTimestamp } - .partition { it.type == ManagerScopesEnum.getType(ManagerScopesEnum.USER) } + .partition { it.type == MemberType.USER.type } return BkAuthGroupAndUserList( displayName = groupInfo.name, @@ -622,7 +622,7 @@ class RbacPermissionResourceMemberService( type: String, memberIds: List ): Boolean { - val membersOfNeedToDelete = if (type == ManagerScopesEnum.getType(ManagerScopesEnum.USER)) { + val membersOfNeedToDelete = if (type == MemberType.USER.type) { memberIds.filterNot { deptService.isUserDeparted(it) } } else { memberIds @@ -638,14 +638,14 @@ class RbacPermissionResourceMemberService( } private fun MutableList.removeDepartedMembers(): List { - val userMemberIds = this.filter { it.type == ManagerScopesEnum.getType(ManagerScopesEnum.USER) }.map { it.id } + val userMemberIds = this.filter { it.type == MemberType.USER.type }.map { it.id } if (userMemberIds.isEmpty()) return this // 获取离职的人员 val departedMembers = deptService.listDepartedMembers( memberIds = userMemberIds ) return this.filterNot { - it.type == ManagerScopesEnum.getType(ManagerScopesEnum.USER) && + it.type == MemberType.USER.type && departedMembers.contains(it.id) } } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionService.kt index 08b14499753..457f56925f4 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionService.kt @@ -29,7 +29,6 @@ package com.tencent.devops.auth.provider.rbac.service import com.tencent.bk.sdk.iam.config.IamConfiguration -import com.tencent.bk.sdk.iam.constants.ManagerScopesEnum import com.tencent.bk.sdk.iam.dto.InstanceDTO import com.tencent.bk.sdk.iam.dto.PathInfoDTO import com.tencent.bk.sdk.iam.dto.SubjectDTO @@ -39,6 +38,7 @@ import com.tencent.bk.sdk.iam.dto.resource.ResourceDTO import com.tencent.bk.sdk.iam.dto.resource.V2ResourceNode import com.tencent.bk.sdk.iam.helper.AuthHelper import com.tencent.bk.sdk.iam.service.PolicyService +import com.tencent.devops.auth.pojo.enum.MemberType import com.tencent.devops.auth.service.AuthProjectUserMetricsService import com.tencent.devops.auth.service.SuperManagerService import com.tencent.devops.auth.service.iam.PermissionService @@ -179,7 +179,7 @@ class RbacPermissionService( } ?: return false val subject = SubjectDTO.builder() .id(userId) - .type(ManagerScopesEnum.getType(ManagerScopesEnum.USER)) + .type(MemberType.USER.type) .build() val actionDTO = ActionDTO() diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/migrate/AbMigratePolicyService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/migrate/AbMigratePolicyService.kt index d74c7192ead..968ea175bc3 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/migrate/AbMigratePolicyService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/migrate/AbMigratePolicyService.kt @@ -29,7 +29,6 @@ package com.tencent.devops.auth.provider.rbac.service.migrate import com.tencent.bk.sdk.iam.config.IamConfiguration -import com.tencent.bk.sdk.iam.constants.ManagerScopesEnum import com.tencent.bk.sdk.iam.dto.manager.AuthorizationScopes import com.tencent.bk.sdk.iam.dto.manager.ManagerPath import com.tencent.bk.sdk.iam.dto.manager.ManagerResources @@ -41,6 +40,7 @@ import com.tencent.devops.auth.constant.AuthMessageCode import com.tencent.devops.auth.dao.AuthMigrationDao import com.tencent.devops.auth.dao.AuthResourceGroupConfigDao import com.tencent.devops.auth.dao.AuthResourceGroupDao +import com.tencent.devops.auth.pojo.enum.MemberType import com.tencent.devops.auth.provider.rbac.pojo.migrate.MigrateTaskDataResult import com.tencent.devops.auth.provider.rbac.service.RbacCacheService import com.tencent.devops.auth.provider.rbac.service.migrate.MigrateIamApiService.Companion.GROUP_API_POLICY @@ -382,7 +382,7 @@ abstract class AbMigratePolicyService( permissionResourceMemberService.addGroupMember( projectCode = projectCode, memberId = userId, - memberType = ManagerScopesEnum.getType(ManagerScopesEnum.USER), + memberType = MemberType.USER.type, expiredAt = System.currentTimeMillis() / MILLISECOND + TimeUnit.DAYS.toSeconds(DEFAULT_EXPIRED_DAY), iamGroupId = groupId diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/migrate/MigrateV0PolicyService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/migrate/MigrateV0PolicyService.kt index 7e286071d36..564063851c5 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/migrate/MigrateV0PolicyService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/migrate/MigrateV0PolicyService.kt @@ -29,7 +29,6 @@ package com.tencent.devops.auth.provider.rbac.service.migrate import com.tencent.bk.sdk.iam.config.IamConfiguration -import com.tencent.bk.sdk.iam.constants.ManagerScopesEnum import com.tencent.bk.sdk.iam.dto.V2PageInfoDTO import com.tencent.bk.sdk.iam.dto.manager.Action import com.tencent.bk.sdk.iam.dto.manager.AuthorizationScopes @@ -41,6 +40,7 @@ import com.tencent.bk.sdk.iam.service.v2.V2ManagerService import com.tencent.devops.auth.dao.AuthMigrationDao import com.tencent.devops.auth.dao.AuthResourceGroupConfigDao import com.tencent.devops.auth.dao.AuthResourceGroupDao +import com.tencent.devops.auth.pojo.enum.MemberType import com.tencent.devops.auth.provider.rbac.pojo.migrate.MigrateTaskDataResult import com.tencent.devops.auth.provider.rbac.service.AuthResourceCodeConverter import com.tencent.devops.auth.provider.rbac.service.RbacCacheService @@ -486,7 +486,7 @@ class MigrateV0PolicyService constructor( groupId = it.toInt(), defaultGroup = true, member = RoleGroupMemberInfo().apply { - type = ManagerScopesEnum.getType(ManagerScopesEnum.TEMPLATE) + type = MemberType.TEMPLATE.type id = subjectTemplateId name = subjectTemplateId expiredAt = 0 diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/config/MockAuthConfiguration.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/config/MockAuthConfiguration.kt index 517846766be..627bd5a0e04 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/config/MockAuthConfiguration.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/config/MockAuthConfiguration.kt @@ -8,6 +8,7 @@ import com.tencent.devops.auth.provider.sample.service.SampleAuthPermissionServi import com.tencent.devops.auth.provider.sample.service.SampleOrganizationService import com.tencent.devops.auth.provider.sample.service.SamplePermissionApplyService import com.tencent.devops.auth.provider.sample.service.SamplePermissionExtService +import com.tencent.devops.auth.provider.sample.service.SamplePermissionHandoverService import com.tencent.devops.auth.provider.sample.service.SamplePermissionItsmCallbackService import com.tencent.devops.auth.provider.sample.service.SamplePermissionMigrateService import com.tencent.devops.auth.provider.sample.service.SamplePermissionManageFacadeService @@ -27,6 +28,7 @@ import com.tencent.devops.auth.service.PermissionAuthorizationService import com.tencent.devops.auth.service.SuperManagerService import com.tencent.devops.auth.service.iam.PermissionApplyService import com.tencent.devops.auth.service.iam.PermissionExtService +import com.tencent.devops.auth.service.iam.PermissionHandoverService import com.tencent.devops.auth.service.iam.PermissionItsmCallbackService import com.tencent.devops.auth.service.iam.PermissionMigrateService import com.tencent.devops.auth.service.iam.PermissionProjectService @@ -128,4 +130,8 @@ class MockAuthConfiguration { @Bean @ConditionalOnMissingBean(PermissionResourceGroupSyncService::class) fun samplePermissionResourceGroupSyncService() = SamplePermissionResourceGroupSyncService() + + @Bean + @ConditionalOnMissingBean(PermissionHandoverService::class) + fun samplePermissionHandoverService() = SamplePermissionHandoverService() } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionHandoverService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionHandoverService.kt new file mode 100644 index 00000000000..83748b1af39 --- /dev/null +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionHandoverService.kt @@ -0,0 +1,62 @@ +package com.tencent.devops.auth.provider.sample.service + +import com.tencent.devops.auth.pojo.dto.HandoverDetailDTO +import com.tencent.devops.auth.pojo.dto.HandoverOverviewCreateDTO +import com.tencent.devops.auth.pojo.request.HandoverOverviewUpdateReq +import com.tencent.devops.auth.pojo.enum.HandoverType +import com.tencent.devops.auth.pojo.request.HandoverDetailsQueryReq +import com.tencent.devops.auth.pojo.request.HandoverOverviewQueryReq +import com.tencent.devops.auth.pojo.vo.HandoverAuthorizationDetailVo +import com.tencent.devops.auth.pojo.vo.HandoverGroupDetailVo +import com.tencent.devops.auth.pojo.vo.HandoverOverviewVo +import com.tencent.devops.auth.pojo.vo.ResourceType2CountVo +import com.tencent.devops.auth.service.iam.PermissionHandoverService +import com.tencent.devops.common.api.model.SQLPage + +class SamplePermissionHandoverService : PermissionHandoverService { + override fun createHandoverApplication( + overview: HandoverOverviewCreateDTO, + details: List + ) { + return + } + + override fun generateTitle(groupCount: Int, authorizationCount: Int): String = "" + + override fun generateFlowNo(): String = "" + + override fun updateHandoverApplication(overview: HandoverOverviewUpdateReq) { + return + } + + override fun getHandoverOverview(flowNo: String): HandoverOverviewVo { + TODO("Not yet implemented") + } + + override fun listHandoverOverviews(queryRequest: HandoverOverviewQueryReq): SQLPage { + return SQLPage(0, emptyList()) + } + + override fun listAuthorizationsOfHandover( + queryReq: HandoverDetailsQueryReq + ): SQLPage { + return SQLPage(0, emptyList()) + } + + override fun listGroupsOfHandover(queryReq: HandoverDetailsQueryReq): SQLPage { + return SQLPage(0, emptyList()) + } + + override fun getResourceType2CountOfHandover(flowNo: String): List { + return emptyList() + } + + override fun listHandoverDetails( + projectCode: String, + flowNo: String, + resourceType: String?, + handoverType: HandoverType? + ): List { + return emptyList() + } +} diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionManageFacadeService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionManageFacadeService.kt index f3e9313db7e..620adfeb671 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionManageFacadeService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionManageFacadeService.kt @@ -3,17 +3,20 @@ package com.tencent.devops.auth.provider.sample.service import com.tencent.devops.auth.pojo.AuthResourceGroupMember import com.tencent.devops.auth.pojo.ResourceMemberInfo import com.tencent.devops.auth.pojo.dto.IamGroupIdsQueryConditionDTO +import com.tencent.devops.auth.pojo.dto.InvalidAuthorizationsDTO import com.tencent.devops.auth.pojo.enum.BatchOperateType import com.tencent.devops.auth.pojo.enum.OperateChannel import com.tencent.devops.auth.pojo.request.GroupMemberCommonConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberHandoverConditionReq +import com.tencent.devops.auth.pojo.request.GroupMemberRemoveConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberRenewalConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberSingleRenewalReq +import com.tencent.devops.auth.pojo.request.HandoverOverviewUpdateReq import com.tencent.devops.auth.pojo.request.ProjectMembersQueryConditionReq import com.tencent.devops.auth.pojo.request.RemoveMemberFromProjectReq import com.tencent.devops.auth.pojo.vo.BatchOperateGroupMemberCheckVo import com.tencent.devops.auth.pojo.vo.GroupDetailsInfoVo -import com.tencent.devops.auth.pojo.vo.MemberGroupCountWithPermissionsVo +import com.tencent.devops.auth.pojo.vo.ResourceType2CountVo import com.tencent.devops.auth.service.iam.PermissionManageFacadeService import com.tencent.devops.common.api.model.SQLPage @@ -44,7 +47,7 @@ class SamplePermissionManageFacadeService : PermissionManageFacadeService { relatedResourceCode: String?, action: String?, operateChannel: OperateChannel? - ): List = emptyList() + ): List = emptyList() override fun listIamGroupIdsByConditions( condition: IamGroupIdsQueryConditionDTO @@ -76,7 +79,7 @@ class SamplePermissionManageFacadeService : PermissionManageFacadeService { projectCode: String, iamGroupIds: List, memberId: String - ): Pair, List> = Pair(emptyList(), emptyList()) + ): InvalidAuthorizationsDTO = InvalidAuthorizationsDTO(emptyList(), emptyList()) override fun renewalGroupMember( userId: String, @@ -96,10 +99,22 @@ class SamplePermissionManageFacadeService : PermissionManageFacadeService { handoverMemberDTO: GroupMemberHandoverConditionReq ): Boolean = true + override fun batchHandoverApplicationFromPersonal( + userId: String, + projectCode: String, + handoverMemberDTO: GroupMemberHandoverConditionReq + ): Boolean = true + override fun batchDeleteResourceGroupMembersFromManager( userId: String, projectCode: String, - removeMemberDTO: GroupMemberCommonConditionReq + removeMemberDTO: GroupMemberRemoveConditionReq + ): Boolean = true + + override fun batchDeleteResourceGroupMembersFromPersonal( + userId: String, + projectCode: String, + removeMemberDTO: GroupMemberRemoveConditionReq ): Boolean = true override fun batchOperateGroupMembersCheck( @@ -120,4 +135,6 @@ class SamplePermissionManageFacadeService : PermissionManageFacadeService { projectCode: String, removeMemberFromProjectReq: RemoveMemberFromProjectReq ): Boolean = true + + override fun handleHanoverApplication(request: HandoverOverviewUpdateReq): Boolean = true } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthHandoverResourceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthHandoverResourceImpl.kt new file mode 100644 index 00000000000..5a1f1a093b9 --- /dev/null +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthHandoverResourceImpl.kt @@ -0,0 +1,70 @@ +package com.tencent.devops.auth.resources.user + +import com.tencent.devops.auth.api.user.UserAuthHandoverResource +import com.tencent.devops.auth.pojo.request.HandoverDetailsQueryReq +import com.tencent.devops.auth.pojo.request.HandoverOverviewQueryReq +import com.tencent.devops.auth.pojo.request.HandoverOverviewUpdateReq +import com.tencent.devops.auth.pojo.vo.HandoverAuthorizationDetailVo +import com.tencent.devops.auth.pojo.vo.HandoverGroupDetailVo +import com.tencent.devops.auth.pojo.vo.HandoverOverviewVo +import com.tencent.devops.auth.pojo.vo.ResourceType2CountVo +import com.tencent.devops.auth.service.PermissionAuthorizationService +import com.tencent.devops.auth.service.iam.PermissionHandoverService +import com.tencent.devops.auth.service.iam.PermissionManageFacadeService +import com.tencent.devops.common.api.model.SQLPage +import com.tencent.devops.common.api.pojo.Result +import com.tencent.devops.common.auth.api.pojo.ResourceAuthorizationHandoverConditionRequest +import com.tencent.devops.common.web.RestResource + +@RestResource +class UserAuthHandoverResourceImpl( + private val permissionAuthorizationService: PermissionAuthorizationService, + private val permissionManageFacadeService: PermissionManageFacadeService, + private val permissionHandoverService: PermissionHandoverService +) : UserAuthHandoverResource { + override fun handoverAuthorizationsApplication( + userId: String, + projectId: String, + condition: ResourceAuthorizationHandoverConditionRequest + ): Result { + return Result( + permissionAuthorizationService.handoverAuthorizationsApplication( + operator = userId, + projectCode = projectId, + condition = condition + ) + ) + } + + override fun listHandoverOverviews( + userId: String, + queryRequest: HandoverOverviewQueryReq + ): Result> { + return Result(permissionHandoverService.listHandoverOverviews(queryRequest = queryRequest)) + } + + override fun getResourceType2CountOfHandover( + userId: String, + flowNo: String + ): Result> { + return Result(permissionHandoverService.getResourceType2CountOfHandover(flowNo = flowNo)) + } + + override fun listAuthorizationsOfHandover( + userId: String, + queryReq: HandoverDetailsQueryReq + ): Result> { + return Result(permissionHandoverService.listAuthorizationsOfHandover(queryReq = queryReq)) + } + + override fun listGroupsOfHandover( + userId: String, + queryReq: HandoverDetailsQueryReq + ): Result> { + return Result(permissionHandoverService.listGroupsOfHandover(queryReq = queryReq)) + } + + override fun handleHanoverApplication(userId: String, request: HandoverOverviewUpdateReq): Result { + return Result(permissionManageFacadeService.handleHanoverApplication(request = request)) + } +} diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceGroupResourceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceGroupResourceImpl.kt index 2d389901bb1..543d63df886 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceGroupResourceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceGroupResourceImpl.kt @@ -28,13 +28,13 @@ package com.tencent.devops.auth.resources.user -import com.tencent.bk.sdk.iam.constants.ManagerScopesEnum import com.tencent.devops.auth.api.user.UserAuthResourceGroupResource import com.tencent.devops.auth.pojo.ResourceMemberInfo import com.tencent.devops.auth.pojo.dto.GroupMemberRenewalDTO import com.tencent.devops.auth.pojo.dto.RenameGroupDTO +import com.tencent.devops.auth.pojo.enum.MemberType import com.tencent.devops.auth.pojo.enum.OperateChannel -import com.tencent.devops.auth.pojo.request.GroupMemberCommonConditionReq +import com.tencent.devops.auth.pojo.request.GroupMemberRemoveConditionReq import com.tencent.devops.auth.pojo.vo.GroupDetailsInfoVo import com.tencent.devops.auth.pojo.vo.IamGroupPoliciesVo import com.tencent.devops.auth.service.iam.PermissionManageFacadeService @@ -138,11 +138,11 @@ class UserAuthResourceGroupResourceImpl @Autowired constructor( permissionManageFacadeService.batchDeleteResourceGroupMembersFromManager( userId = userId, projectCode = projectId, - removeMemberDTO = GroupMemberCommonConditionReq( + removeMemberDTO = GroupMemberRemoveConditionReq( groupIds = listOf(groupId), targetMember = ResourceMemberInfo( id = userId, - type = ManagerScopesEnum.getType(ManagerScopesEnum.USER) + type = MemberType.USER.type ) ) ) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceMemberResourceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceMemberResourceImpl.kt index 023cd3c7c1a..93b6f654996 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceMemberResourceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceMemberResourceImpl.kt @@ -6,13 +6,14 @@ import com.tencent.devops.auth.pojo.enum.BatchOperateType import com.tencent.devops.auth.pojo.enum.OperateChannel import com.tencent.devops.auth.pojo.request.GroupMemberCommonConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberHandoverConditionReq +import com.tencent.devops.auth.pojo.request.GroupMemberRemoveConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberRenewalConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberSingleRenewalReq import com.tencent.devops.auth.pojo.request.ProjectMembersQueryConditionReq import com.tencent.devops.auth.pojo.request.RemoveMemberFromProjectReq import com.tencent.devops.auth.pojo.vo.BatchOperateGroupMemberCheckVo import com.tencent.devops.auth.pojo.vo.GroupDetailsInfoVo -import com.tencent.devops.auth.pojo.vo.MemberGroupCountWithPermissionsVo +import com.tencent.devops.auth.pojo.vo.ResourceType2CountVo import com.tencent.devops.auth.service.iam.PermissionManageFacadeService import com.tencent.devops.auth.service.iam.PermissionResourceMemberService import com.tencent.devops.auth.service.iam.PermissionResourceValidateService @@ -117,7 +118,7 @@ class UserAuthResourceMemberResourceImpl( override fun batchRemoveGroupMembersFromManager( userId: String, projectId: String, - removeMemberDTO: GroupMemberCommonConditionReq + removeMemberDTO: GroupMemberRemoveConditionReq ): Result { return Result( permissionManageFacadeService.batchDeleteResourceGroupMembersFromManager( @@ -128,6 +129,20 @@ class UserAuthResourceMemberResourceImpl( ) } + override fun batchRemoveGroupMembersFromPersonal( + userId: String, + projectId: String, + removeMemberDTO: GroupMemberRemoveConditionReq + ): Result { + return Result( + permissionManageFacadeService.batchDeleteResourceGroupMembersFromPersonal( + userId = userId, + projectCode = projectId, + removeMemberDTO = removeMemberDTO + ) + ) + } + @BkManagerCheck override fun batchHandoverGroupMembersFromManager( userId: String, @@ -143,6 +158,20 @@ class UserAuthResourceMemberResourceImpl( ) } + override fun batchHandoverApplicationFromPersonal( + userId: String, + projectId: String, + handoverMemberDTO: GroupMemberHandoverConditionReq + ): Result { + return Result( + permissionManageFacadeService.batchHandoverApplicationFromPersonal( + userId = userId, + projectCode = projectId, + handoverMemberDTO = handoverMemberDTO + ) + ) + } + @BkManagerCheck override fun batchOperateGroupMembersCheck( userId: String, @@ -201,7 +230,7 @@ class UserAuthResourceMemberResourceImpl( relatedResourceCode: String?, action: String?, operateChannel: OperateChannel? - ): Result> { + ): Result> { permissionResourceValidateService.validateUserProjectPermissionByChannel( userId = userId, projectCode = projectId, @@ -216,7 +245,8 @@ class UserAuthResourceMemberResourceImpl( maxExpiredAt = maxExpiredAt, relatedResourceType = relatedResourceType, relatedResourceCode = relatedResourceCode, - action = action + action = action, + operateChannel = operateChannel ) ) } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationService.kt index 301dd66bea8..5cf6e3117ca 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationService.kt @@ -121,6 +121,15 @@ interface PermissionAuthorizationService { condition: ResourceAuthorizationHandoverConditionRequest ): Map> + /** + * 交接授权申请 + */ + fun handoverAuthorizationsApplication( + operator: String, + projectCode: String, + condition: ResourceAuthorizationHandoverConditionRequest + ): Boolean + /** * 批量重置授权人--项目下全量 */ diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt index bbde2b535c4..15b7846adba 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt @@ -3,8 +3,14 @@ package com.tencent.devops.auth.service import com.tencent.bk.sdk.iam.constants.ManagerScopesEnum import com.tencent.devops.auth.constant.AuthI18nConstants import com.tencent.devops.auth.constant.AuthMessageCode +import com.tencent.devops.auth.constant.AuthMessageCode.ERROR_HANDOVER_AUTHORIZATION import com.tencent.devops.auth.dao.AuthAuthorizationDao +import com.tencent.devops.auth.pojo.dto.HandoverDetailDTO +import com.tencent.devops.auth.pojo.dto.HandoverOverviewCreateDTO +import com.tencent.devops.auth.pojo.enum.HandoverStatus +import com.tencent.devops.auth.pojo.enum.HandoverType import com.tencent.devops.auth.pojo.vo.ResourceTypeInfoVo +import com.tencent.devops.auth.service.iam.PermissionHandoverService import com.tencent.devops.auth.service.iam.PermissionResourceValidateService import com.tencent.devops.auth.service.iam.PermissionService import com.tencent.devops.common.api.exception.ErrorCodeException @@ -36,7 +42,8 @@ class PermissionAuthorizationServiceImpl( private val client: Client, private val permissionResourceValidateService: PermissionResourceValidateService, private val deptService: DeptService, - private val permissionService: PermissionService + private val permissionService: PermissionService, + private val permissionHandoverService: PermissionHandoverService ) : PermissionAuthorizationService { companion object { private val logger = LoggerFactory.getLogger(PermissionAuthorizationServiceImpl::class.java) @@ -226,6 +233,58 @@ class PermissionAuthorizationServiceImpl( return result } + override fun handoverAuthorizationsApplication( + operator: String, + projectCode: String, + condition: ResourceAuthorizationHandoverConditionRequest + ): Boolean { + val handoverResult = resetResourceAuthorizationByResourceType( + operator = operator, + projectCode = projectCode, + condition = condition.copy( + preCheck = true, + checkPermission = false + ) + ) + if (!handoverResult[ResourceAuthorizationHandoverStatus.FAILED].isNullOrEmpty()) { + throw ErrorCodeException(errorCode = ERROR_HANDOVER_AUTHORIZATION) + } + val resourceAuthorizationList = getResourceAuthorizationList(condition = condition) + val authorizationCount = resourceAuthorizationList.size + val flowNo = permissionHandoverService.generateFlowNo() + val title = permissionHandoverService.generateTitle( + groupCount = 0, + authorizationCount = authorizationCount + ) + val handoverDetails = mutableListOf() + resourceAuthorizationList.forEach { authorization -> + handoverDetails.add( + HandoverDetailDTO( + projectCode = projectCode, + flowNo = flowNo, + itemId = authorization.resourceCode, + resourceType = authorization.resourceType, + handoverType = HandoverType.AUTHORIZATION + ) + ) + } + // 创建交接单 + permissionHandoverService.createHandoverApplication( + overview = HandoverOverviewCreateDTO( + projectCode = projectCode, + flowNo = flowNo, + title = title, + applicant = condition.handoverFrom!!, + approver = condition.handoverTo!!, + handoverStatus = HandoverStatus.PENDING, + groupCount = 0, + authorizationCount = resourceAuthorizationList.size + ), + details = handoverDetails + ) + return true + } + override fun resetAllResourceAuthorization( operator: String, projectCode: String, diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionHandoverService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionHandoverService.kt new file mode 100644 index 00000000000..037cd4bc671 --- /dev/null +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionHandoverService.kt @@ -0,0 +1,70 @@ +package com.tencent.devops.auth.service.iam + +import com.tencent.devops.auth.pojo.dto.HandoverDetailDTO +import com.tencent.devops.auth.pojo.dto.HandoverOverviewCreateDTO +import com.tencent.devops.auth.pojo.request.HandoverOverviewUpdateReq +import com.tencent.devops.auth.pojo.enum.HandoverType +import com.tencent.devops.auth.pojo.request.HandoverDetailsQueryReq +import com.tencent.devops.auth.pojo.request.HandoverOverviewQueryReq +import com.tencent.devops.auth.pojo.vo.HandoverAuthorizationDetailVo +import com.tencent.devops.auth.pojo.vo.HandoverGroupDetailVo +import com.tencent.devops.auth.pojo.vo.HandoverOverviewVo +import com.tencent.devops.auth.pojo.vo.ResourceType2CountVo +import com.tencent.devops.common.api.model.SQLPage + +interface PermissionHandoverService { + /** + * 创建权限交接申请单 + * */ + fun createHandoverApplication(overview: HandoverOverviewCreateDTO, details: List) + + /** + * 生成交接单标题 + * */ + fun generateTitle(groupCount: Int, authorizationCount: Int): String + + /** + * 生成流程单号 + * */ + fun generateFlowNo(): String + + /** + * 更新权限交接申请单 + * */ + fun updateHandoverApplication(overview: HandoverOverviewUpdateReq) + + /** + * 根据流程单号获取权限交接总览 + * */ + fun getHandoverOverview(flowNo: String): HandoverOverviewVo + + /** + * 权限交接总览列表 + * */ + fun listHandoverOverviews(queryRequest: HandoverOverviewQueryReq): SQLPage + + /** + * 获取交接单详情 + * */ + fun listHandoverDetails( + projectCode: String, + flowNo: String, + resourceType: String? = null, + handoverType: HandoverType? = null + ): List + + /** + * 获取交接单中授权相关 + * */ + fun listAuthorizationsOfHandover(queryReq: HandoverDetailsQueryReq): SQLPage + + /** + * 获取交接单中用户组相关 + * */ + fun listGroupsOfHandover(queryReq: HandoverDetailsQueryReq): SQLPage + + /** + * 根据资源类型进行分类 + * */ + fun getResourceType2CountOfHandover(flowNo: String): List +} diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionManageFacadeService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionManageFacadeService.kt index 1004c429b47..6b5a2c8479a 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionManageFacadeService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionManageFacadeService.kt @@ -3,17 +3,20 @@ package com.tencent.devops.auth.service.iam import com.tencent.devops.auth.pojo.AuthResourceGroupMember import com.tencent.devops.auth.pojo.ResourceMemberInfo import com.tencent.devops.auth.pojo.dto.IamGroupIdsQueryConditionDTO +import com.tencent.devops.auth.pojo.dto.InvalidAuthorizationsDTO import com.tencent.devops.auth.pojo.enum.BatchOperateType import com.tencent.devops.auth.pojo.enum.OperateChannel import com.tencent.devops.auth.pojo.request.GroupMemberCommonConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberHandoverConditionReq +import com.tencent.devops.auth.pojo.request.GroupMemberRemoveConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberRenewalConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberSingleRenewalReq +import com.tencent.devops.auth.pojo.request.HandoverOverviewUpdateReq import com.tencent.devops.auth.pojo.request.ProjectMembersQueryConditionReq import com.tencent.devops.auth.pojo.request.RemoveMemberFromProjectReq import com.tencent.devops.auth.pojo.vo.BatchOperateGroupMemberCheckVo import com.tencent.devops.auth.pojo.vo.GroupDetailsInfoVo -import com.tencent.devops.auth.pojo.vo.MemberGroupCountWithPermissionsVo +import com.tencent.devops.auth.pojo.vo.ResourceType2CountVo import com.tencent.devops.common.api.model.SQLPage /** @@ -56,7 +59,7 @@ interface PermissionManageFacadeService { relatedResourceCode: String?, action: String?, operateChannel: OperateChannel? = OperateChannel.MANAGER - ): List + ): List /** * 根据条件查询组ID @@ -108,7 +111,7 @@ interface PermissionManageFacadeService { projectCode: String, iamGroupIds: List, memberId: String - ): Pair/*引起代持人权限失效的用户组*/, List/*引起代持人权限失效的流水线*/> + ): InvalidAuthorizationsDTO /** * 续期用户权限-无需审批版本 @@ -137,13 +140,31 @@ interface PermissionManageFacadeService { handoverMemberDTO: GroupMemberHandoverConditionReq ): Boolean + /** + * 批量交接申请-个人视角 + * */ + fun batchHandoverApplicationFromPersonal( + userId: String, + projectCode: String, + handoverMemberDTO: GroupMemberHandoverConditionReq + ): Boolean + /** * 批量移除-管理员视角 * */ fun batchDeleteResourceGroupMembersFromManager( userId: String, projectCode: String, - removeMemberDTO: GroupMemberCommonConditionReq + removeMemberDTO: GroupMemberRemoveConditionReq + ): Boolean + + /** + * 批量退出-个人视角 + * */ + fun batchDeleteResourceGroupMembersFromPersonal( + userId: String, + projectCode: String, + removeMemberDTO: GroupMemberRemoveConditionReq ): Boolean fun batchOperateGroupMembersCheck( @@ -164,4 +185,9 @@ interface PermissionManageFacadeService { projectCode: String, removeMemberFromProjectReq: RemoveMemberFromProjectReq ): Boolean + + /** + * 处理交接审批单 + * */ + fun handleHanoverApplication(request: HandoverOverviewUpdateReq): Boolean } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/lock/HandleHandoverApplicationLock.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/lock/HandleHandoverApplicationLock.kt new file mode 100644 index 00000000000..741873edb55 --- /dev/null +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/lock/HandleHandoverApplicationLock.kt @@ -0,0 +1,45 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. + * + * A copy of the MIT License is included in this file. + * + * + * Terms of the MIT License: + * --------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.tencent.devops.auth.service.lock + +import com.tencent.devops.common.redis.RedisLock +import com.tencent.devops.common.redis.RedisOperation + +class HandleHandoverApplicationLock( + redisOperation: RedisOperation, + flowNo: String +) : + RedisLock( + redisOperation = redisOperation, + lockKey = "auth.handover.$flowNo.lock", + expiredTimeInSeconds = 1800 + ) { + override fun decorateKey(key: String): String { + return key + } +} diff --git a/support-files/i18n/auth/message_en_US.properties b/support-files/i18n/auth/message_en_US.properties index 9b78ae65485..1c955293c00 100644 --- a/support-files/i18n/auth/message_en_US.properties +++ b/support-files/i18n/auth/message_en_US.properties @@ -83,6 +83,13 @@ 2121088=The target member and the handover person are not allowed to be the same. 2121089=Expired permissions are not allowed to be transferred 2121090=Please wait until the next day for user information to be synchronized before trying again, as the information of new users has not yet been synchronized. +2121091=Handover overview not exist +2121092=The handover request has already been processed, and duplicate actions are not allowed +2121093=You are not the initiator of this handover request, so you are not authorized to revoke it +2121094=Due to the fact that you are not the approver of this handover request, you are unable to perform any actions on it. +2121095=The handover request is currently being processed. Please be patient and wait for further updates. +2121096=The handover operation is illegal and the user does not have authorization permissions + bkAdministratorNotExpired=Permission has not expired and no action is required bkAgreeRenew=Agree to renew bkApproverAgreeRenew=Approver agreed to your permission renewal @@ -333,3 +340,6 @@ rule.resourceType.name=Andon Rule bkMemberExpiredAtDisplayExpired=expired bkMemberExpiredAtDisplayNormal={0} days bkMemberExpiredAtDisplayPermanent=permanent +bkApplyToHandover=apply to hand over +bkHandoverGroups={0} groups +bkHandoverAuthorizations={0} authorizations diff --git a/support-files/i18n/auth/message_zh_CN.properties b/support-files/i18n/auth/message_zh_CN.properties index c883c136e04..d624a5826bf 100644 --- a/support-files/i18n/auth/message_zh_CN.properties +++ b/support-files/i18n/auth/message_zh_CN.properties @@ -83,6 +83,13 @@ 2121088=目标对象和交接人不允许相同 2121089=已过期的权限不允许交接 2121090=请等待第二天用户信息同步后再尝试操作,因为新入职用户的信息尚未同步完成。 +2121091=权限交接记录不存在 +2121092=该交接申请单已被处理,不允许重复操作 +2121093=由于您不是该交接申请单的发起人,无法进行撤销操作 +2121094=由于您不是该交接申请单的审批人,无法进行任何操作 +2121095=该交接申请单正在被处理中,请耐心等待 +2121096=交接操作不合法,用户没有对应授权的权限 + bkAdministratorNotExpired=权限还未过期,不需要操作 bkAgreeRenew=同意续期 bkApproverAgreeRenew=审批人同意了您的权限续期 @@ -336,3 +343,7 @@ rule.resourceType.name=质量红线规则 bkMemberExpiredAtDisplayExpired=已过期 bkMemberExpiredAtDisplayNormal={0} 天 bkMemberExpiredAtDisplayPermanent=永久 + +bkApplyToHandover=申请移交 +bkHandoverGroups={0}个权限用户组 +bkHandoverAuthorizations={0}个授权 diff --git a/support-files/sql/1001_ci_auth_ddl_mysql.sql b/support-files/sql/1001_ci_auth_ddl_mysql.sql index 41e31bc6291..77ef7a6cf94 100644 --- a/support-files/sql/1001_ci_auth_ddl_mysql.sql +++ b/support-files/sql/1001_ci_auth_ddl_mysql.sql @@ -440,4 +440,35 @@ CREATE TABLE IF NOT EXISTS `T_AUTH_RESOURCE_GROUP_PERMISSION` ( INDEX `IDX_PROJECT_AND_ACTION_RESOURCE_TYPE` (`PROJECT_CODE`, `ACTION_RELATED_RESOURCE_TYPE`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='资源组权限表'; +CREATE TABLE IF NOT EXISTS `T_AUTH_HANDOVER_OVERVIEW` ( + `ID` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `PROJECT_CODE` varchar(64) NOT NULL COMMENT '项目ID', + `FLOW_NO` varchar(64) NOT NULL COMMENT '流程单号', + `TITLE` varchar(256) DEFAULT NULL COMMENT '标题', + `APPLICANT` varchar(32) NOT NULL COMMENT '申请人', + `APPROVER` varchar(32) DEFAULT NULL COMMENT '审批人', + `STATUS` int DEFAULT 0 COMMENT '审批结果,0-审批中,1-审批成功,2-审批拒绝,3-撤销', + `GROUP_COUNT` int DEFAULT 0 comment '用户组数', + `AUTHORIZATION_COUNT` int DEFAULT 0 comment '授权个数', + `REMARK` varchar(256) DEFAULT NULL COMMENT '备注', + `CREATE_TIME` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `UPDATE_TIME` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`ID`), + UNIQUE KEY `UNIQ_FLOW_NO` (`FLOW_NO`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限交接总览表'; + + +CREATE TABLE IF NOT EXISTS `T_AUTH_HANDOVER_DETAIL` ( + `ID` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `PROJECT_CODE` varchar(64) NOT NULL COMMENT '项目ID', + `FLOW_NO` varchar(64) NOT NULL COMMENT '流程单号', + `ITEM_ID` varchar(255) NOT NULL COMMENT '组/授权资源ID', + `RESOURCE_TYPE` varchar(32) NOT NULL COMMENT '组/授权资源关联的资源类型', + `HANDOVER_TYPE` varchar(32) NOT NULL COMMENT '交接类型-group/authorization', + `CREATE_TIME` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `UPDATE_TIME` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`ID`), + INDEX `IDX_PROJECT_FLOW` (`PROJECT_CODE`,`FLOW_NO`,`HANDOVER_TYPE`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限交接详细表'; + SET FOREIGN_KEY_CHECKS = 1; From 8b07d6e90a845e00d6098cf1fab2bdc1fc7cdac0 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Thu, 14 Nov 2024 21:02:32 +0800 Subject: [PATCH 04/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/auth/api/pojo/ResourceAuthorizationResponse.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationResponse.kt b/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationResponse.kt index 3b4062e55ec..f38136c3bc4 100644 --- a/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationResponse.kt +++ b/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationResponse.kt @@ -6,7 +6,7 @@ import io.swagger.v3.oas.annotations.media.Schema @Suppress("LongParameterList") data class ResourceAuthorizationResponse( @get:Schema(title = "ID") - val id: Long, + val id: Long? = null, @get:Schema(title = "项目ID") val projectCode: String, @get:Schema(title = "资源类型") From 712e056b85d1d7a03b6d3dd6daa94595016d8d79 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Thu, 14 Nov 2024 21:08:31 +0800 Subject: [PATCH 05/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tencent/devops/repository/service/RepositoryAuthService.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/RepositoryAuthService.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/RepositoryAuthService.kt index 0d5ae9b7177..d69d780b489 100644 --- a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/RepositoryAuthService.kt +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/RepositoryAuthService.kt @@ -153,7 +153,7 @@ class RepositoryAuthService @Autowired constructor( repositoryInfos.map { val entity = ResourceAuthorizationResponse( projectCode = projectId, - resourceType = AuthResourceType.PIPELINE_DEFAULT.value, + resourceType = AuthResourceType.CODE_REPERTORY.value, resourceName = it.aliasName, resourceCode = it.repositoryHashId!!, handoverTime = it.updatedTime, From 753a8c0f2bb0c39d190966034e5e10d884814d99 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Thu, 14 Nov 2024 21:21:56 +0800 Subject: [PATCH 06/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devops/auth/dao/AuthResourceGroupPermissionDao.kt | 1 + .../rbac/service/RbacPermissionManageFacadeServiceImpl.kt | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupPermissionDao.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupPermissionDao.kt index 439b357e03e..4ca56fad06d 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupPermissionDao.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupPermissionDao.kt @@ -215,6 +215,7 @@ class AuthResourceGroupPermissionDao { dslContext.select(RELATED_RESOURCE_TYPE, RELATED_RESOURCE_CODE) .from(this) .where(PROJECT_CODE.eq(projectCode)) + .and(IAM_GROUP_ID.`in`(filterIamGroupIds)) .and(ACTION_RELATED_RESOURCE_TYPE.eq(resourceType)) .and(ACTION.eq(action)) .groupBy(RELATED_RESOURCE_TYPE, RELATED_RESOURCE_CODE) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt index 3fa1caded28..77a032b86d7 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt @@ -612,14 +612,16 @@ class RbacPermissionManageFacadeServiceImpl( projectCode = projectCode, memberId = memberId, resourceType = ResourceTypeId.PIPELINE, - excludeIamGroupIds = operatedGroupsWithExecutePerm + excludeIamGroupIds = operatedGroupsWithExecutePerm, + operateChannel = OperateChannel.PERSONAL ).second.toMutableList().apply { addAll( listResourceGroupMembers( projectCode = projectCode, memberId = memberId, resourceType = ResourceTypeId.PROJECT, - excludeIamGroupIds = operatedGroupsWithExecutePerm + excludeIamGroupIds = operatedGroupsWithExecutePerm, + operateChannel = OperateChannel.PERSONAL ).second ) }.map { it.iamGroupId } From 773dcd9f3cab3ae631a6251a5c741072878c980c Mon Sep 17 00:00:00 2001 From: greysonfang Date: Fri, 15 Nov 2024 10:02:39 +0800 Subject: [PATCH 07/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- support-files/i18n/auth/message_zh_CN.properties | 1 - 1 file changed, 1 deletion(-) diff --git a/support-files/i18n/auth/message_zh_CN.properties b/support-files/i18n/auth/message_zh_CN.properties index d624a5826bf..c6aa3be3893 100644 --- a/support-files/i18n/auth/message_zh_CN.properties +++ b/support-files/i18n/auth/message_zh_CN.properties @@ -339,7 +339,6 @@ project.resourceType.name=项目 quality_group.resourceType.name=质量红线通知组 repertory.resourceType.name=代码库 rule.resourceType.name=质量红线规则 - bkMemberExpiredAtDisplayExpired=已过期 bkMemberExpiredAtDisplayNormal={0} 天 bkMemberExpiredAtDisplayPermanent=永久 From d9cc7326194f57afea78282674598e098e995863 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Fri, 15 Nov 2024 10:53:56 +0800 Subject: [PATCH 08/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/tencent/devops/auth/dao/AuthResourceGroupMemberDao.kt | 4 ++++ .../provider/rbac/service/RbacPermissionHandoverService.kt | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupMemberDao.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupMemberDao.kt index 1ad65f22ba9..05e4ef12e03 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupMemberDao.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupMemberDao.kt @@ -32,6 +32,7 @@ import com.tencent.devops.auth.pojo.ResourceMemberInfo import com.tencent.devops.auth.pojo.dto.ProjectMembersQueryConditionDTO import com.tencent.devops.auth.pojo.enum.MemberType import com.tencent.devops.common.auth.api.pojo.BkAuthGroup +import com.tencent.devops.common.db.utils.skipCheck import com.tencent.devops.model.auth.tables.TAuthResourceAuthorization import com.tencent.devops.model.auth.tables.TAuthResourceGroupMember import com.tencent.devops.model.auth.tables.records.TAuthResourceGroupMemberRecord @@ -368,6 +369,7 @@ class AuthResourceGroupMemberDao { ) .orderBy(field(MEMBER_ID)) .offset(offset).limit(limit) + .skipCheck() .fetch().map { ResourceMemberInfo(id = it.value1(), name = it.value2(), type = it.value3()) } @@ -455,6 +457,7 @@ class AuthResourceGroupMemberDao { countDistinct(field(MEMBER_ID, Long::class.java)) ).from(resourceMemberUnionAuthorizationMember) .groupBy(field(MEMBER_TYPE, Long::class.java)) + .skipCheck() .fetch().map { Pair(it.value1(), it.value2()) }.toMap() } @@ -479,6 +482,7 @@ class AuthResourceGroupMemberDao { deptName = deptName ) ) + .skipCheck() .fetchOne(0, Long::class.java) ?: 0L } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverService.kt index 6b233a582d3..81011987d1b 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverService.kt @@ -64,13 +64,13 @@ class RbacPermissionHandoverService( ): String { return I18nUtil.getCodeLanMessage(messageCode = AuthI18nConstants.BK_APPLY_TO_HANDOVER).let { if (groupCount > 0) { - it.plus(I18nUtil.getCodeLanMessage(AuthI18nConstants.BK_HANDOVER_GROUPS, params = arrayOf(groupCount.toString()))).plus(",") + it.plus(I18nUtil.getCodeLanMessage(AuthI18nConstants.BK_HANDOVER_GROUPS, params = arrayOf(groupCount.toString()))) } else { it } }.let { if (authorizationCount > 0) { - it.plus( + it.plus(",").plus( I18nUtil.getCodeLanMessage(AuthI18nConstants.BK_HANDOVER_AUTHORIZATIONS, params = arrayOf(authorizationCount.toString())) ) } else { From 36ce9ead715b2cb65cb6451b1630b203fd03ee05 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Fri, 15 Nov 2024 11:01:25 +0800 Subject: [PATCH 09/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devops/auth/dao/AuthResourceGroupConfigDao.kt | 2 ++ .../kotlin/com/tencent/devops/auth/dao/StrategyDao.kt | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupConfigDao.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupConfigDao.kt index 73a0268d9c8..24e2d69f519 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupConfigDao.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupConfigDao.kt @@ -28,6 +28,7 @@ package com.tencent.devops.auth.dao +import com.tencent.devops.common.db.utils.skipCheck import com.tencent.devops.model.auth.tables.TAuthResourceGroupConfig import com.tencent.devops.model.auth.tables.records.TAuthResourceGroupConfigRecord import org.jooq.DSLContext @@ -110,6 +111,7 @@ class AuthResourceGroupConfigDao { dslContext.selectFrom(this) .orderBy(CREATE_TIME.desc(), RESOURCE_TYPE, GROUP_CODE) .limit(pageSize).offset((page - 1) * pageSize) + .skipCheck() .fetch() } } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/StrategyDao.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/StrategyDao.kt index 6f1303ef2cd..f3a715df452 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/StrategyDao.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/StrategyDao.kt @@ -28,6 +28,7 @@ package com.tencent.devops.auth.dao import com.tencent.devops.auth.entity.StrategyInfo +import com.tencent.devops.common.db.utils.skipCheck import com.tencent.devops.model.auth.tables.TAuthStrategy import com.tencent.devops.model.auth.tables.records.TAuthStrategyRecord import org.jooq.DSLContext @@ -39,7 +40,8 @@ class StrategyDao { fun create(dslContext: DSLContext, userId: String, strategyInfo: StrategyInfo): Int { with(TAuthStrategy.T_AUTH_STRATEGY) { - return dslContext.insertInto(this, + return dslContext.insertInto( + this, STRATEGY_NAME, STRATEGY_BODY, IS_DELETE, @@ -86,7 +88,11 @@ class StrategyDao { fun list(dslContext: DSLContext): Result? { with(TAuthStrategy.T_AUTH_STRATEGY) { - return dslContext.selectFrom(this).where((IS_DELETE.eq(0))).orderBy(CREATE_TIME.desc()).fetch() + return dslContext.selectFrom(this) + .where((IS_DELETE.eq(0))) + .orderBy(CREATE_TIME.desc()) + .skipCheck() + .fetch() } } From 9e6f7ae210f070d265d92a88b8746fc3092cfd5f Mon Sep 17 00:00:00 2001 From: greysonfang Date: Fri, 15 Nov 2024 11:20:26 +0800 Subject: [PATCH 10/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/tencent/devops/quality/dao/v2/QualityMetadataDao.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/dao/v2/QualityMetadataDao.kt b/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/dao/v2/QualityMetadataDao.kt index 878379d7290..a6b5950add2 100644 --- a/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/dao/v2/QualityMetadataDao.kt +++ b/src/backend/ci/core/quality/biz-quality/src/main/kotlin/com/tencent/devops/quality/dao/v2/QualityMetadataDao.kt @@ -28,6 +28,7 @@ package com.tencent.devops.quality.dao.v2 import com.tencent.devops.common.api.util.PageUtil +import com.tencent.devops.common.db.utils.skipCheck import com.tencent.devops.model.quality.tables.TQualityMetadata import com.tencent.devops.model.quality.tables.records.TQualityMetadataRecord import com.tencent.devops.quality.api.v2.pojo.op.QualityMetaData @@ -65,6 +66,7 @@ class QualityMetadataDao { return with(TQualityMetadata.T_QUALITY_METADATA) { dslContext.selectFrom(this) .where(ELEMENT_TYPE.eq(elementType)) + .skipCheck() .fetch() } } From 717dd2de01645644bbf44009d6778f448825a01c Mon Sep 17 00:00:00 2001 From: greysonfang Date: Fri, 15 Nov 2024 15:28:10 +0800 Subject: [PATCH 11/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/resources/user/UserAuthResourceGroupResourceImpl.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceGroupResourceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceGroupResourceImpl.kt index 543d63df886..c9c253c4ec1 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceGroupResourceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceGroupResourceImpl.kt @@ -103,6 +103,7 @@ class UserAuthResourceGroupResourceImpl @Autowired constructor( maxExpiredAt = maxExpiredAt, relatedResourceType = relatedResourceType, relatedResourceCode = relatedResourceCode, + operateChannel = operateChannel, action = action, start = start, limit = limit From ba1deadf13392188374e6ae344ebd6bc19682925 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Fri, 15 Nov 2024 15:58:18 +0800 Subject: [PATCH 12/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RbacPermissionManageFacadeServiceImpl.kt | 40 ++++++++++++++----- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt index 77a032b86d7..5769aa9e71a 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt @@ -160,7 +160,8 @@ class RbacPermissionManageFacadeServiceImpl( private fun getGroupMemberDetailMap( memberId: String, - resourceGroupMembers: List + resourceGroupMembers: List, + operateChannel: OperateChannel? ): Map { // 如果用户离职,查询权限中心接口会报错 if (deptService.isUserDeparted(memberId)) { @@ -181,17 +182,34 @@ class RbacPermissionManageFacadeServiceImpl( groupMemberDetailMap["${it.id}_$memberId"] = it } } - // 直接加入的组织 - val deptGroupIds = resourceGroupMembers + val deptGroups = resourceGroupMembers .filter { it.memberType == MemberType.DEPARTMENT.type } - .map { it.iamGroupId } - if (deptGroupIds.isNotEmpty()) { - iamV2ManagerService.listMemberGroupsDetails( - MemberType.DEPARTMENT.type, - memberId, - deptGroupIds.joinToString(",") - ).forEach { - groupMemberDetailMap["${it.id}_$memberId"] = it + when { + deptGroups.isEmpty() -> {} + operateChannel == OperateChannel.PERSONAL -> { + // 个人视角,会获取用户通过组织间接加入的组 + deptGroups.groupBy({ it.memberId }, { it.iamGroupId.toString() }) + .forEach { (deptId, iamGroupIds) -> + if (iamGroupIds.isEmpty()) return@forEach + iamV2ManagerService.listMemberGroupsDetails( + MemberType.DEPARTMENT.type, + deptId, + iamGroupIds.joinToString(",") + ).forEach { + groupMemberDetailMap["${it.id}_$deptId"] = it + } + } + } + else -> { + // 管理员视角,获取组织直接加入的用户组 + val deptGroupIds = deptGroups.map { it.iamGroupId } + iamV2ManagerService.listMemberGroupsDetails( + MemberType.DEPARTMENT.type, + memberId, + deptGroupIds.joinToString(",") + ).forEach { + groupMemberDetailMap["${it.id}_$memberId"] = it + } } } // 人员模板加入的组 From 237ffb6c9515c940efb05f9ad6686b96f3e079e2 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Fri, 15 Nov 2024 15:59:54 +0800 Subject: [PATCH 13/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rbac/service/RbacPermissionManageFacadeServiceImpl.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt index 5769aa9e71a..a94d06cc606 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt @@ -140,7 +140,8 @@ class RbacPermissionManageFacadeServiceImpl( // 用户组成员详情 val groupMemberDetailMap = getGroupMemberDetailMap( memberId = memberId, - resourceGroupMembers = resourceGroupMembers + resourceGroupMembers = resourceGroupMembers, + operateChannel = operateChannel ) val records = mutableListOf() resourceGroupMembers.forEach { @@ -200,6 +201,7 @@ class RbacPermissionManageFacadeServiceImpl( } } } + else -> { // 管理员视角,获取组织直接加入的用户组 val deptGroupIds = deptGroups.map { it.iamGroupId } From f9eba02f673b88df2cbb2476b9ab03176e7aea06 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Fri, 15 Nov 2024 16:28:06 +0800 Subject: [PATCH 14/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pojo/enum/RemoveMemberButtonControl.kt | 3 +++ .../RbacPermissionManageFacadeServiceImpl.kt | 18 +++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/RemoveMemberButtonControl.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/RemoveMemberButtonControl.kt index fc06012edd1..55064743eb0 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/RemoveMemberButtonControl.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/RemoveMemberButtonControl.kt @@ -37,6 +37,9 @@ enum class RemoveMemberButtonControl { // 通过模板加入,不允许移出组 TEMPLATE, + // 用户通过组织 间接加入,不允许移出组 + DEPARTMENT, + // 其他,允许移出组 OTHER } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt index a94d06cc606..33966d3d72c 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt @@ -152,7 +152,8 @@ class RbacPermissionManageFacadeServiceImpl( resourceGroup = resourceGroup, groupMemberDetail = groupMemberDetail, uniqueManagerGroups = uniqueManagerGroups, - authResourceGroupMember = it + authResourceGroupMember = it, + operateChannel = operateChannel ) ) } @@ -234,7 +235,8 @@ class RbacPermissionManageFacadeServiceImpl( resourceGroup: TAuthResourceGroupRecord, groupMemberDetail: MemberGroupDetailsResponse?, uniqueManagerGroups: List, - authResourceGroupMember: AuthResourceGroupMember + authResourceGroupMember: AuthResourceGroupMember, + operateChannel: OperateChannel? ): GroupDetailsInfoVo { // 如果用户离职,查询权限中心接口会报错,因此从数据库直接取数据,而不去调用权限中心接口。 val (expiredAt, joinedTime) = if (groupMemberDetail != null) { @@ -275,6 +277,10 @@ class RbacPermissionManageFacadeServiceImpl( authResourceGroupMember.memberType == MemberType.TEMPLATE.type -> RemoveMemberButtonControl.TEMPLATE + operateChannel == OperateChannel.PERSONAL && + authResourceGroupMember.memberType == MemberType.DEPARTMENT.type -> + RemoveMemberButtonControl.DEPARTMENT + resourceGroup.resourceType == AuthResourceType.PROJECT.value && uniqueManagerGroups.contains(authResourceGroupMember.iamGroupId) -> RemoveMemberButtonControl.UNIQUE_MANAGER @@ -285,9 +291,11 @@ class RbacPermissionManageFacadeServiceImpl( else -> RemoveMemberButtonControl.OTHER }, - joinedType = when (authResourceGroupMember.memberType) { - MemberType.TEMPLATE.type -> JoinedType.TEMPLATE - MemberType.DEPARTMENT.type -> JoinedType.DEPARTMENT + joinedType = when { + authResourceGroupMember.memberType == MemberType.TEMPLATE.type -> JoinedType.TEMPLATE + authResourceGroupMember.memberType == MemberType.DEPARTMENT.type && + operateChannel == OperateChannel.PERSONAL -> JoinedType.DEPARTMENT + else -> JoinedType.DIRECT }, operator = "" From 8b964817aff81e72129c3bdf1bbd39ec30cd3beb Mon Sep 17 00:00:00 2001 From: greysonfang Date: Fri, 15 Nov 2024 17:56:04 +0800 Subject: [PATCH 15/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/RbacPermissionManageFacadeServiceImpl.kt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt index 33966d3d72c..25447a03fa0 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt @@ -852,10 +852,12 @@ class RbacPermissionManageFacadeServiceImpl( condition = ResourceAuthorizationHandoverConditionRequest( projectCode = projectCode, resourceType = ResourceTypeId.PIPELINE, + fullSelection = true, filterResourceCodes = invalidPipelines, handoverChannel = HandoverChannelCode.MANAGER, handoverFrom = handoverMemberDTO.targetMember.id, - handoverTo = handoverMemberDTO.handoverTo.id + handoverTo = handoverMemberDTO.handoverTo.id, + checkPermission = false ) ) } @@ -999,9 +1001,11 @@ class RbacPermissionManageFacadeServiceImpl( projectCode = projectCode, resourceType = ResourceTypeId.PIPELINE, filterResourceCodes = invalidPipelines, + fullSelection = true, handoverChannel = HandoverChannelCode.MANAGER, handoverFrom = removeMemberDTO.targetMember.id, - handoverTo = removeMemberDTO.handoverTo!!.id + handoverTo = removeMemberDTO.handoverTo!!.id, + checkPermission = false ) ) } @@ -1533,9 +1537,11 @@ class RbacPermissionManageFacadeServiceImpl( projectCode = overview.projectCode, resourceType = resourceType, filterResourceCodes = authorizations.map { it.itemId }, + fullSelection = true, handoverChannel = HandoverChannelCode.MANAGER, handoverFrom = overview.applicant, - handoverTo = overview.approver + handoverTo = overview.approver, + checkPermission = false ) ) } From 60929d01e185b2c4b24e673bbb540588bc288be3 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Mon, 18 Nov 2024 20:04:46 +0800 Subject: [PATCH 16/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/api/user/UserAuthHandoverResource.kt | 2 +- .../pojo/request/HandoverOverviewQueryReq.kt | 8 ++--- .../auth/dao/AuthHandoverOverviewDao.kt | 9 ++++-- .../service/RbacPermissionHandoverService.kt | 29 +++++++++++-------- 4 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthHandoverResource.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthHandoverResource.kt index 7624c00df3c..96a5775077f 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthHandoverResource.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthHandoverResource.kt @@ -56,7 +56,7 @@ interface UserAuthHandoverResource { @GET @Path("/{flowNo}/getResourceType2CountOfHandover") - @Operation(summary = "获取资源授权管理") + @Operation(summary = "获取资源授权管理数量") fun getResourceType2CountOfHandover( @Parameter(description = "用户名", required = true) @HeaderParam(AUTH_HEADER_USER_ID) diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverOverviewQueryReq.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverOverviewQueryReq.kt index b31bf6bcb47..01efd77de22 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverOverviewQueryReq.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverOverviewQueryReq.kt @@ -26,8 +26,8 @@ data class HandoverOverviewQueryReq( val maxCreatedTime: Long? = null, @get:Schema(title = "交接类型") val handoverType: HandoverType? = null, - @get:Schema(title = "限制") - val limit: Int? = null, - @get:Schema(title = "起始值") - val offset: Int? = null + @get:Schema(title = "页数") + val page: Int? = null, + @get:Schema(title = "页大小") + val pageSize: Int? = null ) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthHandoverOverviewDao.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthHandoverOverviewDao.kt index c32effc9cb1..4f2ca7b1825 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthHandoverOverviewDao.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthHandoverOverviewDao.kt @@ -6,6 +6,7 @@ import com.tencent.devops.auth.pojo.request.HandoverOverviewQueryReq import com.tencent.devops.auth.pojo.request.HandoverOverviewUpdateReq import com.tencent.devops.auth.pojo.vo.HandoverOverviewVo import com.tencent.devops.common.api.util.DateTimeUtil +import com.tencent.devops.common.api.util.PageUtil import com.tencent.devops.model.auth.tables.TAuthHandoverOverview import com.tencent.devops.model.auth.tables.records.TAuthHandoverOverviewRecord import org.jooq.Condition @@ -80,10 +81,12 @@ class AuthHandoverOverviewDao { dslContext.selectFrom(this) .where(buildQueryConditions(queryRequest)) .let { - if (queryRequest.limit != null && queryRequest.offset != null) - it.limit(queryRequest.limit).offset(queryRequest.offset) - else + if (queryRequest.page != null && queryRequest.pageSize != null) { + val sqlLimit = PageUtil.convertPageSizeToSQLLimit(queryRequest.page, queryRequest.pageSize) + it.limit(sqlLimit.limit).offset(sqlLimit.offset) + } else { it + } }.fetch().map { it.convert(queryRequest.memberID) } } } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverService.kt index 81011987d1b..7c8618092a6 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverService.kt @@ -63,18 +63,23 @@ class RbacPermissionHandoverService( authorizationCount: Int ): String { return I18nUtil.getCodeLanMessage(messageCode = AuthI18nConstants.BK_APPLY_TO_HANDOVER).let { - if (groupCount > 0) { - it.plus(I18nUtil.getCodeLanMessage(AuthI18nConstants.BK_HANDOVER_GROUPS, params = arrayOf(groupCount.toString()))) - } else { - it - } - }.let { - if (authorizationCount > 0) { - it.plus(",").plus( - I18nUtil.getCodeLanMessage(AuthI18nConstants.BK_HANDOVER_AUTHORIZATIONS, params = arrayOf(authorizationCount.toString())) - ) - } else { - it + when { + groupCount > 0 && authorizationCount > 0 -> { + it.plus(I18nUtil.getCodeLanMessage(AuthI18nConstants.BK_HANDOVER_GROUPS, params = arrayOf(groupCount.toString()))).plus(",") + it.plus( + I18nUtil.getCodeLanMessage(AuthI18nConstants.BK_HANDOVER_AUTHORIZATIONS, params = arrayOf(authorizationCount.toString())) + ) + } + + groupCount > 0 -> { + it.plus(I18nUtil.getCodeLanMessage(AuthI18nConstants.BK_HANDOVER_GROUPS, params = arrayOf(groupCount.toString()))) + } + + else -> { + it.plus( + I18nUtil.getCodeLanMessage(AuthI18nConstants.BK_HANDOVER_AUTHORIZATIONS, params = arrayOf(authorizationCount.toString())) + ) + } } } } From a37597aced4ee297e2630833ef9e327fc937fb89 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Mon, 18 Nov 2024 20:52:03 +0800 Subject: [PATCH 17/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RbacPermissionResourceValidateService.kt | 8 ++++++- ...SamplePermissionResourceValidateService.kt | 3 ++- .../user/UserAuthHandoverResourceImpl.kt | 24 ++++++++++++++++++- .../user/UserAuthResourceGroupResourceImpl.kt | 9 ++++++- .../UserAuthResourceMemberResourceImpl.kt | 22 +++++++++++++++-- .../iam/PermissionResourceValidateService.kt | 3 ++- 6 files changed, 62 insertions(+), 7 deletions(-) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceValidateService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceValidateService.kt index beaaf8312d2..c7176f50d89 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceValidateService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceValidateService.kt @@ -156,7 +156,8 @@ class RbacPermissionResourceValidateService( override fun validateUserProjectPermissionByChannel( userId: String, projectCode: String, - operateChannel: OperateChannel + operateChannel: OperateChannel, + targetMemberId: String ) { if (operateChannel == OperateChannel.PERSONAL) { // 个人视角校验 @@ -171,6 +172,11 @@ class RbacPermissionResourceValidateService( message = "The user does not have permission to visit the project!" ) } + if (userId != targetMemberId){ + throw PermissionForbiddenException( + message = "You do not have permission to operate other user groups!" + ) + } } else { // 管理员视角校验 val hasProjectManagePermission = permissionService.validateUserResourcePermission( diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionResourceValidateService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionResourceValidateService.kt index 6ff90235c55..d8b5f1f1e07 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionResourceValidateService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionResourceValidateService.kt @@ -51,7 +51,8 @@ class SamplePermissionResourceValidateService : PermissionResourceValidateServic override fun validateUserProjectPermissionByChannel( userId: String, projectCode: String, - operateChannel: OperateChannel + operateChannel: OperateChannel, + targetMemberId: String ) { return } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthHandoverResourceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthHandoverResourceImpl.kt index 5a1f1a093b9..68be9dd6b97 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthHandoverResourceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthHandoverResourceImpl.kt @@ -1,6 +1,7 @@ package com.tencent.devops.auth.resources.user import com.tencent.devops.auth.api.user.UserAuthHandoverResource +import com.tencent.devops.auth.pojo.enum.OperateChannel import com.tencent.devops.auth.pojo.request.HandoverDetailsQueryReq import com.tencent.devops.auth.pojo.request.HandoverOverviewQueryReq import com.tencent.devops.auth.pojo.request.HandoverOverviewUpdateReq @@ -11,6 +12,8 @@ import com.tencent.devops.auth.pojo.vo.ResourceType2CountVo import com.tencent.devops.auth.service.PermissionAuthorizationService import com.tencent.devops.auth.service.iam.PermissionHandoverService import com.tencent.devops.auth.service.iam.PermissionManageFacadeService +import com.tencent.devops.auth.service.iam.PermissionResourceValidateService +import com.tencent.devops.common.api.exception.PermissionForbiddenException import com.tencent.devops.common.api.model.SQLPage import com.tencent.devops.common.api.pojo.Result import com.tencent.devops.common.auth.api.pojo.ResourceAuthorizationHandoverConditionRequest @@ -20,13 +23,20 @@ import com.tencent.devops.common.web.RestResource class UserAuthHandoverResourceImpl( private val permissionAuthorizationService: PermissionAuthorizationService, private val permissionManageFacadeService: PermissionManageFacadeService, - private val permissionHandoverService: PermissionHandoverService + private val permissionHandoverService: PermissionHandoverService, + private val permissionResourceValidateService: PermissionResourceValidateService ) : UserAuthHandoverResource { override fun handoverAuthorizationsApplication( userId: String, projectId: String, condition: ResourceAuthorizationHandoverConditionRequest ): Result { + permissionResourceValidateService.validateUserProjectPermissionByChannel( + userId = userId, + projectCode = projectId, + operateChannel = OperateChannel.PERSONAL, + targetMemberId = condition.handoverFrom!! + ) return Result( permissionAuthorizationService.handoverAuthorizationsApplication( operator = userId, @@ -40,6 +50,12 @@ class UserAuthHandoverResourceImpl( userId: String, queryRequest: HandoverOverviewQueryReq ): Result> { + if (userId != queryRequest.memberID) { + throw PermissionForbiddenException( + message = "You have not permission to view other people's handover details!" + ) + } + return Result(permissionHandoverService.listHandoverOverviews(queryRequest = queryRequest)) } @@ -65,6 +81,12 @@ class UserAuthHandoverResourceImpl( } override fun handleHanoverApplication(userId: String, request: HandoverOverviewUpdateReq): Result { + permissionResourceValidateService.validateUserProjectPermissionByChannel( + userId = userId, + projectCode = request.projectCode, + operateChannel = OperateChannel.PERSONAL, + targetMemberId = request.operator + ) return Result(permissionManageFacadeService.handleHanoverApplication(request = request)) } } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceGroupResourceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceGroupResourceImpl.kt index c9c253c4ec1..db182a05f1e 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceGroupResourceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceGroupResourceImpl.kt @@ -90,7 +90,8 @@ class UserAuthResourceGroupResourceImpl @Autowired constructor( permissionResourceValidateService.validateUserProjectPermissionByChannel( userId = userId, projectCode = projectId, - operateChannel = operateChannel ?: OperateChannel.MANAGER + operateChannel = operateChannel ?: OperateChannel.MANAGER, + targetMemberId = memberId ) return Result( @@ -118,6 +119,12 @@ class UserAuthResourceGroupResourceImpl @Autowired constructor( groupId: Int, memberRenewalDTO: GroupMemberRenewalDTO ): Result { + permissionResourceValidateService.validateUserProjectPermissionByChannel( + userId = userId, + projectCode = projectId, + operateChannel = OperateChannel.PERSONAL, + targetMemberId = userId + ) return Result( permissionResourceMemberService.renewalGroupMember( userId = userId, diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceMemberResourceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceMemberResourceImpl.kt index 93b6f654996..cc7e3135bcc 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceMemberResourceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthResourceMemberResourceImpl.kt @@ -134,6 +134,12 @@ class UserAuthResourceMemberResourceImpl( projectId: String, removeMemberDTO: GroupMemberRemoveConditionReq ): Result { + permissionResourceValidateService.validateUserProjectPermissionByChannel( + userId = userId, + projectCode = projectId, + operateChannel = OperateChannel.PERSONAL, + targetMemberId = removeMemberDTO.targetMember.id + ) return Result( permissionManageFacadeService.batchDeleteResourceGroupMembersFromPersonal( userId = userId, @@ -163,6 +169,12 @@ class UserAuthResourceMemberResourceImpl( projectId: String, handoverMemberDTO: GroupMemberHandoverConditionReq ): Result { + permissionResourceValidateService.validateUserProjectPermissionByChannel( + userId = userId, + projectCode = projectId, + operateChannel = OperateChannel.PERSONAL, + targetMemberId = handoverMemberDTO.targetMember.id + ) return Result( permissionManageFacadeService.batchHandoverApplicationFromPersonal( userId = userId, @@ -172,13 +184,18 @@ class UserAuthResourceMemberResourceImpl( ) } - @BkManagerCheck override fun batchOperateGroupMembersCheck( userId: String, projectId: String, batchOperateType: BatchOperateType, conditionReq: GroupMemberCommonConditionReq ): Result { + permissionResourceValidateService.validateUserProjectPermissionByChannel( + userId = userId, + projectCode = projectId, + operateChannel = conditionReq.operateChannel, + targetMemberId = conditionReq.targetMember.id + ) return Result( permissionManageFacadeService.batchOperateGroupMembersCheck( userId = userId, @@ -234,7 +251,8 @@ class UserAuthResourceMemberResourceImpl( permissionResourceValidateService.validateUserProjectPermissionByChannel( userId = userId, projectCode = projectId, - operateChannel = operateChannel ?: OperateChannel.MANAGER + operateChannel = operateChannel ?: OperateChannel.MANAGER, + targetMemberId = memberId ) return Result( permissionManageFacadeService.getMemberGroupsCount( diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionResourceValidateService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionResourceValidateService.kt index 2f0478edd23..c9c9e261ce9 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionResourceValidateService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionResourceValidateService.kt @@ -54,6 +54,7 @@ interface PermissionResourceValidateService { fun validateUserProjectPermissionByChannel( userId: String, projectCode: String, - operateChannel: OperateChannel + operateChannel: OperateChannel, + targetMemberId: String ) } From a2b38b0c58a783d26c031dc4caa3495c04919029 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Wed, 20 Nov 2024 11:25:26 +0800 Subject: [PATCH 18/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RbacPermissionResourceGroupSyncService.kt | 106 +++++++++--------- 1 file changed, 52 insertions(+), 54 deletions(-) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupSyncService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupSyncService.kt index 6fbb4d634f3..928feb6f236 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupSyncService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupSyncService.kt @@ -62,6 +62,7 @@ import org.slf4j.LoggerFactory import org.slf4j.MDC import org.springframework.beans.factory.annotation.Autowired import java.time.LocalDateTime +import java.util.concurrent.Callable import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletionException import java.util.concurrent.Executors @@ -120,8 +121,8 @@ class RbacPermissionResourceGroupSyncService @Autowired constructor( limit = limit, offset = offset ).data?.map { it.englishName } ?: break - projectCodes.forEach { projectCode -> - syncMemberExpiredExecutorService.submit { + val futures = projectCodes.map { projectCode -> + syncMemberExpiredExecutorService.submit(Callable { logger.info("start to sync project group member expired time|$projectCode") val projectMembersOfExpired = authResourceGroupMemberDao.listResourceGroupMember( dslContext = dslContext, @@ -144,8 +145,9 @@ class RbacPermissionResourceGroupSyncService @Autowired constructor( } } } - } + }) } + futures.forEach { it.get() } offset += limit } while (projectCodes.size == limit) } @@ -219,62 +221,58 @@ class RbacPermissionResourceGroupSyncService @Autowired constructor( } override fun syncIamGroupMembersOfApply() { - val traceId = MDC.get(TraceTag.BIZID) - syncExecutorService.submit { - MDC.put(TraceTag.BIZID, traceId) - val limit = 100 - var offset = 0 - val startEpoch = System.currentTimeMillis() - val finalRecordsOfPending = mutableListOf() - val finalRecordsOfSuccess = mutableListOf() - do { - logger.info("sync members of apply | start") - // 获取7天内未审批单据 - val records = authResourceGroupApplyDao.list( - dslContext = dslContext, - day = 7, - limit = limit, - offset = offset - ) - val (recordsOfSuccess, recordsOfPending) = records.partition { - try { - val isMemberJoinedToGroup = iamV2ManagerService.verifyGroupValidMember( - it.memberId, - it.iamGroupId.toString() - )[it.iamGroupId]?.belong == true - isMemberJoinedToGroup - } catch (ignore: Exception) { - logger.warn("verify group valid member failed,${it.memberId}|${it.iamGroupId}", ignore) - authResourceGroupApplyDao.delete(dslContext, it.id) - false - } + val limit = 100 + var offset = 0 + val startEpoch = System.currentTimeMillis() + val finalRecordsOfPending = mutableListOf() + val finalRecordsOfSuccess = mutableListOf() + do { + logger.info("sync members of apply | start") + // 获取7天内未审批单据 + val records = authResourceGroupApplyDao.list( + dslContext = dslContext, + day = 7, + limit = limit, + offset = offset + ) + val (recordsOfSuccess, recordsOfPending) = records.partition { + try { + val isMemberJoinedToGroup = iamV2ManagerService.verifyGroupValidMember( + it.memberId, + it.iamGroupId.toString() + )[it.iamGroupId]?.belong == true + isMemberJoinedToGroup + } catch (ignore: Exception) { + logger.warn("verify group valid member failed,${it.memberId}|${it.iamGroupId}", ignore) + authResourceGroupApplyDao.delete(dslContext, it.id) + false } - finalRecordsOfPending.addAll(recordsOfPending) - finalRecordsOfSuccess.addAll(recordsOfSuccess) - offset += limit - } while (records.size == limit) - if (finalRecordsOfPending.isNotEmpty()) { - authResourceGroupApplyDao.batchUpdate( - dslContext = dslContext, - ids = finalRecordsOfPending.map { it.id }, - applyToGroupStatus = ApplyToGroupStatus.PENDING - ) } - if (finalRecordsOfSuccess.isNotEmpty()) { - finalRecordsOfSuccess.forEach { - syncIamGroupMember( - projectCode = it.projectCode, - iamGroupId = it.iamGroupId - ) - } - authResourceGroupApplyDao.batchUpdate( - dslContext = dslContext, - ids = finalRecordsOfSuccess.map { it.id }, - applyToGroupStatus = ApplyToGroupStatus.SUCCEED + finalRecordsOfPending.addAll(recordsOfPending) + finalRecordsOfSuccess.addAll(recordsOfSuccess) + offset += limit + } while (records.size == limit) + if (finalRecordsOfPending.isNotEmpty()) { + authResourceGroupApplyDao.batchUpdate( + dslContext = dslContext, + ids = finalRecordsOfPending.map { it.id }, + applyToGroupStatus = ApplyToGroupStatus.PENDING + ) + } + if (finalRecordsOfSuccess.isNotEmpty()) { + finalRecordsOfSuccess.forEach { + syncIamGroupMember( + projectCode = it.projectCode, + iamGroupId = it.iamGroupId ) } - logger.info("It take(${System.currentTimeMillis() - startEpoch})ms to sync members of apply") + authResourceGroupApplyDao.batchUpdate( + dslContext = dslContext, + ids = finalRecordsOfSuccess.map { it.id }, + applyToGroupStatus = ApplyToGroupStatus.SUCCEED + ) } + logger.info("It take(${System.currentTimeMillis() - startEpoch})ms to sync members of apply") } override fun syncGroupAndMember(projectCode: String) { From 994dcb8246a9b5c110dd420b3dbdc5c8fa6ee2fc Mon Sep 17 00:00:00 2001 From: greysonfang Date: Tue, 26 Nov 2024 16:14:39 +0800 Subject: [PATCH 19/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/service/ServiceProjectAuthResource.kt | 10 + .../auth/api/user/UserAuthHandoverResource.kt | 11 +- .../devops/auth/constant/AuthMessageCode.kt | 1 - .../auth/pojo/enum/HandoverQueryChannel.kt | 34 ++ .../pojo/request/HandoverDetailsQueryReq.kt | 34 +- .../pojo/request/HandoverOverviewUpdateReq.kt | 2 +- .../ResourceType2CountOfHandoverQuery.kt | 33 ++ .../devops/auth/dao/AuthAuthorizationDao.kt | 13 + .../devops/auth/dao/AuthResourceGroupDao.kt | 17 + .../rbac/config/RbacAuthConfiguration.kt | 16 +- ...acPermissionHandoverApplicationService.kt} | 34 +- .../RbacPermissionManageFacadeServiceImpl.kt | 451 ++++++++++++------ .../RbacPermissionResourceGroupSyncService.kt | 2 + .../RbacPermissionResourceValidateService.kt | 2 +- .../sample/config/MockAuthConfiguration.kt | 8 +- ...lePermissionHandoverApplicationService.kt} | 10 +- .../SamplePermissionManageFacadeService.kt | 16 + .../service/ServiceProjectAuthResourceImpl.kt | 12 +- .../user/UserAuthHandoverResourceImpl.kt | 15 +- .../service/PermissionAuthorizationService.kt | 7 + .../PermissionAuthorizationServiceImpl.kt | 14 +- ...> PermissionHandoverApplicationService.kt} | 10 +- .../iam/PermissionManageFacadeService.kt | 28 ++ .../pojo/BKRepoProjectUpdateRequest.kt | 2 +- .../common/archive/pojo/ProjectMetadata.kt | 2 +- .../project/api/user/UserProjectResource.kt | 5 +- .../resources/UserProjectResourceImpl.kt | 6 +- .../devops/project/service/ProjectService.kt | 4 +- .../service/impl/AbsProjectServiceImpl.kt | 19 +- .../tencent/devops/store/atom/dao/AtomDao.kt | 2 +- .../2030_ci_auth-update_v3.0_mysql.sql | 8 + 31 files changed, 606 insertions(+), 222 deletions(-) create mode 100644 src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/HandoverQueryChannel.kt create mode 100644 src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/ResourceType2CountOfHandoverQuery.kt rename src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/{RbacPermissionHandoverService.kt => RbacPermissionHandoverApplicationService.kt} (91%) rename src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/{SamplePermissionHandoverService.kt => SamplePermissionHandoverApplicationService.kt} (80%) rename src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/{PermissionHandoverService.kt => PermissionHandoverApplicationService.kt} (83%) diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/service/ServiceProjectAuthResource.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/service/ServiceProjectAuthResource.kt index 31fc7fdb84c..9fceb3a64d9 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/service/ServiceProjectAuthResource.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/service/ServiceProjectAuthResource.kt @@ -29,6 +29,7 @@ package com.tencent.devops.auth.api.service import com.tencent.devops.auth.pojo.vo.ProjectPermissionInfoVO import com.tencent.devops.common.api.auth.AUTH_HEADER_DEVOPS_BK_TOKEN +import com.tencent.devops.common.api.auth.AUTH_HEADER_DEVOPS_USER_ID import com.tencent.devops.common.api.auth.AUTH_HEADER_GIT_TYPE import com.tencent.devops.common.api.auth.AUTH_HEADER_USER_ID import com.tencent.devops.common.api.pojo.Result @@ -247,4 +248,13 @@ interface ServiceProjectAuthResource { @Parameter(description = "项目Code", required = true) projectCode: String ): Result + + @GET + @Path("/listUserProjects") + @Operation(summary = "获取用户授权相关的项目") + fun listUserProjects( + @HeaderParam(AUTH_HEADER_DEVOPS_USER_ID) + @Parameter(description = "用户ID", required = true) + userId: String + ): Result> } diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthHandoverResource.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthHandoverResource.kt index 96a5775077f..e330bc8e175 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthHandoverResource.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthHandoverResource.kt @@ -3,6 +3,7 @@ package com.tencent.devops.auth.api.user import com.tencent.devops.auth.pojo.request.HandoverDetailsQueryReq import com.tencent.devops.auth.pojo.request.HandoverOverviewQueryReq import com.tencent.devops.auth.pojo.request.HandoverOverviewUpdateReq +import com.tencent.devops.auth.pojo.request.ResourceType2CountOfHandoverQuery import com.tencent.devops.auth.pojo.vo.HandoverAuthorizationDetailVo import com.tencent.devops.auth.pojo.vo.HandoverGroupDetailVo import com.tencent.devops.auth.pojo.vo.HandoverOverviewVo @@ -16,7 +17,6 @@ import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter import io.swagger.v3.oas.annotations.tags.Tag import javax.ws.rs.Consumes -import javax.ws.rs.GET import javax.ws.rs.HeaderParam import javax.ws.rs.POST import javax.ws.rs.Path @@ -54,16 +54,15 @@ interface UserAuthHandoverResource { queryRequest: HandoverOverviewQueryReq ): Result> - @GET - @Path("/{flowNo}/getResourceType2CountOfHandover") + @POST + @Path("/getResourceType2CountOfHandover") @Operation(summary = "获取资源授权管理数量") fun getResourceType2CountOfHandover( @Parameter(description = "用户名", required = true) @HeaderParam(AUTH_HEADER_USER_ID) userId: String, - @Parameter(description = "流程号", required = true) - @PathParam("flowNo") - flowNo: String + @Parameter(description = "查询请求体", required = true) + queryReq: ResourceType2CountOfHandoverQuery ): Result> @POST diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/constant/AuthMessageCode.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/constant/AuthMessageCode.kt index 8c3d6adb049..6d83a6ebe1c 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/constant/AuthMessageCode.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/constant/AuthMessageCode.kt @@ -149,5 +149,4 @@ object AuthMessageCode { const val ERROR_HANDOVER_APPROVAL = "2121094" // 由于您不是该交接申请单的审批人,无法进行任何操作 const val ERROR_HANDOVER_HANDLE = "2121095" // 该交接申请单正在被处理中,请耐心等待 const val ERROR_HANDOVER_AUTHORIZATION = "2121096" // 交接操作不合法,用户没有对应授权的权限 - } diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/HandoverQueryChannel.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/HandoverQueryChannel.kt new file mode 100644 index 00000000000..352a6c6bbe9 --- /dev/null +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/enum/HandoverQueryChannel.kt @@ -0,0 +1,34 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. + * + * A copy of the MIT License is included in this file. + * + * + * Terms of the MIT License: + * --------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.tencent.devops.auth.pojo.enum + +enum class HandoverQueryChannel { + PREVIEW, + + HANDOVER_APPLICATION +} diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverDetailsQueryReq.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverDetailsQueryReq.kt index 1cd3cbb7d3b..9a8bb88206d 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverDetailsQueryReq.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverDetailsQueryReq.kt @@ -1,18 +1,40 @@ package com.tencent.devops.auth.pojo.request -import com.tencent.devops.auth.pojo.enum.HandoverType +import com.tencent.devops.auth.pojo.enum.HandoverQueryChannel import io.swagger.v3.oas.annotations.media.Schema @Schema(title = "权限交接详细查询请求体") data class HandoverDetailsQueryReq( - @get:Schema(title = "流程单号") - val flowNo: String, @get:Schema(title = "组/授权资源关联的资源类型") val resourceType: String, - @get:Schema(title = "交接类型") - val handoverType: HandoverType, + @get:Schema(title = "流程单号") + val flowNo: String?, + @get:Schema(title = "项目ID") + val projectCode: String?, + @get:Schema(title = "操作的组ID") + val iamGroupIds: List?, + @get:Schema(title = "用户ID") + val memberId: String?, + @get:Schema(title = "渠道") + val queryChannel: HandoverQueryChannel, @get:Schema(title = "第几页") val page: Int, @get:Schema(title = "每页大小") val pageSize: Int -) +) { + fun check() { + when (queryChannel) { + HandoverQueryChannel.HANDOVER_APPLICATION -> { + if (flowNo == null) { + throw IllegalArgumentException("flowNo cannot be null!") + } + } + + else -> { + if (projectCode == null || iamGroupIds == null || memberId == null) { + throw IllegalArgumentException("projectCode or iamGroupIds or memberId cannot be null!") + } + } + } + } +} diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverOverviewUpdateReq.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverOverviewUpdateReq.kt index c5a41e594f2..cd0c27b2b21 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverOverviewUpdateReq.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverOverviewUpdateReq.kt @@ -7,7 +7,7 @@ import io.swagger.v3.oas.annotations.media.Schema data class HandoverOverviewUpdateReq( @get:Schema(title = "项目ID") val projectCode: String, - @get:Schema(title = "项目ID") + @get:Schema(title = "流程单号") val flowNo: String, @get:Schema(title = "操作人") val operator: String, diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/ResourceType2CountOfHandoverQuery.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/ResourceType2CountOfHandoverQuery.kt new file mode 100644 index 00000000000..734ba51b15a --- /dev/null +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/ResourceType2CountOfHandoverQuery.kt @@ -0,0 +1,33 @@ +package com.tencent.devops.auth.pojo.request + +import com.tencent.devops.auth.pojo.enum.HandoverQueryChannel +import io.swagger.v3.oas.annotations.media.Schema + +data class ResourceType2CountOfHandoverQuery( + @get:Schema(title = "渠道") + val queryChannel: HandoverQueryChannel, + @get:Schema(title = "流程单号") + val flowNo: String?, + @get:Schema(title = "项目ID") + val projectCode: String?, + @get:Schema(title = "操作的组ID") + val iamGroupIds: List?, + @get:Schema(title = "用户ID") + val memberId: String? +) { + fun check() { + when (queryChannel) { + HandoverQueryChannel.HANDOVER_APPLICATION -> { + if (flowNo == null) { + throw IllegalArgumentException("flowNo cannot be null!") + } + } + + else -> { + if (projectCode == null || iamGroupIds == null || memberId == null) { + throw IllegalArgumentException("projectCode or iamGroupIds or memberId cannot be null!") + } + } + } + } +} diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthAuthorizationDao.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthAuthorizationDao.kt index d973d4ffe59..f633eaf0f19 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthAuthorizationDao.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthAuthorizationDao.kt @@ -208,6 +208,19 @@ class AuthAuthorizationDao { return conditions } + fun listUserProjects( + dslContext: DSLContext, + userId: String + ): List { + return with(TAuthResourceAuthorization.T_AUTH_RESOURCE_AUTHORIZATION) { + dslContext.select(PROJECT_CODE) + .from(this) + .where(HANDOVER_FROM.eq(userId)) + .groupBy(PROJECT_CODE) + .fetch().map { it.value1() } + } + } + fun TAuthResourceAuthorizationRecord.convert(): ResourceAuthorizationResponse { return ResourceAuthorizationResponse( id = id, diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupDao.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupDao.kt index 263af0b1d00..f4a0c58ccbc 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupDao.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthResourceGroupDao.kt @@ -30,6 +30,7 @@ package com.tencent.devops.auth.dao import com.tencent.devops.auth.pojo.AuthResourceGroup import com.tencent.devops.common.auth.api.AuthResourceType +import org.jooq.impl.DSL.count import com.tencent.devops.model.auth.tables.TAuthResourceGroup import com.tencent.devops.model.auth.tables.records.TAuthResourceGroupRecord import org.jooq.DSLContext @@ -204,6 +205,21 @@ class AuthResourceGroupDao { } } + fun getResourceType2Count( + dslContext: DSLContext, + projectCode: String, + iamGroupIds: List + ): Map { + return with(TAuthResourceGroup.T_AUTH_RESOURCE_GROUP) { + dslContext.select(RESOURCE_TYPE, count()) + .from(this) + .where(PROJECT_CODE.eq(projectCode)) + .and(RELATION_ID.`in`(iamGroupIds)) + .groupBy(RESOURCE_TYPE) + .fetch().map { Pair(it.value1(), it.value2().toLong()) }.toMap() + } + } + fun delete( dslContext: DSLContext, projectCode: String, @@ -383,6 +399,7 @@ class AuthResourceGroupDao { it } } + .orderBy(CREATE_TIME) .offset(offset) .limit(limit) .fetch() diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/config/RbacAuthConfiguration.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/config/RbacAuthConfiguration.kt index d129208b7bf..f9a6730ca9c 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/config/RbacAuthConfiguration.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/config/RbacAuthConfiguration.kt @@ -65,7 +65,7 @@ import com.tencent.devops.auth.provider.rbac.service.RbacPermissionApplyService import com.tencent.devops.auth.provider.rbac.service.RbacPermissionAuthMonitorSpaceService import com.tencent.devops.auth.provider.rbac.service.RbacPermissionAuthorizationScopesService import com.tencent.devops.auth.provider.rbac.service.RbacPermissionExtService -import com.tencent.devops.auth.provider.rbac.service.RbacPermissionHandoverService +import com.tencent.devops.auth.provider.rbac.service.RbacPermissionHandoverApplicationService import com.tencent.devops.auth.provider.rbac.service.RbacPermissionItsmCallbackService import com.tencent.devops.auth.provider.rbac.service.RbacPermissionManageFacadeServiceImpl import com.tencent.devops.auth.provider.rbac.service.RbacPermissionProjectService @@ -97,7 +97,7 @@ import com.tencent.devops.auth.service.PermissionAuthorizationService import com.tencent.devops.auth.service.ResourceService import com.tencent.devops.auth.service.SuperManagerService import com.tencent.devops.auth.service.iam.MigrateCreatorFixService -import com.tencent.devops.auth.service.iam.PermissionHandoverService +import com.tencent.devops.auth.service.iam.PermissionHandoverApplicationService import com.tencent.devops.auth.service.iam.PermissionManageFacadeService import com.tencent.devops.auth.service.iam.PermissionResourceGroupPermissionService import com.tencent.devops.auth.service.iam.PermissionResourceGroupService @@ -215,9 +215,10 @@ class RbacAuthConfiguration { permissionAuthorizationService: PermissionAuthorizationService, syncIamGroupMemberService: PermissionResourceGroupSyncService, authAuthorizationDao: AuthAuthorizationDao, - permissionHandoverService: PermissionHandoverService, + permissionHandoverApplicationService: PermissionHandoverApplicationService, rbacCacheService: RbacCacheService, - redisOperation: RedisOperation + redisOperation: RedisOperation, + authorizationDao: AuthAuthorizationDao ) = RbacPermissionManageFacadeServiceImpl( permissionResourceGroupService = permissionResourceGroupService, groupPermissionService = groupPermissionService, @@ -230,9 +231,10 @@ class RbacAuthConfiguration { permissionAuthorizationService = permissionAuthorizationService, syncIamGroupMemberService = syncIamGroupMemberService, authAuthorizationDao = authAuthorizationDao, - permissionHandoverService = permissionHandoverService, + permissionHandoverApplicationService = permissionHandoverApplicationService, rbacCacheService = rbacCacheService, - redisOperation = redisOperation + redisOperation = redisOperation, + authorizationDao = authorizationDao ) @Bean @@ -619,7 +621,7 @@ class RbacAuthConfiguration { authResourceGroupDao: AuthResourceGroupDao, rbacCacheService: RbacCacheService, redisOperation: RedisOperation - ) = RbacPermissionHandoverService( + ) = RbacPermissionHandoverApplicationService( dslContext = dslContext, handoverOverviewDao = handoverOverviewDao, handoverDetailDao = handoverDetailDao, diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverApplicationService.kt similarity index 91% rename from src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverService.kt rename to src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverApplicationService.kt index 7c8618092a6..c53a11918e5 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverApplicationService.kt @@ -8,15 +8,15 @@ import com.tencent.devops.auth.dao.AuthHandoverOverviewDao import com.tencent.devops.auth.dao.AuthResourceGroupDao import com.tencent.devops.auth.pojo.dto.HandoverDetailDTO import com.tencent.devops.auth.pojo.dto.HandoverOverviewCreateDTO -import com.tencent.devops.auth.pojo.request.HandoverOverviewUpdateReq import com.tencent.devops.auth.pojo.enum.HandoverType import com.tencent.devops.auth.pojo.request.HandoverDetailsQueryReq import com.tencent.devops.auth.pojo.request.HandoverOverviewQueryReq +import com.tencent.devops.auth.pojo.request.HandoverOverviewUpdateReq import com.tencent.devops.auth.pojo.vo.HandoverAuthorizationDetailVo import com.tencent.devops.auth.pojo.vo.HandoverGroupDetailVo import com.tencent.devops.auth.pojo.vo.HandoverOverviewVo import com.tencent.devops.auth.pojo.vo.ResourceType2CountVo -import com.tencent.devops.auth.service.iam.PermissionHandoverService +import com.tencent.devops.auth.service.iam.PermissionHandoverApplicationService import com.tencent.devops.common.api.exception.ErrorCodeException import com.tencent.devops.common.api.model.SQLPage import com.tencent.devops.common.api.util.DateTimeUtil @@ -29,7 +29,7 @@ import org.jooq.impl.DSL import org.slf4j.LoggerFactory import java.time.LocalDateTime -class RbacPermissionHandoverService( +class RbacPermissionHandoverApplicationService( private val dslContext: DSLContext, private val handoverOverviewDao: AuthHandoverOverviewDao, private val handoverDetailDao: AuthHandoverDetailDao, @@ -37,7 +37,7 @@ class RbacPermissionHandoverService( private val authResourceGroupDao: AuthResourceGroupDao, private val rbacCacheService: RbacCacheService, private val redisOperation: RedisOperation -) : PermissionHandoverService { +) : PermissionHandoverApplicationService { override fun createHandoverApplication( overview: HandoverOverviewCreateDTO, details: List @@ -131,23 +131,24 @@ class RbacPermissionHandoverService( ) } - override fun listAuthorizationsOfHandover( + override fun listAuthorizationsOfHandoverApplication( queryReq: HandoverDetailsQueryReq ): SQLPage { - val overview = getHandoverOverview(queryReq.flowNo) + val flowNo = queryReq.flowNo!! + val overview = getHandoverOverview(flowNo) val resourceCodes = handoverDetailDao.list( dslContext = dslContext, projectCode = overview.projectCode, - flowNo = queryReq.flowNo, + flowNo = flowNo, resourceType = queryReq.resourceType, - handoverType = queryReq.handoverType + handoverType = HandoverType.AUTHORIZATION ).map { it.itemId } val count = handoverDetailDao.count( dslContext = dslContext, projectCode = overview.projectCode, - flowNo = queryReq.flowNo, + flowNo = flowNo, resourceType = queryReq.resourceType, - handoverType = queryReq.handoverType + handoverType = HandoverType.AUTHORIZATION ) val records = authorizationDao.list( dslContext = dslContext, @@ -162,20 +163,21 @@ class RbacPermissionHandoverService( HandoverAuthorizationDetailVo( resourceCode = it.resourceCode, resourceName = it.resourceName, - handoverType = queryReq.handoverType, + handoverType = HandoverType.AUTHORIZATION, handoverFrom = overview.applicant ) } return SQLPage(records = records, count = count) } - override fun listGroupsOfHandover( + override fun listGroupsOfHandoverApplication( queryReq: HandoverDetailsQueryReq ): SQLPage { - val handoverOverview = getHandoverOverview(queryReq.flowNo) + val flowNo = queryReq.flowNo!! + val handoverOverview = getHandoverOverview(flowNo) val iamGroupIdsByHandover = listHandoverDetails( projectCode = handoverOverview.projectCode, - flowNo = queryReq.flowNo, + flowNo = flowNo, resourceType = queryReq.resourceType, handoverType = HandoverType.GROUP ).map { it.itemId } @@ -208,7 +210,7 @@ class RbacPermissionHandoverService( ) } - override fun getResourceType2CountOfHandover(flowNo: String): List { + override fun getResourceType2CountOfHandoverApplication(flowNo: String): List { val handoverOverview = getHandoverOverview(flowNo) val resourceType2CountWithGroup = handoverDetailDao.countWithResourceType( dslContext = dslContext, @@ -258,7 +260,7 @@ class RbacPermissionHandoverService( } companion object { - private val logger = LoggerFactory.getLogger(RbacPermissionHandoverService::class.java) + private val logger = LoggerFactory.getLogger(RbacPermissionHandoverApplicationService::class.java) private const val FLOW_NO_PREFIX = "REQ" private const val FLOW_NO_KEY = "AUTH:HANDOVER:FLOW:NO:%s" } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt index 25447a03fa0..40b26206cf1 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt @@ -22,6 +22,7 @@ import com.tencent.devops.auth.pojo.dto.InvalidAuthorizationsDTO import com.tencent.devops.auth.pojo.dto.ProjectMembersQueryConditionDTO import com.tencent.devops.auth.pojo.enum.BatchOperateType import com.tencent.devops.auth.pojo.enum.HandoverAction +import com.tencent.devops.auth.pojo.enum.HandoverQueryChannel import com.tencent.devops.auth.pojo.enum.HandoverStatus import com.tencent.devops.auth.pojo.enum.HandoverType import com.tencent.devops.auth.pojo.enum.JoinedType @@ -33,16 +34,20 @@ import com.tencent.devops.auth.pojo.request.GroupMemberHandoverConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberRemoveConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberRenewalConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberSingleRenewalReq +import com.tencent.devops.auth.pojo.request.HandoverDetailsQueryReq import com.tencent.devops.auth.pojo.request.HandoverOverviewUpdateReq import com.tencent.devops.auth.pojo.request.ProjectMembersQueryConditionReq import com.tencent.devops.auth.pojo.request.RemoveMemberFromProjectReq +import com.tencent.devops.auth.pojo.request.ResourceType2CountOfHandoverQuery import com.tencent.devops.auth.pojo.vo.BatchOperateGroupMemberCheckVo import com.tencent.devops.auth.pojo.vo.GroupDetailsInfoVo +import com.tencent.devops.auth.pojo.vo.HandoverAuthorizationDetailVo +import com.tencent.devops.auth.pojo.vo.HandoverGroupDetailVo import com.tencent.devops.auth.pojo.vo.HandoverOverviewVo import com.tencent.devops.auth.pojo.vo.ResourceType2CountVo import com.tencent.devops.auth.service.DeptService import com.tencent.devops.auth.service.PermissionAuthorizationService -import com.tencent.devops.auth.service.iam.PermissionHandoverService +import com.tencent.devops.auth.service.iam.PermissionHandoverApplicationService import com.tencent.devops.auth.service.iam.PermissionManageFacadeService import com.tencent.devops.auth.service.iam.PermissionResourceGroupPermissionService import com.tencent.devops.auth.service.iam.PermissionResourceGroupService @@ -52,6 +57,7 @@ import com.tencent.devops.auth.service.lock.HandleHandoverApplicationLock import com.tencent.devops.common.api.exception.ErrorCodeException import com.tencent.devops.common.api.model.SQLPage import com.tencent.devops.common.api.util.DateTimeUtil +import com.tencent.devops.common.api.util.PageUtil import com.tencent.devops.common.api.util.timestamp import com.tencent.devops.common.api.util.timestampmilli import com.tencent.devops.common.auth.api.ActionId @@ -83,9 +89,10 @@ class RbacPermissionManageFacadeServiceImpl( private val authAuthorizationDao: AuthAuthorizationDao, private val syncIamGroupMemberService: PermissionResourceGroupSyncService, private val permissionAuthorizationService: PermissionAuthorizationService, - private val permissionHandoverService: PermissionHandoverService, + private val permissionHandoverApplicationService: PermissionHandoverApplicationService, private val rbacCacheService: RbacCacheService, - private val redisOperation: RedisOperation + private val redisOperation: RedisOperation, + private val authorizationDao: AuthAuthorizationDao ) : PermissionManageFacadeService { override fun getMemberGroupsDetails( projectId: String, @@ -626,114 +633,122 @@ class RbacPermissionManageFacadeServiceImpl( memberId: String ): InvalidAuthorizationsDTO { logger.info("list invalid authorizations after operated groups:$projectCode|$iamGroupIds|$memberId") - // 1.筛选出本次退出/交接中包含流水线执行权限的用户组 - val operatedGroupsWithExecutePerm = groupPermissionService.listGroupsByPermissionConditions( - projectCode = projectCode, - relatedResourceType = AuthResourceType.PIPELINE_DEFAULT.value, - action = ActionId.PIPELINE_EXECUTE, - filterIamGroupIds = iamGroupIds - ) - logger.debug("list operated groups with execute perm:{}", operatedGroupsWithExecutePerm) - - // 2.获取用户退出/交接以上操作的用户组后,还未退出的流水线/项目级别(仅这些类型会包含流水线执行权限)的用户组。 - val userGroupsJoinedAfterOperatedGroups = listResourceGroupMembers( - projectCode = projectCode, - memberId = memberId, - resourceType = ResourceTypeId.PIPELINE, - excludeIamGroupIds = operatedGroupsWithExecutePerm, - operateChannel = OperateChannel.PERSONAL - ).second.toMutableList().apply { - addAll( - listResourceGroupMembers( - projectCode = projectCode, - memberId = memberId, - resourceType = ResourceTypeId.PROJECT, - excludeIamGroupIds = operatedGroupsWithExecutePerm, - operateChannel = OperateChannel.PERSONAL - ).second + val startEpoch = System.currentTimeMillis() + try { + // 1.筛选出本次退出/交接中包含流水线执行权限的用户组 + val operatedGroupsWithExecutePerm = groupPermissionService.listGroupsByPermissionConditions( + projectCode = projectCode, + relatedResourceType = AuthResourceType.PIPELINE_DEFAULT.value, + action = ActionId.PIPELINE_EXECUTE, + filterIamGroupIds = iamGroupIds ) - }.map { it.iamGroupId } - logger.debug("list user groups joined after operated groups:{}", userGroupsJoinedAfterOperatedGroups) - // 3.查询未退出的流水线/项目级别的用户组中是否包含项目级别的流水线执行权限。 - // 查询用户在未退出的用户组中否还有整个项目的流水线执行权限。若有的话,则对流水线的代持人权限未造成影响。 - val hasAllPipelineExecutePermAfterOperateGroups = groupPermissionService.isGroupsHasProjectLevelPermission( - projectCode = projectCode, - filterIamGroupIds = userGroupsJoinedAfterOperatedGroups, - action = ActionId.PIPELINE_EXECUTE - ) - logger.debug("has all pipeline execute perm after operate groups:{}", hasAllPipelineExecutePermAfterOperateGroups) - - // 3.1.若用户在未退出的组中拥有整个项目的流水线执行权限,则本次不会对任何的流水线代持人权限造成影响。 - if (hasAllPipelineExecutePermAfterOperateGroups) - return InvalidAuthorizationsDTO(emptyList(), emptyList()) + logger.debug("list operated groups with execute perm:{}", operatedGroupsWithExecutePerm) - // 3.2.若没有的话,查询本次退出/交接的用户组中是否包含项目级别的流水线执行权限。 - val hasAllPipelineExecutePermInOperateGroups = groupPermissionService.isGroupsHasProjectLevelPermission( - projectCode = projectCode, - filterIamGroupIds = operatedGroupsWithExecutePerm, - action = ActionId.PIPELINE_EXECUTE - ) - logger.debug("has all pipeline execute perm in operate groups:{}", hasAllPipelineExecutePermInOperateGroups) - - val pipelinesWithoutAuthorization = if (hasAllPipelineExecutePermInOperateGroups) { - // 3.2.1 如果本次退出/交接的用户组中包含项目级别的流水线执行权限, - // 那么查询出用户还有执行流水线权限的流水线,该项目下除了这些流水线,其他的流水线代持人权限都会失效。 - val userHasExecutePermAfterOperatedGroups = groupPermissionService.listGroupResourcesWithPermission( + // 2.获取用户退出/交接以上操作的用户组后,还未退出的流水线/项目级别(仅这些类型会包含流水线执行权限)的用户组。 + val userGroupsJoinedAfterOperatedGroups = listResourceGroupMembers( projectCode = projectCode, - filterIamGroupIds = userGroupsJoinedAfterOperatedGroups, - relatedResourceType = ResourceTypeId.PIPELINE, - action = ActionId.PIPELINE_EXECUTE - )[ResourceTypeId.PIPELINE] ?: emptyList() - logger.debug("user has execute perm after operated groups:{}", userHasExecutePermAfterOperatedGroups) - // 失去代持人权限的流水线 - authAuthorizationDao.list( - dslContext = dslContext, - condition = ResourceAuthorizationConditionRequest( - projectCode = projectCode, - resourceType = ResourceTypeId.PIPELINE, - handoverFrom = memberId, - excludeResourceCodes = userHasExecutePermAfterOperatedGroups + memberId = memberId, + resourceType = ResourceTypeId.PIPELINE, + excludeIamGroupIds = operatedGroupsWithExecutePerm, + operateChannel = OperateChannel.PERSONAL + ).second.toMutableList().apply { + addAll( + listResourceGroupMembers( + projectCode = projectCode, + memberId = memberId, + resourceType = ResourceTypeId.PROJECT, + excludeIamGroupIds = operatedGroupsWithExecutePerm, + operateChannel = OperateChannel.PERSONAL + ).second ) - ).map { it.resourceCode } - } else { - // 3.2.2 如果本次退出/交接的用户组中不包含整个项目的流水线执行权限。 - // 通过计算得出,用户本次操作用户组,导致失去流水线执行权限的流水线。 - // 然后再计算失去这些流水线执行权限后,会导致哪些流水线的代持人权限失效。 - val pipelinesWithExecutePermAfterOperatedGroups = groupPermissionService.listGroupResourcesWithPermission( + }.map { it.iamGroupId } + logger.debug("list user groups joined after operated groups:{}", userGroupsJoinedAfterOperatedGroups) + // 3.查询未退出的流水线/项目级别的用户组中是否包含项目级别的流水线执行权限。 + // 查询用户在未退出的用户组中否还有整个项目的流水线执行权限。若有的话,则对流水线的代持人权限未造成影响。 + val hasAllPipelineExecutePermAfterOperateGroups = groupPermissionService.isGroupsHasProjectLevelPermission( projectCode = projectCode, filterIamGroupIds = userGroupsJoinedAfterOperatedGroups, - relatedResourceType = ResourceTypeId.PIPELINE, action = ActionId.PIPELINE_EXECUTE - )[ResourceTypeId.PIPELINE] ?: emptyList() - logger.debug("pipelines with execute perm after operate groups:{}", pipelinesWithExecutePermAfterOperatedGroups) + ) + logger.debug("has all pipeline execute perm after operate groups:{}", hasAllPipelineExecutePermAfterOperateGroups) + + // 3.1.若用户在未退出的组中拥有整个项目的流水线执行权限,则本次不会对任何的流水线代持人权限造成影响。 + if (hasAllPipelineExecutePermAfterOperateGroups) + return InvalidAuthorizationsDTO(emptyList(), emptyList()) - val pipelinesWithExecutePermInOperateGroups = groupPermissionService.listGroupResourcesWithPermission( + // 3.2.若没有的话,查询本次退出/交接的用户组中是否包含项目级别的流水线执行权限。 + val hasAllPipelineExecutePermInOperateGroups = groupPermissionService.isGroupsHasProjectLevelPermission( projectCode = projectCode, filterIamGroupIds = operatedGroupsWithExecutePerm, - relatedResourceType = ResourceTypeId.PIPELINE, action = ActionId.PIPELINE_EXECUTE - )[ResourceTypeId.PIPELINE] ?: emptyList() - logger.debug("pipelines with execute perm in operate groups:{}", pipelinesWithExecutePermInOperateGroups) + ) + logger.debug("has all pipeline execute perm in operate groups:{}", hasAllPipelineExecutePermInOperateGroups) - val pipelineExecutePermLostFromUser = pipelinesWithExecutePermInOperateGroups.filterNot { - pipelinesWithExecutePermAfterOperatedGroups.contains(it) - } - // 失去代持人权限的流水线 - authAuthorizationDao.list( - dslContext = dslContext, - condition = ResourceAuthorizationConditionRequest( + val pipelinesWithoutAuthorization = if (hasAllPipelineExecutePermInOperateGroups) { + // 3.2.1 如果本次退出/交接的用户组中包含项目级别的流水线执行权限, + // 那么查询出用户还有执行流水线权限的流水线,该项目下除了这些流水线,其他的流水线代持人权限都会失效。 + val userHasExecutePermAfterOperatedGroups = groupPermissionService.listGroupResourcesWithPermission( projectCode = projectCode, - resourceType = ResourceTypeId.PIPELINE, - handoverFrom = memberId, - filterResourceCodes = pipelineExecutePermLostFromUser + filterIamGroupIds = userGroupsJoinedAfterOperatedGroups, + relatedResourceType = ResourceTypeId.PIPELINE, + action = ActionId.PIPELINE_EXECUTE + )[ResourceTypeId.PIPELINE] ?: emptyList() + logger.debug("user has execute perm after operated groups:{}", userHasExecutePermAfterOperatedGroups) + // 失去代持人权限的流水线 + authAuthorizationDao.list( + dslContext = dslContext, + condition = ResourceAuthorizationConditionRequest( + projectCode = projectCode, + resourceType = ResourceTypeId.PIPELINE, + handoverFrom = memberId, + excludeResourceCodes = userHasExecutePermAfterOperatedGroups + ) + ).map { it.resourceCode } + } else { + // 3.2.2 如果本次退出/交接的用户组中不包含整个项目的流水线执行权限。 + // 通过计算得出,用户本次操作用户组,导致失去流水线执行权限的流水线。 + // 然后再计算失去这些流水线执行权限后,会导致哪些流水线的代持人权限失效。 + val pipelinesWithExecutePermAfterOperatedGroups = groupPermissionService.listGroupResourcesWithPermission( + projectCode = projectCode, + filterIamGroupIds = userGroupsJoinedAfterOperatedGroups, + relatedResourceType = ResourceTypeId.PIPELINE, + action = ActionId.PIPELINE_EXECUTE + )[ResourceTypeId.PIPELINE] ?: emptyList() + logger.debug("pipelines with execute perm after operate groups:{}", pipelinesWithExecutePermAfterOperatedGroups) + + val pipelinesWithExecutePermInOperateGroups = groupPermissionService.listGroupResourcesWithPermission( + projectCode = projectCode, + filterIamGroupIds = operatedGroupsWithExecutePerm, + relatedResourceType = ResourceTypeId.PIPELINE, + action = ActionId.PIPELINE_EXECUTE + )[ResourceTypeId.PIPELINE] ?: emptyList() + logger.debug("pipelines with execute perm in operate groups:{}", pipelinesWithExecutePermInOperateGroups) + + val pipelineExecutePermLostFromUser = pipelinesWithExecutePermInOperateGroups.filterNot { + pipelinesWithExecutePermAfterOperatedGroups.contains(it) + } + // 失去代持人权限的流水线 + authAuthorizationDao.list( + dslContext = dslContext, + condition = ResourceAuthorizationConditionRequest( + projectCode = projectCode, + resourceType = ResourceTypeId.PIPELINE, + handoverFrom = memberId, + filterResourceCodes = pipelineExecutePermLostFromUser + ) + ).map { it.resourceCode } + } + logger.debug("pipelines without authorization:{}", pipelinesWithoutAuthorization) + if (pipelinesWithoutAuthorization.isNotEmpty()) { + return InvalidAuthorizationsDTO( + invalidGroupIds = operatedGroupsWithExecutePerm, + invalidAuthorizations = pipelinesWithoutAuthorization ) - ).map { it.resourceCode } - } - logger.debug("pipelines without authorization:{}", pipelinesWithoutAuthorization) - if (pipelinesWithoutAuthorization.isNotEmpty()) { - return InvalidAuthorizationsDTO( - invalidGroupIds = operatedGroupsWithExecutePerm, - invalidAuthorizations = pipelinesWithoutAuthorization + } + } finally { + logger.info( + "It take(${System.currentTimeMillis() - startEpoch})ms to check invalid authorizations after operated groups" + + "|$projectCode|$iamGroupIds|$memberId" ) } return InvalidAuthorizationsDTO(emptyList(), emptyList()) @@ -748,6 +763,7 @@ class RbacPermissionManageFacadeServiceImpl( val groupId = renewalConditionReq.groupId batchOperateGroupMembers( projectCode = projectCode, + type = BatchOperateType.RENEWAL, conditionReq = GroupMemberRenewalConditionReq( groupIds = listOf(groupId), targetMember = renewalConditionReq.targetMember, @@ -806,6 +822,7 @@ class RbacPermissionManageFacadeServiceImpl( logger.info("batch renewal group member $userId|$projectCode|$renewalConditionReq") batchOperateGroupMembers( projectCode = projectCode, + type = BatchOperateType.RENEWAL, conditionReq = renewalConditionReq, operateGroupMemberTask = ::renewalTask ) @@ -823,6 +840,7 @@ class RbacPermissionManageFacadeServiceImpl( if (handoverMemberDTO.targetMember.type == MemberType.DEPARTMENT.type) { batchOperateGroupMembers( projectCode = projectCode, + type = BatchOperateType.HANDOVER, conditionReq = handoverMemberDTO, operateGroupMemberTask = ::handoverTask ) @@ -835,6 +853,7 @@ class RbacPermissionManageFacadeServiceImpl( // 交接用户组 batchOperateGroupMembers( projectCode = projectCode, + type = BatchOperateType.HANDOVER, conditionReq = handoverMemberDTO, operateGroupMemberTask = ::handoverTask ) @@ -892,8 +911,8 @@ class RbacPermissionManageFacadeServiceImpl( ) val handoverDetails = mutableListOf() - val flowNo = permissionHandoverService.generateFlowNo() - val title = permissionHandoverService.generateTitle( + val flowNo = permissionHandoverApplicationService.generateFlowNo() + val title = permissionHandoverApplicationService.generateTitle( groupCount = groupIds.size, authorizationCount = invalidPipelines.size ) @@ -920,7 +939,7 @@ class RbacPermissionManageFacadeServiceImpl( ) } // 创建交接单 - permissionHandoverService.createHandoverApplication( + permissionHandoverApplicationService.createHandoverApplication( overview = HandoverOverviewCreateDTO( projectCode = projectCode, flowNo = flowNo, @@ -946,6 +965,7 @@ class RbacPermissionManageFacadeServiceImpl( if (removeMemberDTO.targetMember.type == MemberType.DEPARTMENT.type) { batchOperateGroupMembers( projectCode = projectCode, + type = BatchOperateType.REMOVE, conditionReq = removeMemberDTO, operateGroupMemberTask = ::deleteTask ) @@ -976,6 +996,7 @@ class RbacPermissionManageFacadeServiceImpl( // 直接退出的用户组 batchOperateGroupMembers( projectCode = projectCode, + type = BatchOperateType.REMOVE, conditionReq = GroupMemberRemoveConditionReq( groupIds = toDeleteGroups, targetMember = removeMemberDTO.targetMember @@ -987,6 +1008,7 @@ class RbacPermissionManageFacadeServiceImpl( removeMemberDTO.checkHandoverTo() batchOperateGroupMembers( projectCode = projectCode, + type = BatchOperateType.HANDOVER, conditionReq = GroupMemberHandoverConditionReq( groupIds = toHandoverGroups, targetMember = removeMemberDTO.targetMember, @@ -1042,6 +1064,7 @@ class RbacPermissionManageFacadeServiceImpl( // 直接退出的用户组 batchOperateGroupMembers( projectCode = projectCode, + type = BatchOperateType.REMOVE, conditionReq = GroupMemberRemoveConditionReq( groupIds = toDeleteGroups, targetMember = removeMemberDTO.targetMember @@ -1058,8 +1081,8 @@ class RbacPermissionManageFacadeServiceImpl( ) val handoverDetails = mutableListOf() - val flowNo = permissionHandoverService.generateFlowNo() - val title = permissionHandoverService.generateTitle( + val flowNo = permissionHandoverApplicationService.generateFlowNo() + val title = permissionHandoverApplicationService.generateTitle( groupCount = groupIds.size, authorizationCount = invalidPipelines.size ) @@ -1085,7 +1108,7 @@ class RbacPermissionManageFacadeServiceImpl( ) ) } - permissionHandoverService.createHandoverApplication( + permissionHandoverApplicationService.createHandoverApplication( overview = HandoverOverviewCreateDTO( projectCode = projectCode, flowNo = flowNo, @@ -1372,6 +1395,7 @@ class RbacPermissionManageFacadeServiceImpl( ) batchOperateGroupMembers( projectCode = projectCode, + type = BatchOperateType.HANDOVER, conditionReq = handoverMemberDTO, operateGroupMemberTask = ::handoverTask ) @@ -1393,6 +1417,7 @@ class RbacPermissionManageFacadeServiceImpl( ) batchOperateGroupMembers( projectCode = projectCode, + type = BatchOperateType.REMOVE, conditionReq = removeMemberDTO, operateGroupMemberTask = ::deleteTask ) @@ -1448,7 +1473,7 @@ class RbacPermissionManageFacadeServiceImpl( } override fun handleHanoverApplication(request: HandoverOverviewUpdateReq): Boolean { - val overview = permissionHandoverService.getHandoverOverview(request.flowNo) + val overview = permissionHandoverApplicationService.getHandoverOverview(request.flowNo) logger.info("revoke hanover application:{}|{} ", request, overview) HandleHandoverApplicationLock(redisOperation, request.flowNo).use { lock -> if (!lock.tryLock()) { @@ -1463,7 +1488,7 @@ class RbacPermissionManageFacadeServiceImpl( overview = overview ) } - permissionHandoverService.updateHandoverApplication( + permissionHandoverApplicationService.updateHandoverApplication( overview = request ) } catch (e: Exception) { @@ -1474,6 +1499,131 @@ class RbacPermissionManageFacadeServiceImpl( return true } + override fun getResourceType2CountOfHandover(queryReq: ResourceType2CountOfHandoverQuery): List { + queryReq.check() + return if (queryReq.queryChannel == HandoverQueryChannel.HANDOVER_APPLICATION) { + permissionHandoverApplicationService.getResourceType2CountOfHandoverApplication(queryReq.flowNo!!) + } else { + getResourceType2CountOfHandoverPreview(queryReq) + } + } + + // 交接预览 + private fun getResourceType2CountOfHandoverPreview(queryReq: ResourceType2CountOfHandoverQuery): List { + val projectCode = queryReq.projectCode!! + val iamGroupIds = queryReq.iamGroupIds!! + val memberId = queryReq.memberId!! + val (invalidGroups, invalidPipelines) = listInvalidAuthorizationsAfterOperatedGroups( + projectCode = projectCode, + iamGroupIds = iamGroupIds, + memberId = memberId + ) + val resourceType2CountOfGroup = authResourceGroupDao.getResourceType2Count( + dslContext = dslContext, + projectCode = projectCode, + iamGroupIds = invalidGroups.map { it.toString() } + ) + val result = mutableListOf() + + if (resourceType2CountOfGroup.isNotEmpty()) { + result.addAll( + rbacCacheService.convertResourceType2Count( + resourceType2Count = resourceType2CountOfGroup, + type = HandoverType.GROUP + ) + ) + } + if (invalidPipelines.isNotEmpty()) { + result.addAll( + rbacCacheService.convertResourceType2Count( + resourceType2Count = mapOf(ResourceTypeId.PIPELINE to invalidPipelines.size.toLong()), + type = HandoverType.AUTHORIZATION + ) + ) + } + return result + } + + override fun listAuthorizationsOfHandover(queryReq: HandoverDetailsQueryReq): SQLPage { + queryReq.check() + return if (queryReq.queryChannel == HandoverQueryChannel.HANDOVER_APPLICATION) { + permissionHandoverApplicationService.listAuthorizationsOfHandoverApplication(queryReq) + } else { + listAuthorizationsOfHandoverPreview(queryReq) + } + } + + private fun listAuthorizationsOfHandoverPreview( + queryReq: HandoverDetailsQueryReq + ): SQLPage { + val projectCode = queryReq.projectCode!! + val iamGroupIds = queryReq.iamGroupIds!! + val memberId = queryReq.memberId!! + val invalidPipelines = listInvalidAuthorizationsAfterOperatedGroups( + projectCode = projectCode, + iamGroupIds = iamGroupIds, + memberId = memberId + ).invalidAuthorizations + val records = authorizationDao.list( + dslContext = dslContext, + condition = ResourceAuthorizationConditionRequest( + projectCode = projectCode, + resourceType = ResourceTypeId.PIPELINE, + filterResourceCodes = invalidPipelines, + page = queryReq.page, + pageSize = queryReq.pageSize + ) + ).map { + HandoverAuthorizationDetailVo( + resourceCode = it.resourceCode, + resourceName = it.resourceName, + handoverType = HandoverType.AUTHORIZATION, + handoverFrom = it.handoverFrom + ) + } + return SQLPage(count = invalidPipelines.size.toLong(), records = records) + } + + override fun listGroupsOfHandover(queryReq: HandoverDetailsQueryReq): SQLPage { + queryReq.check() + return if (queryReq.queryChannel == HandoverQueryChannel.HANDOVER_APPLICATION) { + permissionHandoverApplicationService.listGroupsOfHandoverApplication(queryReq) + } else { + listGroupsOfHandoverPreview(queryReq) + } + } + + private fun listGroupsOfHandoverPreview(queryReq: HandoverDetailsQueryReq): SQLPage { + val projectCode = queryReq.projectCode!! + val iamGroupIds = queryReq.iamGroupIds!! + val memberId = queryReq.memberId!! + val invalidGroupIds = listInvalidAuthorizationsAfterOperatedGroups( + projectCode = projectCode, + iamGroupIds = iamGroupIds, + memberId = memberId + ).invalidGroupIds + val convertPageSizeToSQLLimit = PageUtil.convertPageSizeToSQLLimit(queryReq.page, queryReq.pageSize) + + val records = authResourceGroupDao.listGroupByResourceType( + dslContext = dslContext, + projectCode = projectCode, + resourceType = queryReq.resourceType, + iamGroupIds = invalidGroupIds.map { it.toString() }, + offset = convertPageSizeToSQLLimit.offset, + limit = convertPageSizeToSQLLimit.limit + ).map { + HandoverGroupDetailVo( + projectCode = it.projectCode, + iamGroupId = it.relationId, + groupName = it.groupName, + groupDesc = it.description, + resourceCode = it.resourceCode, + resourceName = it.resourceName + ) + } + return SQLPage(count = invalidGroupIds.size.toLong(), records = records) + } + private fun handleHanoverCheck( request: HandoverOverviewUpdateReq, overview: HandoverOverviewVo @@ -1493,7 +1643,7 @@ class RbacPermissionManageFacadeServiceImpl( request: HandoverOverviewUpdateReq, overview: HandoverOverviewVo ) { - val handoverDetails = permissionHandoverService.listHandoverDetails( + val handoverDetails = permissionHandoverApplicationService.listHandoverDetails( projectCode = overview.projectCode, flowNo = overview.flowNo ) @@ -1520,6 +1670,7 @@ class RbacPermissionManageFacadeServiceImpl( ) batchOperateGroupMembers( projectCode = overview.projectCode, + type = BatchOperateType.HANDOVER, conditionReq = groupMemberHandoverConditionReq, operateGroupMemberTask = ::handoverTask ) @@ -1551,6 +1702,7 @@ class RbacPermissionManageFacadeServiceImpl( private fun batchOperateGroupMembers( projectCode: String, conditionReq: T, + type: BatchOperateType, operateGroupMemberTask: ( projectCode: String, groupId: Int, @@ -1558,51 +1710,54 @@ class RbacPermissionManageFacadeServiceImpl( expiredAt: Long ) -> Unit ): Boolean { - // 成员直接加入的组 - val groupIds = getGroupIdsByGroupMemberCondition( - projectCode = projectCode, - commonCondition = conditionReq - )[MemberType.get(conditionReq.targetMember.type)] - if (groupIds.isNullOrEmpty()) { - return true - } + val startEpoch = System.currentTimeMillis() + try { + // 成员直接加入的组 + val groupIds = getGroupIdsByGroupMemberCondition( + projectCode = projectCode, + commonCondition = conditionReq + )[MemberType.get(conditionReq.targetMember.type)] + if (groupIds.isNullOrEmpty()) { + return true + } - val targetMember = conditionReq.targetMember - val memberGroupsDetailsList = listMemberGroupsDetails( - projectCode = projectCode, - memberId = targetMember.id, - memberType = targetMember.type, - groupIds = groupIds - ) - val outOfSyncGroupIds = mutableListOf() - val futures = groupIds.map { groupId -> - CompletableFuture.supplyAsync( - { - val memberGroupsDetails = memberGroupsDetailsList.firstOrNull { it.id == groupId } - if (memberGroupsDetails == null) { - logger.warn( - "The data is out of sync, and the record no longer exists in the iam.$groupId" - ) - outOfSyncGroupIds.add(groupId) - return@supplyAsync - } - val expiredAt = memberGroupsDetails.expiredAt - RetryUtils.retry(3) { - operateGroupMemberTask.invoke( - projectCode, - groupId, - conditionReq, - expiredAt - ) - } - }, executorService + val targetMember = conditionReq.targetMember + val memberGroupsDetailsList = listMemberGroupsDetails( + projectCode = projectCode, + memberId = targetMember.id, + memberType = targetMember.type, + groupIds = groupIds + ) + val outOfSyncGroupIds = mutableListOf() + val futures = groupIds.map { groupId -> + CompletableFuture.supplyAsync( + { + val memberGroupsDetails = memberGroupsDetailsList.firstOrNull { it.id == groupId } + if (memberGroupsDetails == null) { + logger.warn("The data is out of sync, and the record no longer exists in the iam.$groupId") + outOfSyncGroupIds.add(groupId) + return@supplyAsync + } + val expiredAt = memberGroupsDetails.expiredAt + RetryUtils.retry(3) { + operateGroupMemberTask.invoke( + projectCode, + groupId, + conditionReq, + expiredAt + ) + } + }, executorService + ) + } + handleFutures( + projectCode = projectCode, + outOfSyncGroupIds = outOfSyncGroupIds, + futures = futures ) + } finally { + "It take(${System.currentTimeMillis() - startEpoch})ms to $type group members|$projectCode|$conditionReq" } - handleFutures( - projectCode = projectCode, - outOfSyncGroupIds = outOfSyncGroupIds, - futures = futures - ) return true } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupSyncService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupSyncService.kt index 928feb6f236..bdb6e8d6e52 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupSyncService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceGroupSyncService.kt @@ -111,6 +111,7 @@ class RbacPermissionResourceGroupSyncService @Autowired constructor( override fun syncGroupMemberExpiredTime(projectConditionDTO: ProjectConditionDTO) { logger.info("start to sync group member expired time|$projectConditionDTO") val traceId = MDC.get(TraceTag.BIZID) + val startEpoch = System.currentTimeMillis() syncExecutorService.submit { MDC.put(TraceTag.BIZID, traceId) var offset = 0 @@ -150,6 +151,7 @@ class RbacPermissionResourceGroupSyncService @Autowired constructor( futures.forEach { it.get() } offset += limit } while (projectCodes.size == limit) + logger.info("It take(${System.currentTimeMillis() - startEpoch})ms to sync Group Member Expired Time") } } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceValidateService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceValidateService.kt index c7176f50d89..3198aa05099 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceValidateService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionResourceValidateService.kt @@ -172,7 +172,7 @@ class RbacPermissionResourceValidateService( message = "The user does not have permission to visit the project!" ) } - if (userId != targetMemberId){ + if (userId != targetMemberId) { throw PermissionForbiddenException( message = "You do not have permission to operate other user groups!" ) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/config/MockAuthConfiguration.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/config/MockAuthConfiguration.kt index 627bd5a0e04..d7bc98262d4 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/config/MockAuthConfiguration.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/config/MockAuthConfiguration.kt @@ -8,7 +8,7 @@ import com.tencent.devops.auth.provider.sample.service.SampleAuthPermissionServi import com.tencent.devops.auth.provider.sample.service.SampleOrganizationService import com.tencent.devops.auth.provider.sample.service.SamplePermissionApplyService import com.tencent.devops.auth.provider.sample.service.SamplePermissionExtService -import com.tencent.devops.auth.provider.sample.service.SamplePermissionHandoverService +import com.tencent.devops.auth.provider.sample.service.SamplePermissionHandoverApplicationService import com.tencent.devops.auth.provider.sample.service.SamplePermissionItsmCallbackService import com.tencent.devops.auth.provider.sample.service.SamplePermissionMigrateService import com.tencent.devops.auth.provider.sample.service.SamplePermissionManageFacadeService @@ -28,7 +28,7 @@ import com.tencent.devops.auth.service.PermissionAuthorizationService import com.tencent.devops.auth.service.SuperManagerService import com.tencent.devops.auth.service.iam.PermissionApplyService import com.tencent.devops.auth.service.iam.PermissionExtService -import com.tencent.devops.auth.service.iam.PermissionHandoverService +import com.tencent.devops.auth.service.iam.PermissionHandoverApplicationService import com.tencent.devops.auth.service.iam.PermissionItsmCallbackService import com.tencent.devops.auth.service.iam.PermissionMigrateService import com.tencent.devops.auth.service.iam.PermissionProjectService @@ -132,6 +132,6 @@ class MockAuthConfiguration { fun samplePermissionResourceGroupSyncService() = SamplePermissionResourceGroupSyncService() @Bean - @ConditionalOnMissingBean(PermissionHandoverService::class) - fun samplePermissionHandoverService() = SamplePermissionHandoverService() + @ConditionalOnMissingBean(PermissionHandoverApplicationService::class) + fun samplePermissionHandoverService() = SamplePermissionHandoverApplicationService() } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionHandoverService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionHandoverApplicationService.kt similarity index 80% rename from src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionHandoverService.kt rename to src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionHandoverApplicationService.kt index 83748b1af39..cb82750990d 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionHandoverService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionHandoverApplicationService.kt @@ -10,10 +10,10 @@ import com.tencent.devops.auth.pojo.vo.HandoverAuthorizationDetailVo import com.tencent.devops.auth.pojo.vo.HandoverGroupDetailVo import com.tencent.devops.auth.pojo.vo.HandoverOverviewVo import com.tencent.devops.auth.pojo.vo.ResourceType2CountVo -import com.tencent.devops.auth.service.iam.PermissionHandoverService +import com.tencent.devops.auth.service.iam.PermissionHandoverApplicationService import com.tencent.devops.common.api.model.SQLPage -class SamplePermissionHandoverService : PermissionHandoverService { +class SamplePermissionHandoverApplicationService : PermissionHandoverApplicationService { override fun createHandoverApplication( overview: HandoverOverviewCreateDTO, details: List @@ -37,17 +37,17 @@ class SamplePermissionHandoverService : PermissionHandoverService { return SQLPage(0, emptyList()) } - override fun listAuthorizationsOfHandover( + override fun listAuthorizationsOfHandoverApplication( queryReq: HandoverDetailsQueryReq ): SQLPage { return SQLPage(0, emptyList()) } - override fun listGroupsOfHandover(queryReq: HandoverDetailsQueryReq): SQLPage { + override fun listGroupsOfHandoverApplication(queryReq: HandoverDetailsQueryReq): SQLPage { return SQLPage(0, emptyList()) } - override fun getResourceType2CountOfHandover(flowNo: String): List { + override fun getResourceType2CountOfHandoverApplication(flowNo: String): List { return emptyList() } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionManageFacadeService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionManageFacadeService.kt index 620adfeb671..2898bcecacf 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionManageFacadeService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionManageFacadeService.kt @@ -11,11 +11,15 @@ import com.tencent.devops.auth.pojo.request.GroupMemberHandoverConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberRemoveConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberRenewalConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberSingleRenewalReq +import com.tencent.devops.auth.pojo.request.HandoverDetailsQueryReq import com.tencent.devops.auth.pojo.request.HandoverOverviewUpdateReq import com.tencent.devops.auth.pojo.request.ProjectMembersQueryConditionReq import com.tencent.devops.auth.pojo.request.RemoveMemberFromProjectReq +import com.tencent.devops.auth.pojo.request.ResourceType2CountOfHandoverQuery import com.tencent.devops.auth.pojo.vo.BatchOperateGroupMemberCheckVo import com.tencent.devops.auth.pojo.vo.GroupDetailsInfoVo +import com.tencent.devops.auth.pojo.vo.HandoverAuthorizationDetailVo +import com.tencent.devops.auth.pojo.vo.HandoverGroupDetailVo import com.tencent.devops.auth.pojo.vo.ResourceType2CountVo import com.tencent.devops.auth.service.iam.PermissionManageFacadeService import com.tencent.devops.common.api.model.SQLPage @@ -137,4 +141,16 @@ class SamplePermissionManageFacadeService : PermissionManageFacadeService { ): Boolean = true override fun handleHanoverApplication(request: HandoverOverviewUpdateReq): Boolean = true + + override fun getResourceType2CountOfHandover(queryReq: ResourceType2CountOfHandoverQuery): List { + return emptyList() + } + + override fun listAuthorizationsOfHandover(queryReq: HandoverDetailsQueryReq): SQLPage { + return SQLPage(0, emptyList()) + } + + override fun listGroupsOfHandover(queryReq: HandoverDetailsQueryReq): SQLPage { + return SQLPage(0, emptyList()) + } } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/service/ServiceProjectAuthResourceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/service/ServiceProjectAuthResourceImpl.kt index e94939ddc5b..e52fd966270 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/service/ServiceProjectAuthResourceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/service/ServiceProjectAuthResourceImpl.kt @@ -29,6 +29,7 @@ package com.tencent.devops.auth.resources.service import com.tencent.devops.auth.api.service.ServiceProjectAuthResource import com.tencent.devops.auth.pojo.vo.ProjectPermissionInfoVO +import com.tencent.devops.auth.service.PermissionAuthorizationService import com.tencent.devops.auth.service.iam.PermissionProjectService import com.tencent.devops.common.api.pojo.Result import com.tencent.devops.common.auth.api.pojo.BKAuthProjectRolesResources @@ -41,7 +42,8 @@ import org.springframework.beans.factory.annotation.Autowired @RestResource class ServiceProjectAuthResourceImpl @Autowired constructor( - val permissionProjectService: PermissionProjectService + val permissionProjectService: PermissionProjectService, + val permissionAuthorizationService: PermissionAuthorizationService ) : ServiceProjectAuthResource { @BkApiPermission([BkApiHandleType.API_OPEN_TOKEN_CHECK]) override fun getProjectUsers( @@ -201,4 +203,12 @@ class ServiceProjectAuthResourceImpl @Autowired constructor( ) ) } + + override fun listUserProjects(userId: String): Result> { + return Result( + permissionAuthorizationService.listUserProjects( + userId = userId + ) + ) + } } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthHandoverResourceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthHandoverResourceImpl.kt index 68be9dd6b97..b55573f6f30 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthHandoverResourceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthHandoverResourceImpl.kt @@ -5,12 +5,13 @@ import com.tencent.devops.auth.pojo.enum.OperateChannel import com.tencent.devops.auth.pojo.request.HandoverDetailsQueryReq import com.tencent.devops.auth.pojo.request.HandoverOverviewQueryReq import com.tencent.devops.auth.pojo.request.HandoverOverviewUpdateReq +import com.tencent.devops.auth.pojo.request.ResourceType2CountOfHandoverQuery import com.tencent.devops.auth.pojo.vo.HandoverAuthorizationDetailVo import com.tencent.devops.auth.pojo.vo.HandoverGroupDetailVo import com.tencent.devops.auth.pojo.vo.HandoverOverviewVo import com.tencent.devops.auth.pojo.vo.ResourceType2CountVo import com.tencent.devops.auth.service.PermissionAuthorizationService -import com.tencent.devops.auth.service.iam.PermissionHandoverService +import com.tencent.devops.auth.service.iam.PermissionHandoverApplicationService import com.tencent.devops.auth.service.iam.PermissionManageFacadeService import com.tencent.devops.auth.service.iam.PermissionResourceValidateService import com.tencent.devops.common.api.exception.PermissionForbiddenException @@ -23,7 +24,7 @@ import com.tencent.devops.common.web.RestResource class UserAuthHandoverResourceImpl( private val permissionAuthorizationService: PermissionAuthorizationService, private val permissionManageFacadeService: PermissionManageFacadeService, - private val permissionHandoverService: PermissionHandoverService, + private val permissionHandoverApplicationService: PermissionHandoverApplicationService, private val permissionResourceValidateService: PermissionResourceValidateService ) : UserAuthHandoverResource { override fun handoverAuthorizationsApplication( @@ -56,28 +57,28 @@ class UserAuthHandoverResourceImpl( ) } - return Result(permissionHandoverService.listHandoverOverviews(queryRequest = queryRequest)) + return Result(permissionHandoverApplicationService.listHandoverOverviews(queryRequest = queryRequest)) } override fun getResourceType2CountOfHandover( userId: String, - flowNo: String + queryReq: ResourceType2CountOfHandoverQuery ): Result> { - return Result(permissionHandoverService.getResourceType2CountOfHandover(flowNo = flowNo)) + return Result(permissionManageFacadeService.getResourceType2CountOfHandover(queryReq = queryReq)) } override fun listAuthorizationsOfHandover( userId: String, queryReq: HandoverDetailsQueryReq ): Result> { - return Result(permissionHandoverService.listAuthorizationsOfHandover(queryReq = queryReq)) + return Result(permissionManageFacadeService.listAuthorizationsOfHandover(queryReq = queryReq)) } override fun listGroupsOfHandover( userId: String, queryReq: HandoverDetailsQueryReq ): Result> { - return Result(permissionHandoverService.listGroupsOfHandover(queryReq = queryReq)) + return Result(permissionManageFacadeService.listGroupsOfHandover(queryReq = queryReq)) } override fun handleHanoverApplication(userId: String, request: HandoverOverviewUpdateReq): Result { diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationService.kt index 5cf6e3117ca..45331886a48 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationService.kt @@ -80,6 +80,13 @@ interface PermissionAuthorizationService { condition: ResourceAuthorizationConditionRequest ): SQLPage + /** + * 获取用户授权相关项目 + */ + fun listUserProjects( + userId: String + ): List + /** * 修改资源授权管理 */ diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt index 15b7846adba..76e0af87e98 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt @@ -10,7 +10,7 @@ import com.tencent.devops.auth.pojo.dto.HandoverOverviewCreateDTO import com.tencent.devops.auth.pojo.enum.HandoverStatus import com.tencent.devops.auth.pojo.enum.HandoverType import com.tencent.devops.auth.pojo.vo.ResourceTypeInfoVo -import com.tencent.devops.auth.service.iam.PermissionHandoverService +import com.tencent.devops.auth.service.iam.PermissionHandoverApplicationService import com.tencent.devops.auth.service.iam.PermissionResourceValidateService import com.tencent.devops.auth.service.iam.PermissionService import com.tencent.devops.common.api.exception.ErrorCodeException @@ -43,7 +43,7 @@ class PermissionAuthorizationServiceImpl( private val permissionResourceValidateService: PermissionResourceValidateService, private val deptService: DeptService, private val permissionService: PermissionService, - private val permissionHandoverService: PermissionHandoverService + private val permissionHandoverApplicationService: PermissionHandoverApplicationService ) : PermissionAuthorizationService { companion object { private val logger = LoggerFactory.getLogger(PermissionAuthorizationServiceImpl::class.java) @@ -145,6 +145,10 @@ class PermissionAuthorizationServiceImpl( ) } + override fun listUserProjects(userId: String): List { + return authAuthorizationDao.listUserProjects(dslContext, userId) + } + override fun modifyResourceAuthorization(resourceAuthorizationList: List): Boolean { logger.info("modify resource authorizations:$resourceAuthorizationList") addHandoverFromCnName(resourceAuthorizationList) @@ -251,8 +255,8 @@ class PermissionAuthorizationServiceImpl( } val resourceAuthorizationList = getResourceAuthorizationList(condition = condition) val authorizationCount = resourceAuthorizationList.size - val flowNo = permissionHandoverService.generateFlowNo() - val title = permissionHandoverService.generateTitle( + val flowNo = permissionHandoverApplicationService.generateFlowNo() + val title = permissionHandoverApplicationService.generateTitle( groupCount = 0, authorizationCount = authorizationCount ) @@ -269,7 +273,7 @@ class PermissionAuthorizationServiceImpl( ) } // 创建交接单 - permissionHandoverService.createHandoverApplication( + permissionHandoverApplicationService.createHandoverApplication( overview = HandoverOverviewCreateDTO( projectCode = projectCode, flowNo = flowNo, diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionHandoverService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionHandoverApplicationService.kt similarity index 83% rename from src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionHandoverService.kt rename to src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionHandoverApplicationService.kt index 037cd4bc671..d79c0b6212b 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionHandoverService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionHandoverApplicationService.kt @@ -2,17 +2,17 @@ package com.tencent.devops.auth.service.iam import com.tencent.devops.auth.pojo.dto.HandoverDetailDTO import com.tencent.devops.auth.pojo.dto.HandoverOverviewCreateDTO -import com.tencent.devops.auth.pojo.request.HandoverOverviewUpdateReq import com.tencent.devops.auth.pojo.enum.HandoverType import com.tencent.devops.auth.pojo.request.HandoverDetailsQueryReq import com.tencent.devops.auth.pojo.request.HandoverOverviewQueryReq +import com.tencent.devops.auth.pojo.request.HandoverOverviewUpdateReq import com.tencent.devops.auth.pojo.vo.HandoverAuthorizationDetailVo import com.tencent.devops.auth.pojo.vo.HandoverGroupDetailVo import com.tencent.devops.auth.pojo.vo.HandoverOverviewVo import com.tencent.devops.auth.pojo.vo.ResourceType2CountVo import com.tencent.devops.common.api.model.SQLPage -interface PermissionHandoverService { +interface PermissionHandoverApplicationService { /** * 创建权限交接申请单 * */ @@ -56,15 +56,15 @@ interface PermissionHandoverService { /** * 获取交接单中授权相关 * */ - fun listAuthorizationsOfHandover(queryReq: HandoverDetailsQueryReq): SQLPage + fun listAuthorizationsOfHandoverApplication(queryReq: HandoverDetailsQueryReq): SQLPage /** * 获取交接单中用户组相关 * */ - fun listGroupsOfHandover(queryReq: HandoverDetailsQueryReq): SQLPage + fun listGroupsOfHandoverApplication(queryReq: HandoverDetailsQueryReq): SQLPage /** * 根据资源类型进行分类 * */ - fun getResourceType2CountOfHandover(flowNo: String): List + fun getResourceType2CountOfHandoverApplication(flowNo: String): List } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionManageFacadeService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionManageFacadeService.kt index 6b5a2c8479a..2ed38675be0 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionManageFacadeService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionManageFacadeService.kt @@ -11,11 +11,15 @@ import com.tencent.devops.auth.pojo.request.GroupMemberHandoverConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberRemoveConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberRenewalConditionReq import com.tencent.devops.auth.pojo.request.GroupMemberSingleRenewalReq +import com.tencent.devops.auth.pojo.request.HandoverDetailsQueryReq import com.tencent.devops.auth.pojo.request.HandoverOverviewUpdateReq import com.tencent.devops.auth.pojo.request.ProjectMembersQueryConditionReq import com.tencent.devops.auth.pojo.request.RemoveMemberFromProjectReq +import com.tencent.devops.auth.pojo.request.ResourceType2CountOfHandoverQuery import com.tencent.devops.auth.pojo.vo.BatchOperateGroupMemberCheckVo import com.tencent.devops.auth.pojo.vo.GroupDetailsInfoVo +import com.tencent.devops.auth.pojo.vo.HandoverAuthorizationDetailVo +import com.tencent.devops.auth.pojo.vo.HandoverGroupDetailVo import com.tencent.devops.auth.pojo.vo.ResourceType2CountVo import com.tencent.devops.common.api.model.SQLPage @@ -167,6 +171,9 @@ interface PermissionManageFacadeService { removeMemberDTO: GroupMemberRemoveConditionReq ): Boolean + /** + * 批量操作检查 + * */ fun batchOperateGroupMembersCheck( userId: String, projectCode: String, @@ -174,12 +181,18 @@ interface PermissionManageFacadeService { conditionReq: GroupMemberCommonConditionReq ): BatchOperateGroupMemberCheckVo + /** + * 将用户移出项目-管理员视角 + * */ fun removeMemberFromProject( userId: String, projectCode: String, removeMemberFromProjectReq: RemoveMemberFromProjectReq ): List + /** + * 将用户移出项目检查-管理员视角 + * */ fun removeMemberFromProjectCheck( userId: String, projectCode: String, @@ -190,4 +203,19 @@ interface PermissionManageFacadeService { * 处理交接审批单 * */ fun handleHanoverApplication(request: HandoverOverviewUpdateReq): Boolean + + /** + * 根据资源类型进行分类-交接 + * */ + fun getResourceType2CountOfHandover(queryReq: ResourceType2CountOfHandoverQuery): List + + /** + * 获取交接中授权相关-分为预览/交接单审批两个场景 + * */ + fun listAuthorizationsOfHandover(queryReq: HandoverDetailsQueryReq): SQLPage + + /** + * 获取交接中用户组相关-分为预览/交接单审批两个场景 + * */ + fun listGroupsOfHandover(queryReq: HandoverDetailsQueryReq): SQLPage } diff --git a/src/backend/ci/core/common/common-archive/src/main/kotlin/com/tencent/devops/common/archive/pojo/BKRepoProjectUpdateRequest.kt b/src/backend/ci/core/common/common-archive/src/main/kotlin/com/tencent/devops/common/archive/pojo/BKRepoProjectUpdateRequest.kt index 9d88f752de6..3657af9a6d6 100644 --- a/src/backend/ci/core/common/common-archive/src/main/kotlin/com/tencent/devops/common/archive/pojo/BKRepoProjectUpdateRequest.kt +++ b/src/backend/ci/core/common/common-archive/src/main/kotlin/com/tencent/devops/common/archive/pojo/BKRepoProjectUpdateRequest.kt @@ -12,5 +12,5 @@ data class BKRepoProjectUpdateRequest( @get:Schema(title = "项目新建仓库默认使用的存储") val credentialsKey: String? = null, @get:Schema(title = "设置项目新建仓库默认使用默认存储") - val useDefaultCredentialsKey: Boolean? = false, + val useDefaultCredentialsKey: Boolean? = false ) diff --git a/src/backend/ci/core/common/common-archive/src/main/kotlin/com/tencent/devops/common/archive/pojo/ProjectMetadata.kt b/src/backend/ci/core/common/common-archive/src/main/kotlin/com/tencent/devops/common/archive/pojo/ProjectMetadata.kt index f53d41090d8..2c31b9a545b 100644 --- a/src/backend/ci/core/common/common-archive/src/main/kotlin/com/tencent/devops/common/archive/pojo/ProjectMetadata.kt +++ b/src/backend/ci/core/common/common-archive/src/main/kotlin/com/tencent/devops/common/archive/pojo/ProjectMetadata.kt @@ -8,5 +8,5 @@ data class ProjectMetadata( /** * 元数据值 */ - var value: Any, + var value: Any ) diff --git a/src/backend/ci/core/project/api-project/src/main/kotlin/com/tencent/devops/project/api/user/UserProjectResource.kt b/src/backend/ci/core/project/api-project/src/main/kotlin/com/tencent/devops/project/api/user/UserProjectResource.kt index e8f127c08cd..3faea6cd8b3 100644 --- a/src/backend/ci/core/project/api-project/src/main/kotlin/com/tencent/devops/project/api/user/UserProjectResource.kt +++ b/src/backend/ci/core/project/api-project/src/main/kotlin/com/tencent/devops/project/api/user/UserProjectResource.kt @@ -89,7 +89,10 @@ interface UserProjectResource { sortType: ProjectSortType?, @Parameter(description = "排序规则", required = false) @QueryParam("collation") - collation: ProjectCollation? + collation: ProjectCollation?, + @Parameter(description = "是否查询授权相关项目", required = false) + @QueryParam("queryAuthorization") + queryAuthorization: Boolean? ): Result> @GET diff --git a/src/backend/ci/core/project/biz-project/src/main/kotlin/com/tencent/devops/project/resources/UserProjectResourceImpl.kt b/src/backend/ci/core/project/biz-project/src/main/kotlin/com/tencent/devops/project/resources/UserProjectResourceImpl.kt index 5dc5d7e84de..2973270a59a 100644 --- a/src/backend/ci/core/project/biz-project/src/main/kotlin/com/tencent/devops/project/resources/UserProjectResourceImpl.kt +++ b/src/backend/ci/core/project/biz-project/src/main/kotlin/com/tencent/devops/project/resources/UserProjectResourceImpl.kt @@ -69,7 +69,8 @@ class UserProjectResourceImpl @Autowired constructor( enabled: Boolean?, unApproved: Boolean?, sortType: ProjectSortType?, - collation: ProjectCollation? + collation: ProjectCollation?, + queryAuthorization: Boolean? ): Result> { return Result( projectService.list( @@ -78,7 +79,8 @@ class UserProjectResourceImpl @Autowired constructor( enabled = enabled, unApproved = unApproved ?: false, sortType = sortType ?: ProjectSortType.PROJECT_NAME, - collation = collation ?: ProjectCollation.DEFAULT + collation = collation ?: ProjectCollation.DEFAULT, + queryAuthorization = queryAuthorization ) ) } diff --git a/src/backend/ci/core/project/biz-project/src/main/kotlin/com/tencent/devops/project/service/ProjectService.kt b/src/backend/ci/core/project/biz-project/src/main/kotlin/com/tencent/devops/project/service/ProjectService.kt index c59da263686..4c1452278e3 100644 --- a/src/backend/ci/core/project/biz-project/src/main/kotlin/com/tencent/devops/project/service/ProjectService.kt +++ b/src/backend/ci/core/project/biz-project/src/main/kotlin/com/tencent/devops/project/service/ProjectService.kt @@ -164,7 +164,9 @@ interface ProjectService { enabled: Boolean? = null, unApproved: Boolean, sortType: ProjectSortType? = null, - collation: ProjectCollation? = null + collation: ProjectCollation? = null, + // 获取授权相关项目(主要用于个人视角界面) + queryAuthorization: Boolean? = false ): List fun listProjectsForApply( diff --git a/src/backend/ci/core/project/biz-project/src/main/kotlin/com/tencent/devops/project/service/impl/AbsProjectServiceImpl.kt b/src/backend/ci/core/project/biz-project/src/main/kotlin/com/tencent/devops/project/service/impl/AbsProjectServiceImpl.kt index cda63255184..f841f698ad4 100644 --- a/src/backend/ci/core/project/biz-project/src/main/kotlin/com/tencent/devops/project/service/impl/AbsProjectServiceImpl.kt +++ b/src/backend/ci/core/project/biz-project/src/main/kotlin/com/tencent/devops/project/service/impl/AbsProjectServiceImpl.kt @@ -32,6 +32,7 @@ import com.fasterxml.jackson.databind.ObjectMapper import com.tencent.bk.audit.annotations.ActionAuditRecord import com.tencent.bk.audit.annotations.AuditInstanceRecord import com.tencent.bk.audit.context.ActionAuditContext +import com.tencent.devops.auth.api.service.ServiceProjectAuthResource import com.tencent.devops.common.api.enums.SystemModuleEnum import com.tencent.devops.common.api.exception.ErrorCodeException import com.tencent.devops.common.api.exception.InvalidParamException @@ -809,15 +810,29 @@ abstract class AbsProjectServiceImpl @Autowired constructor( enabled: Boolean?, unApproved: Boolean, sortType: ProjectSortType?, - collation: ProjectCollation? + collation: ProjectCollation?, + queryAuthorization: Boolean? ): List { val startEpoch = System.currentTimeMillis() var success = false try { + // 获取有访问权限的项目 val projectsWithVisitPermission = getProjectFromAuth( userId = userId, accessToken = accessToken - ).toSet() + ).toMutableSet() + // 获取授权相关项目,主要用于个人视角权限管理 + if (queryAuthorization == true) { + val projectWithAuthorization = try { + client.get(ServiceProjectAuthResource::class).listUserProjects(userId).data ?: emptyList() + } catch (ex: Exception) { + emptyList() + } + projectsWithVisitPermission.apply { + this.addAll(projectWithAuthorization) + } + } + if (projectsWithVisitPermission.isEmpty() && !unApproved) { return emptyList() } diff --git a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/atom/dao/AtomDao.kt b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/atom/dao/AtomDao.kt index f127eb0e29e..3c2a3237fc4 100644 --- a/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/atom/dao/AtomDao.kt +++ b/src/backend/ci/core/store/biz-store/src/main/kotlin/com/tencent/devops/store/atom/dao/AtomDao.kt @@ -1198,7 +1198,7 @@ class AtomDao : AtomBaseDao() { listOf( AtomStatusEnum.UNDERCARRIAGING.status.toByte(), AtomStatusEnum.UNDERCARRIAGED.status.toByte(), - AtomStatusEnum.RELEASED.status.toByte(), + AtomStatusEnum.RELEASED.status.toByte() ) )) } else { diff --git a/support-files/sql/2004_v3.x/2030_ci_auth-update_v3.0_mysql.sql b/support-files/sql/2004_v3.x/2030_ci_auth-update_v3.0_mysql.sql index dd612f62c83..a151c2258e5 100644 --- a/support-files/sql/2004_v3.x/2030_ci_auth-update_v3.0_mysql.sql +++ b/support-files/sql/2004_v3.x/2030_ci_auth-update_v3.0_mysql.sql @@ -38,6 +38,14 @@ BEGIN ALTER TABLE T_AUTH_OAUTH2_ACCESS_TOKEN ADD COLUMN `PASS_WORD` VARCHAR(64) DEFAULT NULL COMMENT '用于密码模式' AFTER `USER_NAME`; END IF; + IF NOT EXISTS(SELECT 1 + FROM information_schema.statistics + WHERE TABLE_SCHEMA = db + AND TABLE_NAME = 'T_AUTH_RESOURCE_AUTHORIZATION' + AND INDEX_NAME = 'HANDOVER_FROM_PROJECT_CODE_INDEX') THEN + ALTER TABLE T_AUTH_RESOURCE_AUTHORIZATION ADD INDEX `HANDOVER_FROM_PROJECT_CODE_INDEX` (`HANDOVER_FROM`,`PROJECT_CODE`); + END IF; + COMMIT; END DELIMITER ; From ae8d8d550b1f10bcdb28c9ba4e1c3e35018c209e Mon Sep 17 00:00:00 2001 From: greysonfang Date: Fri, 29 Nov 2024 17:59:17 +0800 Subject: [PATCH 20/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/pojo/dto/InvalidAuthorizationsDTO.kt | 4 +- .../pojo/request/HandoverDetailsQueryReq.kt | 14 +- .../pojo/request/HandoverOverviewQueryReq.kt | 5 +- .../ResourceType2CountOfHandoverQuery.kt | 17 +- .../pojo/vo/BatchOperateGroupMemberCheckVo.kt | 6 +- .../devops/auth/pojo/vo/GroupDetailsInfoVo.kt | 4 +- .../devops/auth/dao/AuthHandoverDetailDao.kt | 14 +- .../auth/dao/AuthHandoverOverviewDao.kt | 4 +- ...bacPermissionHandoverApplicationService.kt | 29 +- .../RbacPermissionManageFacadeServiceImpl.kt | 423 +++++++++++++----- ...plePermissionHandoverApplicationService.kt | 8 + .../user/UserAuthHandoverResourceImpl.kt | 2 +- .../service/PermissionAuthorizationService.kt | 8 + .../PermissionAuthorizationServiceImpl.kt | 30 ++ .../PermissionHandoverApplicationService.kt | 9 + .../iam/PermissionManageFacadeService.kt | 3 +- .../devops/common/auth/api/ActionId.kt | 1 + 17 files changed, 442 insertions(+), 139 deletions(-) diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/dto/InvalidAuthorizationsDTO.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/dto/InvalidAuthorizationsDTO.kt index f49626f8c55..097096aad72 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/dto/InvalidAuthorizationsDTO.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/dto/InvalidAuthorizationsDTO.kt @@ -7,5 +7,7 @@ data class InvalidAuthorizationsDTO( @get:Schema(title = "引起代持人权限失效的用户组") val invalidGroupIds: List, @get:Schema(title = "引起代持人权限失效的流水线") - val invalidAuthorizations: List + val invalidPipelineIds: List, + @get:Schema(title = "引起oauth失效的代码库") + val invalidRepertoryIds: List = emptyList() ) diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverDetailsQueryReq.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverDetailsQueryReq.kt index 9a8bb88206d..81065ed94d4 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverDetailsQueryReq.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverDetailsQueryReq.kt @@ -5,16 +5,14 @@ import io.swagger.v3.oas.annotations.media.Schema @Schema(title = "权限交接详细查询请求体") data class HandoverDetailsQueryReq( + @get:Schema(title = "项目ID") + val projectCode: String, @get:Schema(title = "组/授权资源关联的资源类型") val resourceType: String, @get:Schema(title = "流程单号") val flowNo: String?, - @get:Schema(title = "项目ID") - val projectCode: String?, - @get:Schema(title = "操作的组ID") - val iamGroupIds: List?, - @get:Schema(title = "用户ID") - val memberId: String?, + @get:Schema(title = "交接预览请求条件") + val previewConditionReq: GroupMemberCommonConditionReq?, @get:Schema(title = "渠道") val queryChannel: HandoverQueryChannel, @get:Schema(title = "第几页") @@ -31,8 +29,8 @@ data class HandoverDetailsQueryReq( } else -> { - if (projectCode == null || iamGroupIds == null || memberId == null) { - throw IllegalArgumentException("projectCode or iamGroupIds or memberId cannot be null!") + if (previewConditionReq == null) { + throw IllegalArgumentException("previewConditionReq can not be null!") } } } diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverOverviewQueryReq.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverOverviewQueryReq.kt index 01efd77de22..7d4b8aa88ad 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverOverviewQueryReq.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/HandoverOverviewQueryReq.kt @@ -1,13 +1,12 @@ package com.tencent.devops.auth.pojo.request import com.tencent.devops.auth.pojo.enum.HandoverStatus -import com.tencent.devops.auth.pojo.enum.HandoverType import io.swagger.v3.oas.annotations.media.Schema @Schema(title = "权限交接总览查询") data class HandoverOverviewQueryReq( @get:Schema(title = "成员ID") - val memberID: String, + val memberId: String, @get:Schema(title = "项目ID") val projectCode: String? = null, @get:Schema(title = "项目ID") @@ -24,8 +23,6 @@ data class HandoverOverviewQueryReq( val minCreatedTime: Long? = null, @get:Schema(title = "最打提单时间") val maxCreatedTime: Long? = null, - @get:Schema(title = "交接类型") - val handoverType: HandoverType? = null, @get:Schema(title = "页数") val page: Int? = null, @get:Schema(title = "页大小") diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/ResourceType2CountOfHandoverQuery.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/ResourceType2CountOfHandoverQuery.kt index 734ba51b15a..a3c0cd1c298 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/ResourceType2CountOfHandoverQuery.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/request/ResourceType2CountOfHandoverQuery.kt @@ -1,19 +1,20 @@ package com.tencent.devops.auth.pojo.request +import com.tencent.devops.auth.pojo.enum.BatchOperateType import com.tencent.devops.auth.pojo.enum.HandoverQueryChannel import io.swagger.v3.oas.annotations.media.Schema data class ResourceType2CountOfHandoverQuery( + @get:Schema(title = "项目ID") + val projectCode: String, @get:Schema(title = "渠道") val queryChannel: HandoverQueryChannel, @get:Schema(title = "流程单号") val flowNo: String?, - @get:Schema(title = "项目ID") - val projectCode: String?, - @get:Schema(title = "操作的组ID") - val iamGroupIds: List?, - @get:Schema(title = "用户ID") - val memberId: String? + @get:Schema(title = "交接预览请求条件") + val previewConditionReq: GroupMemberCommonConditionReq?, + @get:Schema(title = "批量操作动作") + val batchOperateType: BatchOperateType? ) { fun check() { when (queryChannel) { @@ -24,8 +25,8 @@ data class ResourceType2CountOfHandoverQuery( } else -> { - if (projectCode == null || iamGroupIds == null || memberId == null) { - throw IllegalArgumentException("projectCode or iamGroupIds or memberId cannot be null!") + if (previewConditionReq == null || batchOperateType == null) { + throw IllegalArgumentException("previewConditionReq or batchOperateType can not be null!") } } } diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/BatchOperateGroupMemberCheckVo.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/BatchOperateGroupMemberCheckVo.kt index 7972171ac94..8b9257db5fb 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/BatchOperateGroupMemberCheckVo.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/BatchOperateGroupMemberCheckVo.kt @@ -12,6 +12,10 @@ data class BatchOperateGroupMemberCheckVo( val inoperableCount: Int? = null, @get:Schema(title = "唯一管理员组的数量") val uniqueManagerCount: Int? = null, + @get:Schema(title = "导致代持人失效的用户组") + val invalidGroupCount: Int? = null, @get:Schema(title = "无效的流水线授权数量") - val invalidPipelineAuthorizationCount: Int? = null + val invalidPipelineAuthorizationCount: Int? = null, + @get:Schema(title = "无效的代码库授权数量") + val invalidRepositoryAuthorizationCount: Int? = null ) diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/GroupDetailsInfoVo.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/GroupDetailsInfoVo.kt index 6193dda5c6e..0e6f8bd256f 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/GroupDetailsInfoVo.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/GroupDetailsInfoVo.kt @@ -29,5 +29,7 @@ data class GroupDetailsInfoVo( @get:Schema(title = "加入方式") val joinedType: JoinedType, @get:Schema(title = "操作人") - val operator: String + val operator: String, + @get:Schema(title = "是否正在交接") + val beingHandedOver: Boolean? = null ) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthHandoverDetailDao.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthHandoverDetailDao.kt index a78efd6aaab..73a5ac000dc 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthHandoverDetailDao.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthHandoverDetailDao.kt @@ -38,7 +38,7 @@ class AuthHandoverDetailDao { fun list( dslContext: DSLContext, projectCode: String, - flowNo: String, + flowNos: List, resourceType: String?, handoverType: HandoverType? ): List { @@ -47,7 +47,7 @@ class AuthHandoverDetailDao { .where( buildQueryConditions( projectCode = projectCode, - flowNo = flowNo, + flowNos = flowNos, resourceType = resourceType, handoverType = handoverType ) @@ -58,7 +58,7 @@ class AuthHandoverDetailDao { fun count( dslContext: DSLContext, projectCode: String, - flowNo: String, + flowNos: List, resourceType: String?, handoverType: HandoverType? ): Long { @@ -67,7 +67,7 @@ class AuthHandoverDetailDao { .where( buildQueryConditions( projectCode = projectCode, - flowNo = flowNo, + flowNos = flowNos, resourceType = resourceType, handoverType = handoverType ) @@ -87,7 +87,7 @@ class AuthHandoverDetailDao { .where( buildQueryConditions( projectCode = projectCode, - flowNo = flowNo, + flowNos = listOf(flowNo), resourceType = null, handoverType = handoverType ) @@ -98,14 +98,14 @@ class AuthHandoverDetailDao { private fun buildQueryConditions( projectCode: String, - flowNo: String, + flowNos: List, resourceType: String?, handoverType: HandoverType? ): List { with(TAuthHandoverDetail.T_AUTH_HANDOVER_DETAIL) { val conditions = mutableListOf() conditions.add(PROJECT_CODE.eq(projectCode)) - conditions.add(FLOW_NO.eq(flowNo)) + conditions.add(FLOW_NO.`in`(flowNos)) resourceType?.let { conditions.add(RESOURCE_TYPE.eq(resourceType)) } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthHandoverOverviewDao.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthHandoverOverviewDao.kt index 4f2ca7b1825..d9ae83250ee 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthHandoverOverviewDao.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/dao/AuthHandoverOverviewDao.kt @@ -87,7 +87,7 @@ class AuthHandoverOverviewDao { } else { it } - }.fetch().map { it.convert(queryRequest.memberID) } + }.fetch().map { it.convert(queryRequest.memberId) } } } @@ -107,7 +107,7 @@ class AuthHandoverOverviewDao { ): List { with(TAuthHandoverOverview.T_AUTH_HANDOVER_OVERVIEW) { val conditions = mutableListOf() - conditions.add(APPROVER.eq(queryRequest.memberID).or(APPLICANT.eq(queryRequest.memberID))) + conditions.add(APPROVER.eq(queryRequest.memberId).or(APPLICANT.eq(queryRequest.memberId))) queryRequest.projectCode?.let { conditions.add(PROJECT_CODE.eq(queryRequest.projectCode)) } queryRequest.title?.let { conditions.add(TITLE.like("%${queryRequest.title}%")) } queryRequest.flowNo?.let { conditions.add(FLOW_NO.eq(queryRequest.flowNo)) } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverApplicationService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverApplicationService.kt index c53a11918e5..40f58fb120d 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverApplicationService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverApplicationService.kt @@ -8,6 +8,7 @@ import com.tencent.devops.auth.dao.AuthHandoverOverviewDao import com.tencent.devops.auth.dao.AuthResourceGroupDao import com.tencent.devops.auth.pojo.dto.HandoverDetailDTO import com.tencent.devops.auth.pojo.dto.HandoverOverviewCreateDTO +import com.tencent.devops.auth.pojo.enum.HandoverStatus import com.tencent.devops.auth.pojo.enum.HandoverType import com.tencent.devops.auth.pojo.request.HandoverDetailsQueryReq import com.tencent.devops.auth.pojo.request.HandoverOverviewQueryReq @@ -139,14 +140,14 @@ class RbacPermissionHandoverApplicationService( val resourceCodes = handoverDetailDao.list( dslContext = dslContext, projectCode = overview.projectCode, - flowNo = flowNo, + flowNos = listOf(flowNo), resourceType = queryReq.resourceType, handoverType = HandoverType.AUTHORIZATION ).map { it.itemId } val count = handoverDetailDao.count( dslContext = dslContext, projectCode = overview.projectCode, - flowNo = flowNo, + flowNos = listOf(flowNo), resourceType = queryReq.resourceType, handoverType = HandoverType.AUTHORIZATION ) @@ -253,12 +254,34 @@ class RbacPermissionHandoverApplicationService( return handoverDetailDao.list( dslContext = dslContext, projectCode = projectCode, - flowNo = flowNo, + flowNos = listOf(flowNo), resourceType = resourceType, handoverType = handoverType ) } + override fun listMemberHandoverDetails( + projectCode: String, + memberId: String, + handoverType: HandoverType + ): List { + val flowNos = listHandoverOverviews( + queryRequest = HandoverOverviewQueryReq( + memberId = memberId, + projectCode = projectCode, + applicant = memberId, + handoverStatus = HandoverStatus.PENDING + ) + ).records.map { it.flowNo } + return handoverDetailDao.list( + dslContext = dslContext, + projectCode = projectCode, + flowNos = flowNos, + resourceType = null, + handoverType = handoverType + ) + } + companion object { private val logger = LoggerFactory.getLogger(RbacPermissionHandoverApplicationService::class.java) private const val FLOW_NO_PREFIX = "REQ" diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt index 40b26206cf1..ca40e840c95 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt @@ -150,6 +150,8 @@ class RbacPermissionManageFacadeServiceImpl( resourceGroupMembers = resourceGroupMembers, operateChannel = operateChannel ) + // 获取用户正在交接的用户组 + val records = mutableListOf() resourceGroupMembers.forEach { val resourceGroup = resourceGroupMap[it.iamGroupId.toString()]!! @@ -631,6 +633,28 @@ class RbacPermissionManageFacadeServiceImpl( projectCode: String, iamGroupIds: List, memberId: String + ): InvalidAuthorizationsDTO { + val (invalidGroups, invalidPipelines) = listInvalidPipelinesAfterOperatedGroups( + projectCode = projectCode, + iamGroupIds = iamGroupIds, + memberId = memberId + ) + val invalidRepositoryIds = listInvalidRepositoryAfterOperatedGroups( + projectCode = projectCode, + iamGroupIds = iamGroupIds, + memberId = memberId + ) + return InvalidAuthorizationsDTO( + invalidGroupIds = invalidGroups, + invalidPipelineIds = invalidPipelines, + invalidRepertoryIds = invalidRepositoryIds + ) + } + + private fun listInvalidPipelinesAfterOperatedGroups( + projectCode: String, + iamGroupIds: List, + memberId: String ): InvalidAuthorizationsDTO { logger.info("list invalid authorizations after operated groups:$projectCode|$iamGroupIds|$memberId") val startEpoch = System.currentTimeMillis() @@ -742,7 +766,7 @@ class RbacPermissionManageFacadeServiceImpl( if (pipelinesWithoutAuthorization.isNotEmpty()) { return InvalidAuthorizationsDTO( invalidGroupIds = operatedGroupsWithExecutePerm, - invalidAuthorizations = pipelinesWithoutAuthorization + invalidPipelineIds = pipelinesWithoutAuthorization ) } } finally { @@ -754,6 +778,55 @@ class RbacPermissionManageFacadeServiceImpl( return InvalidAuthorizationsDTO(emptyList(), emptyList()) } + private fun listInvalidRepositoryAfterOperatedGroups( + projectCode: String, + iamGroupIds: List, + memberId: String + ): List { + // 获取用户退出/交接以上用户组后还加入的用户组 + val (count, records) = listResourceGroupMembers( + projectCode = projectCode, + memberId = memberId, + excludeIamGroupIds = iamGroupIds, + operateChannel = OperateChannel.PERSONAL + ) + + // 如果退出/交接了项目下所有组,直接返回用户无效代码库oauth列表 + if (count == 0L) { + return authAuthorizationDao.list( + dslContext = dslContext, + condition = ResourceAuthorizationConditionRequest( + projectCode = projectCode, + resourceType = ResourceTypeId.REPERTORY, + handoverFrom = memberId + ) + ).map { it.resourceCode } + } + + // 检查用户是否还有权限访问权限当退出/交接以上组后 + val isHasProjectVisitPermOperatedGroups = groupPermissionService.isGroupsHasPermission( + projectCode = projectCode, + filterIamGroupIds = records.map { it.iamGroupId }, + relatedResourceType = ResourceTypeId.PROJECT, + relatedResourceCode = projectCode, + action = ActionId.PROJECT_VISIT + ) + + // 如果有访问权限,返回空列表,否则直接返回用户无效代码库oauth列表 + return if (isHasProjectVisitPermOperatedGroups) { + emptyList() + } else { + authAuthorizationDao.list( + dslContext = dslContext, + condition = ResourceAuthorizationConditionRequest( + projectCode = projectCode, + resourceType = ResourceTypeId.REPERTORY, + handoverFrom = memberId + ) + ).map { it.resourceCode } + } + } + override fun renewalGroupMember( userId: String, projectCode: String, @@ -850,6 +923,23 @@ class RbacPermissionManageFacadeServiceImpl( projectCode = projectCode, commonCondition = handoverMemberDTO )[MemberType.USER] ?: return true + // 获取导致失效的流水线/代码库授权,并进行交接 + val (invalidGroups, invalidPipelines, invalidRepertoryIds) = + listInvalidAuthorizationsAfterOperatedGroups( + projectCode = projectCode, + iamGroupIds = groupIds, + memberId = handoverMemberDTO.targetMember.id + ) + // 检查授予人是否有代码库oauth权限 + if (invalidRepertoryIds.isNotEmpty()) { + permissionAuthorizationService.checkRepertoryAuthorizationsHanover( + operator = userId, + projectCode = projectCode, + repertoryIds = invalidRepertoryIds, + handoverFrom = handoverMemberDTO.targetMember.id, + handoverTo = handoverMemberDTO.handoverTo.id + ) + } // 交接用户组 batchOperateGroupMembers( projectCode = projectCode, @@ -857,14 +947,24 @@ class RbacPermissionManageFacadeServiceImpl( conditionReq = handoverMemberDTO, operateGroupMemberTask = ::handoverTask ) - // 获取导致流水线代持人权限受到影响的流水线,并进行交接 - val invalidPipelines = listInvalidAuthorizationsAfterOperatedGroups( - projectCode = projectCode, - iamGroupIds = groupIds, - memberId = handoverMemberDTO.targetMember.id - ).invalidAuthorizations + + if (invalidRepertoryIds.isNotEmpty()) { + permissionAuthorizationService.resetResourceAuthorizationByResourceType( + operator = userId, + projectCode = projectCode, + condition = ResourceAuthorizationHandoverConditionRequest( + projectCode = projectCode, + resourceType = ResourceTypeId.REPERTORY, + fullSelection = true, + filterResourceCodes = invalidRepertoryIds, + handoverChannel = HandoverChannelCode.MANAGER, + handoverFrom = handoverMemberDTO.targetMember.id, + handoverTo = handoverMemberDTO.handoverTo.id, + checkPermission = false + ) + ) + } if (invalidPipelines.isNotEmpty()) { - // 交接授权 permissionAuthorizationService.resetResourceAuthorizationByResourceType( operator = userId, projectCode = projectCode, @@ -898,23 +998,34 @@ class RbacPermissionManageFacadeServiceImpl( if (groupIds.isNullOrEmpty()) { return true } - // 本次操作导致流水线代持人权限受到影响的流水线 - val invalidPipelines = listInvalidAuthorizationsAfterOperatedGroups( - projectCode = projectCode, - iamGroupIds = groupIds, - memberId = handoverMemberDTO.targetMember.id - ).invalidAuthorizations val resourceGroups = authResourceGroupDao.listByRelationId( dslContext = dslContext, projectCode = projectCode, iamGroupIds = groupIds.map { it.toString() } ) + // 本次操作导致失效的授权 + val invalidAuthorizations = listInvalidAuthorizationsAfterOperatedGroups( + projectCode = projectCode, + iamGroupIds = groupIds, + memberId = handoverMemberDTO.targetMember.id + ) + val invalidPipelines = invalidAuthorizations.invalidPipelineIds + val invalidRepertoryIds = invalidAuthorizations.invalidRepertoryIds + if (invalidRepertoryIds.isNotEmpty()) { + permissionAuthorizationService.checkRepertoryAuthorizationsHanover( + operator = userId, + projectCode = projectCode, + repertoryIds = invalidRepertoryIds, + handoverFrom = handoverMemberDTO.targetMember.id, + handoverTo = handoverMemberDTO.handoverTo.id + ) + } val handoverDetails = mutableListOf() val flowNo = permissionHandoverApplicationService.generateFlowNo() val title = permissionHandoverApplicationService.generateTitle( groupCount = groupIds.size, - authorizationCount = invalidPipelines.size + authorizationCount = invalidPipelines.size + invalidRepertoryIds.size ) resourceGroups.forEach { groupInfo -> handoverDetails.add( @@ -938,6 +1049,17 @@ class RbacPermissionManageFacadeServiceImpl( ) ) } + invalidRepertoryIds.forEach { repertoryId -> + handoverDetails.add( + HandoverDetailDTO( + projectCode = projectCode, + flowNo = flowNo, + itemId = repertoryId, + resourceType = ResourceTypeId.REPERTORY, + handoverType = HandoverType.AUTHORIZATION + ) + ) + } // 创建交接单 permissionHandoverApplicationService.createHandoverApplication( overview = HandoverOverviewCreateDTO( @@ -948,7 +1070,7 @@ class RbacPermissionManageFacadeServiceImpl( approver = handoverMemberDTO.handoverTo.id, handoverStatus = HandoverStatus.PENDING, groupCount = groupIds.size, - authorizationCount = invalidPipelines.size + authorizationCount = invalidPipelines.size + invalidRepertoryIds.size ), details = handoverDetails ) @@ -973,24 +1095,33 @@ class RbacPermissionManageFacadeServiceImpl( } // 以下逻辑是用户类型成员的批量移出组 // 根据条件获取成员直接加入的用户组 - val groupIds = getGroupIdsByGroupMemberCondition( + val groupIdsDirectlyJoined = getGroupIdsByGroupMemberCondition( projectCode = projectCode, commonCondition = removeMemberDTO )[MemberType.USER] ?: return true + // 获取导致流水线代持人权限受到影响的用户组及流水线以及代码库授权 + val (invalidGroups, invalidPipelines, invalidRepertoryIds) = + listInvalidAuthorizationsAfterOperatedGroups( + projectCode = projectCode, + iamGroupIds = groupIdsDirectlyJoined, + memberId = removeMemberDTO.targetMember.id + ) + if (invalidRepertoryIds.isNotEmpty()) { + permissionAuthorizationService.checkRepertoryAuthorizationsHanover( + operator = userId, + projectCode = projectCode, + repertoryIds = invalidRepertoryIds, + handoverFrom = removeMemberDTO.targetMember.id, + handoverTo = removeMemberDTO.handoverTo!!.id, + ) + } // 获取唯一管理员组 val uniqueManagerGroups = authResourceGroupMemberDao.listProjectUniqueManagerGroups( dslContext = dslContext, projectCode = projectCode, - iamGroupIds = groupIds + iamGroupIds = groupIdsDirectlyJoined ) - // 获取导致流水线代持人权限受到影响的用户组及流水线 - val (invalidGroups, invalidPipelines) = - listInvalidAuthorizationsAfterOperatedGroups( - projectCode = projectCode, - iamGroupIds = groupIds, - memberId = removeMemberDTO.targetMember.id - ) - val (toHandoverGroups, toDeleteGroups) = groupIds.partition { + val (toHandoverGroups, toDeleteGroups) = groupIdsDirectlyJoined.partition { uniqueManagerGroups.contains(it) || invalidGroups.contains(it) } // 直接退出的用户组 @@ -1003,7 +1134,7 @@ class RbacPermissionManageFacadeServiceImpl( ), operateGroupMemberTask = ::deleteTask ) - // 交接唯一拥有者、影响代持人权限的用户组以及流水线授权 + // 交接唯一拥有者、影响代持人权限的用户组以及流水线/代码库授权 if (toHandoverGroups.isNotEmpty()) { removeMemberDTO.checkHandoverTo() batchOperateGroupMembers( @@ -1016,6 +1147,8 @@ class RbacPermissionManageFacadeServiceImpl( ), operateGroupMemberTask = ::handoverTask ) + } + if (invalidPipelines.isNotEmpty()) { permissionAuthorizationService.resetResourceAuthorizationByResourceType( operator = userId, projectCode = projectCode, @@ -1031,6 +1164,22 @@ class RbacPermissionManageFacadeServiceImpl( ) ) } + if (invalidRepertoryIds.isNotEmpty()) { + permissionAuthorizationService.resetResourceAuthorizationByResourceType( + operator = userId, + projectCode = projectCode, + condition = ResourceAuthorizationHandoverConditionRequest( + projectCode = projectCode, + resourceType = ResourceTypeId.REPERTORY, + filterResourceCodes = invalidRepertoryIds, + fullSelection = true, + handoverChannel = HandoverChannelCode.MANAGER, + handoverFrom = removeMemberDTO.targetMember.id, + handoverTo = removeMemberDTO.handoverTo!!.id, + checkPermission = false + ) + ) + } return true } @@ -1045,19 +1194,31 @@ class RbacPermissionManageFacadeServiceImpl( projectCode = projectCode, commonCondition = removeMemberDTO )[MemberType.USER] ?: return true - // 获取唯一管理员组 - val uniqueManagerGroups = authResourceGroupMemberDao.listProjectUniqueManagerGroups( - dslContext = dslContext, - projectCode = projectCode, - iamGroupIds = groupIds - ) // 获取导致流水线代持人权限受到影响的用户组及流水线 - val (invalidGroups, invalidPipelines) = + val (invalidGroups, invalidPipelines, invalidRepertoryIds) = listInvalidAuthorizationsAfterOperatedGroups( projectCode = projectCode, iamGroupIds = groupIds, memberId = removeMemberDTO.targetMember.id ) + + // 检查授予人是否有代码库oauth权限 + if (invalidRepertoryIds.isNotEmpty()) { + permissionAuthorizationService.checkRepertoryAuthorizationsHanover( + operator = userId, + projectCode = projectCode, + repertoryIds = invalidRepertoryIds, + handoverFrom = removeMemberDTO.targetMember.id, + handoverTo = removeMemberDTO.handoverTo!!.id, + ) + } + + // 获取唯一管理员组 + val uniqueManagerGroups = authResourceGroupMemberDao.listProjectUniqueManagerGroups( + dslContext = dslContext, + projectCode = projectCode, + iamGroupIds = groupIds + ) val (toHandoverGroups, toDeleteGroups) = groupIds.partition { uniqueManagerGroups.contains(it) || invalidGroups.contains(it) } @@ -1071,7 +1232,9 @@ class RbacPermissionManageFacadeServiceImpl( ), operateGroupMemberTask = ::deleteTask ) - // 交接唯一拥有者、影响代持人权限的用户组以及流水线授权 + val handoverDetails = mutableListOf() + val flowNo = permissionHandoverApplicationService.generateFlowNo() + // 交接唯一拥有者、影响代持人权限的用户组 if (toHandoverGroups.isNotEmpty()) { removeMemberDTO.checkHandoverTo() val resourceGroups = authResourceGroupDao.listByRelationId( @@ -1079,13 +1242,6 @@ class RbacPermissionManageFacadeServiceImpl( projectCode = projectCode, iamGroupIds = toHandoverGroups.map { it.toString() } ) - - val handoverDetails = mutableListOf() - val flowNo = permissionHandoverApplicationService.generateFlowNo() - val title = permissionHandoverApplicationService.generateTitle( - groupCount = groupIds.size, - authorizationCount = invalidPipelines.size - ) resourceGroups.forEach { groupInfo -> handoverDetails.add( HandoverDetailDTO( @@ -1097,6 +1253,10 @@ class RbacPermissionManageFacadeServiceImpl( ) ) } + + } + // 交接流水线代持失效的流水线 + if (invalidPipelines.isNotEmpty()) { invalidPipelines.forEach { pipelineId -> handoverDetails.add( HandoverDetailDTO( @@ -1108,20 +1268,38 @@ class RbacPermissionManageFacadeServiceImpl( ) ) } - permissionHandoverApplicationService.createHandoverApplication( - overview = HandoverOverviewCreateDTO( - projectCode = projectCode, - flowNo = flowNo, - title = title, - applicant = removeMemberDTO.targetMember.id, - approver = removeMemberDTO.handoverTo!!.id, - handoverStatus = HandoverStatus.PENDING, - groupCount = toHandoverGroups.size, - authorizationCount = invalidPipelines.size - ), - details = handoverDetails - ) } + // 交接代码库授权失效的代码库 + if (invalidRepertoryIds.isNotEmpty()) { + invalidRepertoryIds.forEach { repertoryId -> + handoverDetails.add( + HandoverDetailDTO( + projectCode = projectCode, + flowNo = flowNo, + itemId = repertoryId, + resourceType = ResourceTypeId.REPERTORY, + handoverType = HandoverType.AUTHORIZATION + ) + ) + } + } + val title = permissionHandoverApplicationService.generateTitle( + groupCount = groupIds.size, + authorizationCount = invalidPipelines.size + invalidRepertoryIds.size + ) + permissionHandoverApplicationService.createHandoverApplication( + overview = HandoverOverviewCreateDTO( + projectCode = projectCode, + flowNo = flowNo, + title = title, + applicant = removeMemberDTO.targetMember.id, + approver = removeMemberDTO.handoverTo!!.id, + handoverStatus = HandoverStatus.PENDING, + groupCount = toHandoverGroups.size, + authorizationCount = invalidPipelines.size + invalidRepertoryIds.size + ), + details = handoverDetails + ) return true } @@ -1272,8 +1450,8 @@ class RbacPermissionManageFacadeServiceImpl( projectCode = projectCode, iamGroupIds = groupsOfDirectlyJoined ) - // 本次操作导致流水线代持人权限受到影响的用户组及流水线 - val (invalidGroups, invalidPipelines) = + // 本次操作导致流水线代持人权限受到影响的用户组及流水线/代码库oauth + val (invalidGroups, invalidPipelines, invalidRepositoryIds) = listInvalidAuthorizationsAfterOperatedGroups( projectCode = projectCode, iamGroupIds = groupsOfDirectlyJoined, @@ -1291,7 +1469,9 @@ class RbacPermissionManageFacadeServiceImpl( operableCount = totalCount - groupsOfInOperableWhenBatchRemove, inoperableCount = groupsOfInOperableWhenBatchRemove, uniqueManagerCount = groupsOfUniqueManager.size, - invalidPipelineAuthorizationCount = invalidPipelines.size + invalidGroupCount = invalidGroups.size, + invalidPipelineAuthorizationCount = invalidPipelines.size, + invalidRepositoryAuthorizationCount = invalidRepositoryIds.size ) } } @@ -1352,17 +1532,19 @@ class RbacPermissionManageFacadeServiceImpl( }.size val inoperableCount = groupsOfTemplateOrDeptJoined.size + groupCountOfExpired // 本次操作导致流水线代持人权限受到影响的流水线 - val invalidPipelines = listInvalidAuthorizationsAfterOperatedGroups( - projectCode = projectCode, - iamGroupIds = groupsOfDirectlyJoined, - memberId = conditionReq.targetMember.id - ).invalidAuthorizations + val (invalidGroups, invalidPipelines, invalidRepositoryIds) = + listInvalidAuthorizationsAfterOperatedGroups( + projectCode = projectCode, + iamGroupIds = groupsOfDirectlyJoined, + memberId = conditionReq.targetMember.id + ) BatchOperateGroupMemberCheckVo( totalCount = totalCount, operableCount = totalCount - inoperableCount, inoperableCount = groupsOfTemplateOrDeptJoined.size + groupCountOfExpired, - invalidPipelineAuthorizationCount = invalidPipelines.size + invalidPipelineAuthorizationCount = invalidPipelines.size, + invalidRepositoryAuthorizationCount = invalidRepositoryIds.size ) } } @@ -1510,33 +1692,54 @@ class RbacPermissionManageFacadeServiceImpl( // 交接预览 private fun getResourceType2CountOfHandoverPreview(queryReq: ResourceType2CountOfHandoverQuery): List { - val projectCode = queryReq.projectCode!! - val iamGroupIds = queryReq.iamGroupIds!! - val memberId = queryReq.memberId!! - val (invalidGroups, invalidPipelines) = listInvalidAuthorizationsAfterOperatedGroups( + val projectCode = queryReq.projectCode + val previewConditionReq = queryReq.previewConditionReq!! + val batchOperateType = queryReq.batchOperateType!! + val groupIdsDirectlyJoined = getGroupIdsByGroupMemberCondition( projectCode = projectCode, - iamGroupIds = iamGroupIds, - memberId = memberId - ) - val resourceType2CountOfGroup = authResourceGroupDao.getResourceType2Count( - dslContext = dslContext, + commonCondition = previewConditionReq + )[MemberType.USER] ?: return emptyList() + + val result = mutableListOf() + val (invalidGroups, invalidPipelines, invalidRepertoryIds) = listInvalidAuthorizationsAfterOperatedGroups( projectCode = projectCode, - iamGroupIds = invalidGroups.map { it.toString() } + iamGroupIds = groupIdsDirectlyJoined, + memberId = previewConditionReq.targetMember.id ) - val result = mutableListOf() - - if (resourceType2CountOfGroup.isNotEmpty()) { + if (batchOperateType == BatchOperateType.REMOVE) { + // 只有一个成员的管理员组 + val uniqueManagerGroups = authResourceGroupMemberDao.listProjectUniqueManagerGroups( + dslContext = dslContext, + projectCode = projectCode, + iamGroupIds = groupIdsDirectlyJoined + ) + val needToHandoverGroupIds = invalidGroups.union(uniqueManagerGroups).map { it.toString() } + val resourceType2CountOfGroup = authResourceGroupDao.getResourceType2Count( + dslContext = dslContext, + projectCode = projectCode, + iamGroupIds = needToHandoverGroupIds + ) + if (resourceType2CountOfGroup.isNotEmpty()) { + result.addAll( + rbacCacheService.convertResourceType2Count( + resourceType2Count = resourceType2CountOfGroup, + type = HandoverType.GROUP + ) + ) + } + } + if (invalidPipelines.isNotEmpty()) { result.addAll( rbacCacheService.convertResourceType2Count( - resourceType2Count = resourceType2CountOfGroup, - type = HandoverType.GROUP + resourceType2Count = mapOf(ResourceTypeId.PIPELINE to invalidPipelines.size.toLong()), + type = HandoverType.AUTHORIZATION ) ) } - if (invalidPipelines.isNotEmpty()) { + if (invalidRepertoryIds.isNotEmpty()) { result.addAll( rbacCacheService.convertResourceType2Count( - resourceType2Count = mapOf(ResourceTypeId.PIPELINE to invalidPipelines.size.toLong()), + resourceType2Count = mapOf(ResourceTypeId.REPERTORY to invalidRepertoryIds.size.toLong()), type = HandoverType.AUTHORIZATION ) ) @@ -1553,23 +1756,30 @@ class RbacPermissionManageFacadeServiceImpl( } } - private fun listAuthorizationsOfHandoverPreview( - queryReq: HandoverDetailsQueryReq - ): SQLPage { - val projectCode = queryReq.projectCode!! - val iamGroupIds = queryReq.iamGroupIds!! - val memberId = queryReq.memberId!! - val invalidPipelines = listInvalidAuthorizationsAfterOperatedGroups( + private fun listAuthorizationsOfHandoverPreview(queryReq: HandoverDetailsQueryReq): SQLPage { + val projectCode = queryReq.projectCode + val previewConditionReq = queryReq.previewConditionReq!! + val groupIdsDirectlyJoined = getGroupIdsByGroupMemberCondition( projectCode = projectCode, - iamGroupIds = iamGroupIds, - memberId = memberId - ).invalidAuthorizations + commonCondition = previewConditionReq + )[MemberType.USER] ?: return SQLPage(0, emptyList()) + val (invalidGroups, invalidPipelines, invalidRepertoryIds) = listInvalidAuthorizationsAfterOperatedGroups( + projectCode = projectCode, + iamGroupIds = groupIdsDirectlyJoined, + memberId = previewConditionReq.targetMember.id + ) + + val invalidResources = if (queryReq.resourceType == ResourceTypeId.PIPELINE) { + invalidPipelines + } else { + invalidRepertoryIds + } val records = authorizationDao.list( dslContext = dslContext, condition = ResourceAuthorizationConditionRequest( projectCode = projectCode, - resourceType = ResourceTypeId.PIPELINE, - filterResourceCodes = invalidPipelines, + resourceType = queryReq.resourceType, + filterResourceCodes = invalidResources, page = queryReq.page, pageSize = queryReq.pageSize ) @@ -1581,7 +1791,7 @@ class RbacPermissionManageFacadeServiceImpl( handoverFrom = it.handoverFrom ) } - return SQLPage(count = invalidPipelines.size.toLong(), records = records) + return SQLPage(count = invalidResources.size.toLong(), records = records) } override fun listGroupsOfHandover(queryReq: HandoverDetailsQueryReq): SQLPage { @@ -1594,21 +1804,30 @@ class RbacPermissionManageFacadeServiceImpl( } private fun listGroupsOfHandoverPreview(queryReq: HandoverDetailsQueryReq): SQLPage { - val projectCode = queryReq.projectCode!! - val iamGroupIds = queryReq.iamGroupIds!! - val memberId = queryReq.memberId!! + val projectCode = queryReq.projectCode + val previewConditionReq = queryReq.previewConditionReq!! + val convertPageSizeToSQLLimit = PageUtil.convertPageSizeToSQLLimit(queryReq.page, queryReq.pageSize) + val groupIdsDirectlyJoined = getGroupIdsByGroupMemberCondition( + projectCode = projectCode, + commonCondition = previewConditionReq + )[MemberType.USER] ?: return SQLPage(0, emptyList()) val invalidGroupIds = listInvalidAuthorizationsAfterOperatedGroups( projectCode = projectCode, - iamGroupIds = iamGroupIds, - memberId = memberId + iamGroupIds = groupIdsDirectlyJoined, + memberId = previewConditionReq.targetMember.id ).invalidGroupIds - val convertPageSizeToSQLLimit = PageUtil.convertPageSizeToSQLLimit(queryReq.page, queryReq.pageSize) - + // 只有一个成员的管理员组 + val uniqueManagerGroups = authResourceGroupMemberDao.listProjectUniqueManagerGroups( + dslContext = dslContext, + projectCode = projectCode, + iamGroupIds = groupIdsDirectlyJoined + ) + val needToHandoverGroupIds = invalidGroupIds.union(uniqueManagerGroups).map { it.toString() } val records = authResourceGroupDao.listGroupByResourceType( dslContext = dslContext, projectCode = projectCode, resourceType = queryReq.resourceType, - iamGroupIds = invalidGroupIds.map { it.toString() }, + iamGroupIds = needToHandoverGroupIds, offset = convertPageSizeToSQLLimit.offset, limit = convertPageSizeToSQLLimit.limit ).map { diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionHandoverApplicationService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionHandoverApplicationService.kt index cb82750990d..fca71c0f59b 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionHandoverApplicationService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionHandoverApplicationService.kt @@ -59,4 +59,12 @@ class SamplePermissionHandoverApplicationService : PermissionHandoverApplication ): List { return emptyList() } + + override fun listMemberHandoverDetails( + projectCode: String, + memberId: String, + handoverType: HandoverType + ): List { + return emptyList() + } } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthHandoverResourceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthHandoverResourceImpl.kt index b55573f6f30..f78881e72fb 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthHandoverResourceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthHandoverResourceImpl.kt @@ -51,7 +51,7 @@ class UserAuthHandoverResourceImpl( userId: String, queryRequest: HandoverOverviewQueryReq ): Result> { - if (userId != queryRequest.memberID) { + if (userId != queryRequest.memberId) { throw PermissionForbiddenException( message = "You have not permission to view other people's handover details!" ) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationService.kt index 45331886a48..22213a782ad 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationService.kt @@ -145,4 +145,12 @@ interface PermissionAuthorizationService { projectCode: String, condition: ResetAllResourceAuthorizationReq ): List + + fun checkRepertoryAuthorizationsHanover( + operator: String, + projectCode: String, + repertoryIds: List, + handoverFrom: String, + handoverTo: String + ) } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt index 76e0af87e98..1beb2b2afdc 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt @@ -17,6 +17,7 @@ import com.tencent.devops.common.api.exception.ErrorCodeException import com.tencent.devops.common.api.model.SQLPage import com.tencent.devops.common.auth.api.AuthPermission import com.tencent.devops.common.auth.api.AuthResourceType +import com.tencent.devops.common.auth.api.ResourceTypeId import com.tencent.devops.common.auth.api.pojo.ResetAllResourceAuthorizationReq import com.tencent.devops.common.auth.api.pojo.ResourceAuthorizationConditionRequest import com.tencent.devops.common.auth.api.pojo.ResourceAuthorizationDTO @@ -324,6 +325,35 @@ class PermissionAuthorizationServiceImpl( return result } + override fun checkRepertoryAuthorizationsHanover( + operator: String, + projectCode: String, + repertoryIds: List, + handoverFrom: String, + handoverTo: String + ) { + val canHandoverRepertory = resetResourceAuthorizationByResourceType( + operator = operator, + projectCode = projectCode, + condition = ResourceAuthorizationHandoverConditionRequest( + projectCode = projectCode, + resourceType = ResourceTypeId.REPERTORY, + fullSelection = true, + filterResourceCodes = repertoryIds, + handoverChannel = HandoverChannelCode.MANAGER, + handoverFrom = handoverFrom, + handoverTo = handoverTo, + checkPermission = false, + preCheck = true + ) + )[ResourceAuthorizationHandoverStatus.FAILED].isNullOrEmpty() + if (!canHandoverRepertory) { + throw ErrorCodeException( + errorCode = ERROR_HANDOVER_AUTHORIZATION + ) + } + } + private fun addHandoverFromCnName( resourceAuthorizationList: List ) { diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionHandoverApplicationService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionHandoverApplicationService.kt index d79c0b6212b..23d5153c825 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionHandoverApplicationService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionHandoverApplicationService.kt @@ -53,6 +53,15 @@ interface PermissionHandoverApplicationService { handoverType: HandoverType? = null ): List + /** + * 获取用户在项目下正在交接的组/授权 + * */ + fun listMemberHandoverDetails( + projectCode: String, + memberId: String, + handoverType: HandoverType + ): List + /** * 获取交接单中授权相关 * */ diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionManageFacadeService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionManageFacadeService.kt index 2ed38675be0..6db0cca2a12 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionManageFacadeService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionManageFacadeService.kt @@ -106,10 +106,11 @@ interface PermissionManageFacadeService { ): SQLPage /** - * 为了避免流水线代持人权限失效,需要对用户退出/交接用户组进行检查。 + * 为了避免流水线代持人/代码库oauth权限失效,需要对用户退出/交接用户组进行检查。 * 返回结果: * 1、引起代持人权限失效的用户组。 * 2、引起代持人权限失效的流水线。 + * 3、引起代码库oauth失效的代码库(当用户操作完组后,不再拥有项目访问权限时,会代码库oauth引起失效) **/ fun listInvalidAuthorizationsAfterOperatedGroups( projectCode: String, diff --git a/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/ActionId.kt b/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/ActionId.kt index 835cf51999a..b331faa1d4b 100644 --- a/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/ActionId.kt +++ b/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/ActionId.kt @@ -2,6 +2,7 @@ package com.tencent.devops.common.auth.api object ActionId { // 项目 + const val PROJECT_VISIT = "project_visit" const val PROJECT_CREATE = "project_create" const val PROJECT_EDIT = "project_edit" const val PROJECT_ENABLE = "project_enable" From 5342b9fa0ba8cb12d9e9045b92ff966086b53d69 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Mon, 2 Dec 2024 11:57:05 +0800 Subject: [PATCH 21/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/user/UserAuthAuthorizationResource.kt | 4 ++++ .../pojo/vo/BatchOperateGroupMemberCheckVo.kt | 12 +++++----- .../RbacPermissionManageFacadeServiceImpl.kt | 24 ++++++++++++++----- .../user/UserAuthAuthorizationResourceImpl.kt | 13 ++++++++-- .../service/PermissionAuthorizationService.kt | 7 +++++- .../PermissionAuthorizationServiceImpl.kt | 20 ++++++++++++++-- .../api/pojo/ResourceAuthorizationResponse.kt | 4 +++- 7 files changed, 66 insertions(+), 18 deletions(-) diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthAuthorizationResource.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthAuthorizationResource.kt index 0f672983e72..fac3082e3aa 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthAuthorizationResource.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserAuthAuthorizationResource.kt @@ -28,6 +28,7 @@ package com.tencent.devops.auth.api.user +import com.tencent.devops.auth.pojo.enum.OperateChannel import com.tencent.devops.auth.pojo.vo.ResourceTypeInfoVo import com.tencent.devops.common.api.auth.AUTH_HEADER_USER_ID import com.tencent.devops.common.api.auth.AUTH_HEADER_USER_ID_DEFAULT_VALUE @@ -68,6 +69,9 @@ interface UserAuthAuthorizationResource { @Parameter(description = "项目ID", required = true) @PathParam("projectId") projectId: String, + @Parameter(description = "操作渠道", required = true) + @QueryParam("operateChannel") + operateChannel: OperateChannel?, @Parameter(description = "查询条件", required = true) condition: ResourceAuthorizationConditionRequest ): Result> diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/BatchOperateGroupMemberCheckVo.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/BatchOperateGroupMemberCheckVo.kt index 8b9257db5fb..baa89c70154 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/BatchOperateGroupMemberCheckVo.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/vo/BatchOperateGroupMemberCheckVo.kt @@ -7,15 +7,15 @@ data class BatchOperateGroupMemberCheckVo( @get:Schema(title = "总数") val totalCount: Int, @get:Schema(title = "可操作的数量") - val operableCount: Int? = null, + val operableCount: Int? = 0, @get:Schema(title = "无法操作的数量") - val inoperableCount: Int? = null, + val inoperableCount: Int? = 0, @get:Schema(title = "唯一管理员组的数量") - val uniqueManagerCount: Int? = null, + val uniqueManagerCount: Int? = 0, @get:Schema(title = "导致代持人失效的用户组") - val invalidGroupCount: Int? = null, + val invalidGroupCount: Int? = 0, @get:Schema(title = "无效的流水线授权数量") - val invalidPipelineAuthorizationCount: Int? = null, + val invalidPipelineAuthorizationCount: Int? = 0, @get:Schema(title = "无效的代码库授权数量") - val invalidRepositoryAuthorizationCount: Int? = null + val invalidRepositoryAuthorizationCount: Int? = 0 ) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt index ca40e840c95..39291f30e8f 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt @@ -150,8 +150,16 @@ class RbacPermissionManageFacadeServiceImpl( resourceGroupMembers = resourceGroupMembers, operateChannel = operateChannel ) - // 获取用户正在交接的用户组 - + // 获取用户正在交接的用户组,仅用于个人视角 + val groupsBeingHandover = if (operateChannel == OperateChannel.PERSONAL) { + permissionHandoverApplicationService.listMemberHandoverDetails( + projectCode = projectId, + memberId = memberId, + handoverType = HandoverType.GROUP + ).map { it.itemId.toInt() }.distinct() + } else { + emptyList() + } val records = mutableListOf() resourceGroupMembers.forEach { val resourceGroup = resourceGroupMap[it.iamGroupId.toString()]!! @@ -162,7 +170,8 @@ class RbacPermissionManageFacadeServiceImpl( groupMemberDetail = groupMemberDetail, uniqueManagerGroups = uniqueManagerGroups, authResourceGroupMember = it, - operateChannel = operateChannel + operateChannel = operateChannel, + groupsBeingHandover = groupsBeingHandover ) ) } @@ -245,7 +254,8 @@ class RbacPermissionManageFacadeServiceImpl( groupMemberDetail: MemberGroupDetailsResponse?, uniqueManagerGroups: List, authResourceGroupMember: AuthResourceGroupMember, - operateChannel: OperateChannel? + operateChannel: OperateChannel?, + groupsBeingHandover: List ): GroupDetailsInfoVo { // 如果用户离职,查询权限中心接口会报错,因此从数据库直接取数据,而不去调用权限中心接口。 val (expiredAt, joinedTime) = if (groupMemberDetail != null) { @@ -260,11 +270,12 @@ class RbacPermissionManageFacadeServiceImpl( ) } val between = expiredAt - System.currentTimeMillis() + val groupId = resourceGroup.relationId.toInt() return GroupDetailsInfoVo( resourceCode = resourceGroup.resourceCode, resourceName = resourceGroup.resourceName, resourceType = resourceGroup.resourceType, - groupId = resourceGroup.relationId.toInt(), + groupId = groupId, groupName = resourceGroup.groupName, groupDesc = resourceGroup.description, expiredAtDisplay = when { @@ -307,7 +318,8 @@ class RbacPermissionManageFacadeServiceImpl( else -> JoinedType.DIRECT }, - operator = "" + operator = "", + beingHandedOver = groupsBeingHandover.contains(groupId) ) } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthAuthorizationResourceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthAuthorizationResourceImpl.kt index e4c5ed68aa4..f3b3ab959b9 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthAuthorizationResourceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthAuthorizationResourceImpl.kt @@ -1,8 +1,10 @@ package com.tencent.devops.auth.resources.user import com.tencent.devops.auth.api.user.UserAuthAuthorizationResource +import com.tencent.devops.auth.pojo.enum.OperateChannel import com.tencent.devops.auth.pojo.vo.ResourceTypeInfoVo import com.tencent.devops.auth.service.PermissionAuthorizationService +import com.tencent.devops.auth.service.iam.PermissionResourceValidateService import com.tencent.devops.common.api.model.SQLPage import com.tencent.devops.common.api.pojo.Result import com.tencent.devops.common.auth.api.BkManagerCheck @@ -16,14 +18,21 @@ import com.tencent.devops.common.web.RestResource @RestResource class UserAuthAuthorizationResourceImpl( - val permissionAuthorizationService: PermissionAuthorizationService + val permissionAuthorizationService: PermissionAuthorizationService, + val permissionResourceValidateService: PermissionResourceValidateService ) : UserAuthAuthorizationResource { - @BkManagerCheck override fun listResourceAuthorization( userId: String, projectId: String, + operateChannel: OperateChannel?, condition: ResourceAuthorizationConditionRequest ): Result> { + permissionResourceValidateService.validateUserProjectPermissionByChannel( + userId = userId, + projectCode = projectId, + operateChannel = operateChannel ?: OperateChannel.MANAGER, + targetMemberId = if (operateChannel == OperateChannel.PERSONAL) condition.handoverFrom!! else userId + ) return Result( permissionAuthorizationService.listResourceAuthorizations( condition = condition diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationService.kt index 22213a782ad..746b974aa23 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationService.kt @@ -27,6 +27,7 @@ package com.tencent.devops.auth.service +import com.tencent.devops.auth.pojo.enum.OperateChannel import com.tencent.devops.auth.pojo.vo.ResourceTypeInfoVo import com.tencent.devops.common.api.model.SQLPage import com.tencent.devops.common.auth.api.pojo.ResetAllResourceAuthorizationReq @@ -77,7 +78,8 @@ interface PermissionAuthorizationService { * 获取项目资源授予记录--根据条件 */ fun listResourceAuthorizations( - condition: ResourceAuthorizationConditionRequest + condition: ResourceAuthorizationConditionRequest, + operateChannel: OperateChannel? = OperateChannel.MANAGER, ): SQLPage /** @@ -146,6 +148,9 @@ interface PermissionAuthorizationService { condition: ResetAllResourceAuthorizationReq ): List + /** + * 检查交接人是否有代码库授权权限 + */ fun checkRepertoryAuthorizationsHanover( operator: String, projectCode: String, diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt index 1beb2b2afdc..3d0db184cad 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt @@ -9,6 +9,7 @@ import com.tencent.devops.auth.pojo.dto.HandoverDetailDTO import com.tencent.devops.auth.pojo.dto.HandoverOverviewCreateDTO import com.tencent.devops.auth.pojo.enum.HandoverStatus import com.tencent.devops.auth.pojo.enum.HandoverType +import com.tencent.devops.auth.pojo.enum.OperateChannel import com.tencent.devops.auth.pojo.vo.ResourceTypeInfoVo import com.tencent.devops.auth.service.iam.PermissionHandoverApplicationService import com.tencent.devops.auth.service.iam.PermissionResourceValidateService @@ -129,13 +130,28 @@ class PermissionAuthorizationServiceImpl( } override fun listResourceAuthorizations( - condition: ResourceAuthorizationConditionRequest + condition: ResourceAuthorizationConditionRequest, + operateChannel: OperateChannel? ): SQLPage { logger.info("list resource authorizations:$condition") + // 获取用户正在交接的授权,仅用于个人视角 + val beingHandoverMap = if (operateChannel == OperateChannel.PERSONAL) { + permissionHandoverApplicationService.listMemberHandoverDetails( + projectCode = condition.projectCode, + memberId = condition.handoverFrom!!, + handoverType = HandoverType.AUTHORIZATION + ) + } else { + emptyList() + }.associateBy { it.resourceType to it.itemId } val record = authAuthorizationDao.list( dslContext = dslContext, condition = condition - ) + ).map { authRecord -> + authRecord.copy( + beingHandover = beingHandoverMap.containsKey(authRecord.resourceType to authRecord.resourceCode) + ) + } val count = authAuthorizationDao.count( dslContext = dslContext, condition = condition diff --git a/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationResponse.kt b/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationResponse.kt index f38136c3bc4..d2b8139054d 100644 --- a/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationResponse.kt +++ b/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationResponse.kt @@ -22,5 +22,7 @@ data class ResourceAuthorizationResponse( @get:Schema(title = "授予人中文名称") val handoverFromCnName: String? = null, @get:Schema(title = "是否有执行权限") - val executePermission: Boolean? = null + val executePermission: Boolean? = null, + @get:Schema(title = "是否正在交接,用于我的授权界面") + val beingHandover: Boolean? = null ) From 4fbdb4c91382915ecca3333b481ba36692cc911a Mon Sep 17 00:00:00 2001 From: greysonfang Date: Tue, 3 Dec 2024 20:47:47 +0800 Subject: [PATCH 22/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../devops/auth/pojo/dto/HandoverDetailDTO.kt | 4 +- ...bacPermissionHandoverApplicationService.kt | 13 +++-- ...plePermissionHandoverApplicationService.kt | 3 +- .../PermissionAuthorizationServiceImpl.kt | 57 ++++++++++++------- .../PermissionHandoverApplicationService.kt | 3 +- .../ResourceAuthorizationConditionRequest.kt | 6 +- ...ceAuthorizationHandoverConditionRequest.kt | 4 +- .../api/pojo/ResourceAuthorizationResponse.kt | 4 +- 8 files changed, 60 insertions(+), 34 deletions(-) diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/dto/HandoverDetailDTO.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/dto/HandoverDetailDTO.kt index 19e842c289d..84682f8debc 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/dto/HandoverDetailDTO.kt +++ b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/dto/HandoverDetailDTO.kt @@ -14,5 +14,7 @@ data class HandoverDetailDTO( @get:Schema(title = "组/授权资源关联的资源类型") val resourceType: String, @get:Schema(title = "交接类型") - val handoverType: HandoverType + val handoverType: HandoverType, + @get:Schema(title = "审批人") + var approver: String? = null ) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverApplicationService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverApplicationService.kt index 40f58fb120d..f2d7d8a5c5f 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverApplicationService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionHandoverApplicationService.kt @@ -263,23 +263,26 @@ class RbacPermissionHandoverApplicationService( override fun listMemberHandoverDetails( projectCode: String, memberId: String, - handoverType: HandoverType + handoverType: HandoverType, + resourceType: String? ): List { - val flowNos = listHandoverOverviews( + val handoverOverviews = listHandoverOverviews( queryRequest = HandoverOverviewQueryReq( memberId = memberId, projectCode = projectCode, applicant = memberId, handoverStatus = HandoverStatus.PENDING ) - ).records.map { it.flowNo } + ).records + val flowNos = handoverOverviews.map { it.flowNo } + val flowNo2Approver = handoverOverviews.associate { Pair(it.flowNo, it.approver) } return handoverDetailDao.list( dslContext = dslContext, projectCode = projectCode, flowNos = flowNos, - resourceType = null, + resourceType = resourceType, handoverType = handoverType - ) + ).map { it.copy(approver = flowNo2Approver[it.flowNo]) } } companion object { diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionHandoverApplicationService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionHandoverApplicationService.kt index fca71c0f59b..7f147e9cde0 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionHandoverApplicationService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/sample/service/SamplePermissionHandoverApplicationService.kt @@ -63,7 +63,8 @@ class SamplePermissionHandoverApplicationService : PermissionHandoverApplication override fun listMemberHandoverDetails( projectCode: String, memberId: String, - handoverType: HandoverType + handoverType: HandoverType, + resourceType: String? ): List { return emptyList() } diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt index 3d0db184cad..6b3c0fe4a20 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt @@ -133,33 +133,48 @@ class PermissionAuthorizationServiceImpl( condition: ResourceAuthorizationConditionRequest, operateChannel: OperateChannel? ): SQLPage { - logger.info("list resource authorizations:$condition") - // 获取用户正在交接的授权,仅用于个人视角 - val beingHandoverMap = if (operateChannel == OperateChannel.PERSONAL) { - permissionHandoverApplicationService.listMemberHandoverDetails( + logger.info("list resource authorizations:$condition|$operateChannel") + val (records, count) = if (operateChannel == OperateChannel.PERSONAL) { + val beingHandoverDetails = permissionHandoverApplicationService.listMemberHandoverDetails( projectCode = condition.projectCode, memberId = condition.handoverFrom!!, - handoverType = HandoverType.AUTHORIZATION + handoverType = HandoverType.AUTHORIZATION, + resourceType = condition.resourceType!! ) + val beingHandoverResourceCodes = beingHandoverDetails.map { it.itemId }.distinct() + val finalCondition = condition.apply { + when (this.queryHandover) { + true -> this.filterResourceCodes = beingHandoverResourceCodes + false -> this.excludeResourceCodes = beingHandoverResourceCodes + else -> {} + } + } + val records = authAuthorizationDao.list( + dslContext = dslContext, + condition = finalCondition + ).map { + it.copy( + beingHandover = beingHandoverResourceCodes.contains(it.resourceCode), + approver = beingHandoverDetails.find { details -> details.itemId == it.resourceCode }?.approver + ) + } + val count = authAuthorizationDao.count( + dslContext = dslContext, + condition = finalCondition + ) + Pair(records, count) } else { - emptyList() - }.associateBy { it.resourceType to it.itemId } - val record = authAuthorizationDao.list( - dslContext = dslContext, - condition = condition - ).map { authRecord -> - authRecord.copy( - beingHandover = beingHandoverMap.containsKey(authRecord.resourceType to authRecord.resourceCode) + val records = authAuthorizationDao.list( + dslContext = dslContext, + condition = condition ) + val count = authAuthorizationDao.count( + dslContext = dslContext, + condition = condition + ) + Pair(records, count) } - val count = authAuthorizationDao.count( - dslContext = dslContext, - condition = condition - ) - return SQLPage( - count = count.toLong(), - records = record - ) + return SQLPage(count = count.toLong(), records = records) } override fun listUserProjects(userId: String): List { diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionHandoverApplicationService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionHandoverApplicationService.kt index 23d5153c825..b4cad1299b5 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionHandoverApplicationService.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/iam/PermissionHandoverApplicationService.kt @@ -59,7 +59,8 @@ interface PermissionHandoverApplicationService { fun listMemberHandoverDetails( projectCode: String, memberId: String, - handoverType: HandoverType + handoverType: HandoverType, + resourceType: String? = null ): List /** diff --git a/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationConditionRequest.kt b/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationConditionRequest.kt index 05498e044d3..9ec5d746ead 100644 --- a/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationConditionRequest.kt +++ b/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationConditionRequest.kt @@ -13,15 +13,17 @@ open class ResourceAuthorizationConditionRequest( @get:Schema(title = "资源名称") open val resourceName: String? = null, @get:Schema(title = "过滤资源ID列表") - open val filterResourceCodes: List? = null, + open var filterResourceCodes: List? = null, @get:Schema(title = "排除资源ID列表") - open val excludeResourceCodes: List? = null, + open var excludeResourceCodes: List? = null, @get:Schema(title = "授予人") open val handoverFrom: String? = null, @get:Schema(title = "greaterThanHandoverTime") open val greaterThanHandoverTime: Long? = null, @get:Schema(title = "lessThanHandoverTime") open val lessThanHandoverTime: Long? = null, + @get:Schema(title = "是否查询交接中单据") + open val queryHandover: Boolean? = null, @Parameter(description = "第几页", required = false) open val page: Int? = null, @Parameter(description = "每页条数", required = false) diff --git a/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationHandoverConditionRequest.kt b/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationHandoverConditionRequest.kt index d8f4e1bdde0..633031a4fc8 100644 --- a/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationHandoverConditionRequest.kt +++ b/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationHandoverConditionRequest.kt @@ -13,9 +13,9 @@ data class ResourceAuthorizationHandoverConditionRequest( @get:Schema(title = "资源名称") override val resourceName: String? = null, @get:Schema(title = "过滤资源ID列表") - override val filterResourceCodes: List? = null, + override var filterResourceCodes: List? = null, @get:Schema(title = "排除资源ID列表") - override val excludeResourceCodes: List? = null, + override var excludeResourceCodes: List? = null, @get:Schema(title = "授予人") override val handoverFrom: String? = null, @get:Schema(title = "greaterThanHandoverTime") diff --git a/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationResponse.kt b/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationResponse.kt index d2b8139054d..179fc004daa 100644 --- a/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationResponse.kt +++ b/src/backend/ci/core/common/common-auth/common-auth-api/src/main/kotlin/com/tencent/devops/common/auth/api/pojo/ResourceAuthorizationResponse.kt @@ -24,5 +24,7 @@ data class ResourceAuthorizationResponse( @get:Schema(title = "是否有执行权限") val executePermission: Boolean? = null, @get:Schema(title = "是否正在交接,用于我的授权界面") - val beingHandover: Boolean? = null + val beingHandover: Boolean? = null, + @get:Schema(title = "交接审批人") + val approver: String? = null ) From 052b43176782cee71a5a658d0ecef0198ef09eb6 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Wed, 4 Dec 2024 09:59:43 +0800 Subject: [PATCH 23/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PermissionAuthorizationServiceImpl.kt | 62 ++++++++++--------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt index 6b3c0fe4a20..ba5b8e98bc5 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt @@ -134,7 +134,17 @@ class PermissionAuthorizationServiceImpl( operateChannel: OperateChannel? ): SQLPage { logger.info("list resource authorizations:$condition|$operateChannel") - val (records, count) = if (operateChannel == OperateChannel.PERSONAL) { + val (records, count) = if (operateChannel != OperateChannel.PERSONAL) { + val records = authAuthorizationDao.list( + dslContext = dslContext, + condition = condition + ) + val count = authAuthorizationDao.count( + dslContext = dslContext, + condition = condition + ) + Pair(records, count) + } else { val beingHandoverDetails = permissionHandoverApplicationService.listMemberHandoverDetails( projectCode = condition.projectCode, memberId = condition.handoverFrom!!, @@ -142,37 +152,31 @@ class PermissionAuthorizationServiceImpl( resourceType = condition.resourceType!! ) val beingHandoverResourceCodes = beingHandoverDetails.map { it.itemId }.distinct() - val finalCondition = condition.apply { - when (this.queryHandover) { - true -> this.filterResourceCodes = beingHandoverResourceCodes - false -> this.excludeResourceCodes = beingHandoverResourceCodes - else -> {} + if (condition.queryHandover == true && beingHandoverResourceCodes.isEmpty()) { + Pair(emptyList(), 0L) + } else { + val finalCondition = condition.apply { + when (this.queryHandover) { + true -> this.filterResourceCodes = beingHandoverResourceCodes + false -> this.excludeResourceCodes = beingHandoverResourceCodes + else -> {} + } } - } - val records = authAuthorizationDao.list( - dslContext = dslContext, - condition = finalCondition - ).map { - it.copy( - beingHandover = beingHandoverResourceCodes.contains(it.resourceCode), - approver = beingHandoverDetails.find { details -> details.itemId == it.resourceCode }?.approver + val records = authAuthorizationDao.list( + dslContext = dslContext, + condition = finalCondition + ).map { + it.copy( + beingHandover = beingHandoverResourceCodes.contains(it.resourceCode), + approver = beingHandoverDetails.find { details -> details.itemId == it.resourceCode }?.approver + ) + } + val count = authAuthorizationDao.count( + dslContext = dslContext, + condition = finalCondition ) + Pair(records, count) } - val count = authAuthorizationDao.count( - dslContext = dslContext, - condition = finalCondition - ) - Pair(records, count) - } else { - val records = authAuthorizationDao.list( - dslContext = dslContext, - condition = condition - ) - val count = authAuthorizationDao.count( - dslContext = dslContext, - condition = condition - ) - Pair(records, count) } return SQLPage(count = count.toLong(), records = records) } From c51b0b68a17269e9e5c9d69a3918c6d549a101a5 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Wed, 4 Dec 2024 10:55:46 +0800 Subject: [PATCH 24/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/resources/user/UserAuthAuthorizationResourceImpl.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthAuthorizationResourceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthAuthorizationResourceImpl.kt index f3b3ab959b9..0315323b980 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthAuthorizationResourceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/user/UserAuthAuthorizationResourceImpl.kt @@ -35,7 +35,8 @@ class UserAuthAuthorizationResourceImpl( ) return Result( permissionAuthorizationService.listResourceAuthorizations( - condition = condition + condition = condition, + operateChannel = operateChannel ) ) } From 2cc000af7195d05da9e80e1644c345d12e990877 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Wed, 4 Dec 2024 11:17:32 +0800 Subject: [PATCH 25/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PermissionAuthorizationServiceImpl.kt | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt index ba5b8e98bc5..3d8b2405209 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/PermissionAuthorizationServiceImpl.kt @@ -278,18 +278,28 @@ class PermissionAuthorizationServiceImpl( projectCode: String, condition: ResourceAuthorizationHandoverConditionRequest ): Boolean { + val beingHandoverDetails = permissionHandoverApplicationService.listMemberHandoverDetails( + projectCode = condition.projectCode, + memberId = condition.handoverFrom!!, + handoverType = HandoverType.AUTHORIZATION, + resourceType = condition.resourceType + ).map { it.itemId }.distinct() + + val finalCondition = condition.copy( + preCheck = true, + checkPermission = false, + excludeResourceCodes = beingHandoverDetails + ) + val handoverResult = resetResourceAuthorizationByResourceType( operator = operator, projectCode = projectCode, - condition = condition.copy( - preCheck = true, - checkPermission = false - ) + condition = finalCondition ) if (!handoverResult[ResourceAuthorizationHandoverStatus.FAILED].isNullOrEmpty()) { throw ErrorCodeException(errorCode = ERROR_HANDOVER_AUTHORIZATION) } - val resourceAuthorizationList = getResourceAuthorizationList(condition = condition) + val resourceAuthorizationList = getResourceAuthorizationList(condition = finalCondition) val authorizationCount = resourceAuthorizationList.size val flowNo = permissionHandoverApplicationService.generateFlowNo() val title = permissionHandoverApplicationService.generateTitle( From 7e2379eb0624608a39c87e32e855190f0dca1616 Mon Sep 17 00:00:00 2001 From: greysonfang Date: Wed, 4 Dec 2024 15:53:50 +0800 Subject: [PATCH 26/26] =?UTF-8?q?feat=EF=BC=9A=E7=94=A8=E6=88=B7=E4=B8=AA?= =?UTF-8?q?=E4=BA=BA=E8=A7=86=E8=A7=92=20=E6=9D=83=E9=99=90=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E4=BC=98=E5=8C=96=20#11138?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rbac/service/RbacPermissionManageFacadeServiceImpl.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt index 39291f30e8f..30c8513c8c4 100644 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt +++ b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/provider/rbac/service/RbacPermissionManageFacadeServiceImpl.kt @@ -319,7 +319,8 @@ class RbacPermissionManageFacadeServiceImpl( else -> JoinedType.DIRECT }, operator = "", - beingHandedOver = groupsBeingHandover.contains(groupId) + beingHandedOver = authResourceGroupMember.memberType == MemberType.USER.type + && groupsBeingHandover.contains(groupId) ) }