diff --git a/scripts/build-images.sh b/scripts/build-images.sh index e3613286b8..32f96fd21e 100755 --- a/scripts/build-images.sh +++ b/scripts/build-images.sh @@ -12,6 +12,7 @@ ALL=1 GATEWAY=0 BACKEND=0 INIT=0 +INIT_RBAC=0 VERSION=latest PUSH=0 ALL_IN_ONE=0 @@ -41,6 +42,7 @@ usage () { [ --all-in-one [可选] 打包all in one镜像] [ --slim-package-path [可选] slim包路径,打包all in one镜像需要] [ --init [可选] 打包init镜像 ] + [ --init-rbac [可选] 打包init-rbac镜像 ] [ -v, --version [可选] 镜像版本tag, 默认latest ] [ -p, --push [可选] 推送镜像到docker远程仓库,默认不推送 ] [ -l, --latest [可选] 是否更新并推送latest tag ] @@ -91,6 +93,10 @@ while (( $# > 0 )); do ALL=0 INIT=1 ;; + --init-rbac ) + ALL=0 + INIT_RBAC=1 + ;; -v | --version ) shift VERSION=$1 @@ -213,4 +219,16 @@ if [[ $ALL -eq 1 || $INIT -eq 1 ]] ; then fi fi +# 构建init-rbac镜像 +if [[ $ALL -eq 1 || $INIT_RBAC -eq 1 ]] ; then + log "构建init-rbac镜像..." + rm -rf $tmp_dir/* + mkdir -p $tmp_dir/support-files/bkiam + cp -rf $ROOT_DIR/support-files/bkiam/* $tmp_dir/support-files/bkiam + docker build -f init/init-rbac.Dockerfile -t $REGISTRY/bkrepo-init-rbac:$VERSION $tmp_dir --no-cache --network=host + if [[ $PUSH -eq 1 ]] ; then + docker push $REGISTRY/bkrepo-init-rbac:$VERSION + fi +fi + echo "BUILD SUCCESSFUL!" diff --git a/src/backend/auth/api-auth/build.gradle.kts b/src/backend/auth/api-auth/build.gradle.kts index aea9561284..f32a38f9c9 100644 --- a/src/backend/auth/api-auth/build.gradle.kts +++ b/src/backend/auth/api-auth/build.gradle.kts @@ -29,7 +29,6 @@ * SOFTWARE. */ dependencies { - api(fileTree(mapOf("dir" to "lib", "include" to listOf("*.jar")))) implementation(project(":common:common-api")) api(project(":common:common-operate:operate-annotation")) compileOnly("org.springframework.cloud:spring-cloud-openfeign-core") diff --git a/src/backend/auth/api-auth/lib/iam-sdk-1.0.0.jar b/src/backend/auth/api-auth/lib/iam-sdk-1.0.0.jar deleted file mode 100644 index 9c4f95f271..0000000000 Binary files a/src/backend/auth/api-auth/lib/iam-sdk-1.0.0.jar and /dev/null differ diff --git a/src/backend/auth/api-auth/src/main/kotlin/com/tencent/bkrepo/auth/api/ServiceBkiamV3ResourceClient.kt b/src/backend/auth/api-auth/src/main/kotlin/com/tencent/bkrepo/auth/api/ServiceBkiamV3ResourceClient.kt new file mode 100644 index 0000000000..0a36e5c391 --- /dev/null +++ b/src/backend/auth/api-auth/src/main/kotlin/com/tencent/bkrepo/auth/api/ServiceBkiamV3ResourceClient.kt @@ -0,0 +1,89 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.api + +import com.tencent.bkrepo.auth.constant.AUTH_SERVICE_BKIAMV3_PREFIX +import com.tencent.bkrepo.common.api.constant.AUTH_SERVICE_NAME +import com.tencent.bkrepo.common.api.pojo.Response +import io.swagger.annotations.Api +import io.swagger.annotations.ApiOperation +import io.swagger.annotations.ApiParam +import org.springframework.cloud.openfeign.FeignClient +import org.springframework.context.annotation.Primary +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam + +@Api(tags = ["SERVICE_BKIAMV3"], description = "蓝鲸权限v3接口") +@Primary +@FeignClient(AUTH_SERVICE_NAME, contextId = "ServiceBkiamV3Resource") +@RequestMapping(AUTH_SERVICE_BKIAMV3_PREFIX) +interface ServiceBkiamV3ResourceClient { + @ApiOperation("创建项目管理员") + @PostMapping("/create/project/manage/{projectId}") + fun createProjectManage( + @ApiParam(value = "用户id") + @RequestParam userId: String, + @ApiParam(value = "项目名称") + @PathVariable projectId: String + ): Response + + @ApiOperation("创建2级仓库管理员") + @PostMapping("/create/repo/manage/{projectId}/{repoName}") + fun createRepoManage( + @ApiParam(value = "用户id") + @RequestParam userId: String, + @ApiParam(value = "项目名称") + @PathVariable projectId: String, + @ApiParam(value = "仓库名称") + @PathVariable repoName: String + ): Response + + @ApiOperation("删除仓库相关用户组") + @DeleteMapping("/delete/repo/manage/{projectId}/{repoName}") + fun deleteRepoManageGroup( + @ApiParam(value = "用户id") + @RequestParam userId: String, + @ApiParam(value = "项目名称") + @PathVariable projectId: String, + @ApiParam(value = "仓库名称") + @PathVariable repoName: String + ): Response + + + @ApiOperation("检查项目默认的rbac项目组是否已经存在") + @PostMapping("/rbac/group/check") + fun getExistRbacDefaultGroupProjectIds( + @ApiParam(value = "项目ID列表") + @RequestBody projectIdList: List = emptyList() + ): Response> + +} diff --git a/src/backend/auth/api-auth/src/main/kotlin/com/tencent/bkrepo/auth/constant/AuthConstants.kt b/src/backend/auth/api-auth/src/main/kotlin/com/tencent/bkrepo/auth/constant/AuthConstants.kt new file mode 100644 index 0000000000..c97cf38b1f --- /dev/null +++ b/src/backend/auth/api-auth/src/main/kotlin/com/tencent/bkrepo/auth/constant/AuthConstants.kt @@ -0,0 +1,41 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.constant + +const val AUTH_CONFIG_PREFIX = "auth" +const val AUTH_CONFIG_TYPE_NAME = "realm" +const val AUTH_CONFIG_TYPE_VALUE_DEVOPS = "devops" +const val AUTH_CONFIG_TYPE_VALUE_LOCAL = "local" +const val AUTH_CONFIG_TYPE_VALUE_BKIAMV3 = "bkiamv3" + +const val BKIAMV3_CHECK = "bkiamv3Check" + +const val CUSTOM = "custom" +const val PIPELINE = "pipeline" +const val REPORT = "report" +const val LOG = "log" \ No newline at end of file diff --git a/src/backend/auth/api-auth/src/main/kotlin/com/tencent/bkrepo/auth/constant/Constants.kt b/src/backend/auth/api-auth/src/main/kotlin/com/tencent/bkrepo/auth/constant/Constants.kt index c8d13577b3..436e2c7baa 100644 --- a/src/backend/auth/api-auth/src/main/kotlin/com/tencent/bkrepo/auth/constant/Constants.kt +++ b/src/backend/auth/api-auth/src/main/kotlin/com/tencent/bkrepo/auth/constant/Constants.kt @@ -73,6 +73,10 @@ const val AUTH_CLUSTER_PERMISSION_PREFIX = "/cluster/permission" const val AUTH_API_ROLE_PREFIX = "/api/role" const val AUTH_SERVICE_ROLE_PREFIX = "/service/role" + +const val AUTH_SERVICE_BKIAMV3_PREFIX = "/service/bkiamv3" + + const val AUTH_API_USER_PREFIX = "/api/user" const val AUTH_SERVICE_USER_PREFIX = "/service/user" const val AUTH_CLUSTER_USER_PREFIX = "/cluster/permission" @@ -99,6 +103,7 @@ const val AUTH_API_PERMISSION_USER_PREFIX = "api/permission/user" const val AUTH_API_USER_UPDATE_PREFIX = "api/user/update/info" const val AUTH_API_USER_DELETE_PREFIX = "api/user/delete" const val AUTH_API_USER_ASSET_USER_GROUP_PREFIX = "api/user/group" +const val AUTH_API_USER_BKIAMV3_PREFIX = "api/user/auth" const val AUTH_CLUSTER_TOKEN_INFO_PREFIX = "/cluster/temporary/token/info" const val AUTH_CLUSTER_TOKEN_DELETE_PREFIX = "/cluster/temporary/token/delete" diff --git a/src/backend/auth/api-auth/src/main/kotlin/com/tencent/bkrepo/auth/pojo/enums/ActionTypeMapping.kt b/src/backend/auth/api-auth/src/main/kotlin/com/tencent/bkrepo/auth/pojo/enums/ActionTypeMapping.kt new file mode 100644 index 0000000000..aac8521b6c --- /dev/null +++ b/src/backend/auth/api-auth/src/main/kotlin/com/tencent/bkrepo/auth/pojo/enums/ActionTypeMapping.kt @@ -0,0 +1,58 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.pojo.enums + +/** + * 权限中心v3 action映射关系 + */ +enum class ActionTypeMapping(val resType: String, val pAction: String) { + PROJECT_MANAGE(ResourceType.PROJECT.name, PermissionAction.MANAGE.name), + PROJECT_VIEW(ResourceType.PROJECT.name, PermissionAction.READ.name), + PROJECT_EDIT(ResourceType.PROJECT.name, PermissionAction.UPDATE.name), + REPO_CREATE(ResourceType.PROJECT.name, PermissionAction.WRITE.name), + REPO_MANAGE(ResourceType.REPO.name, PermissionAction.MANAGE.name), + REPO_VIEW(ResourceType.REPO.name, PermissionAction.READ.name), + REPO_EDIT(ResourceType.REPO.name, PermissionAction.UPDATE.name), + REPO_DELETE(ResourceType.REPO.name, PermissionAction.DELETE.name), + NODE_CREATE(ResourceType.REPO.name, PermissionAction.WRITE.name), + NODE_VIEW(ResourceType.NODE.name, PermissionAction.VIEW.name), + NODE_DOWNLOAD(ResourceType.NODE.name, PermissionAction.READ.name), + NODE_EDIT(ResourceType.NODE.name, PermissionAction.UPDATE.name), + NODE_WRITE(ResourceType.NODE.name, PermissionAction.WRITE.name), + NODE_DELETE(ResourceType.NODE.name, PermissionAction.DELETE.name); + + fun id() = this.name.toLowerCase() + + companion object { + + fun lookup(resType: String, pAction: String): ActionTypeMapping { + return values().find { it.resType == resType && it.pAction == pAction } + ?: throw IllegalArgumentException("No enum for resType $resType and pAction $pAction!") + } + } +} diff --git a/src/backend/auth/api-auth/src/main/kotlin/com/tencent/bkrepo/auth/pojo/enums/DefaultGroupType.kt b/src/backend/auth/api-auth/src/main/kotlin/com/tencent/bkrepo/auth/pojo/enums/DefaultGroupType.kt new file mode 100644 index 0000000000..ff47382184 --- /dev/null +++ b/src/backend/auth/api-auth/src/main/kotlin/com/tencent/bkrepo/auth/pojo/enums/DefaultGroupType.kt @@ -0,0 +1,62 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.pojo.enums + +/** + * 默认用户组 + */ +enum class DefaultGroupType(val value: String, val displayName: String) { + PROJECT_MANAGER("project_manager", "项目管理组"), // 管理员 + PROJECT_UPLOAD_DELETE("project_upload_delete", "项目操作组"), // 上传下载删除权限 + PROJECT_DOWNLOAD("project_download", "项目访问组"), // 下载权限 + REPO_MANAGER("repo_manager", "仓库管理组"), // 管理员 + REPO_UPLOAD_DELETE("repo_upload_delete", "仓库操作组"), + REPO_DOWNLOAD("repo_download", "仓库访问组"); // 下载权限 + companion object { + fun get(value: String): DefaultGroupType { + values().forEach { + if (value == it.value) return it + } + throw IllegalArgumentException("No enum for constant $value") + } + + fun contains(value: String): Boolean { + values().forEach { + if (value == it.value) return true + } + return false + } + + fun containsDisplayName(displayName: String): Boolean { + values().forEach { + if (displayName == it.displayName) return true + } + return false + } + } +} diff --git a/src/backend/auth/api-auth/src/main/kotlin/com/tencent/bkrepo/auth/pojo/enums/DefaultGroupTypeAndActions.kt b/src/backend/auth/api-auth/src/main/kotlin/com/tencent/bkrepo/auth/pojo/enums/DefaultGroupTypeAndActions.kt new file mode 100644 index 0000000000..2c57ef8079 --- /dev/null +++ b/src/backend/auth/api-auth/src/main/kotlin/com/tencent/bkrepo/auth/pojo/enums/DefaultGroupTypeAndActions.kt @@ -0,0 +1,142 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.pojo.enums + +/** + * 默认用户组对应的操作权限 + */ +enum class DefaultGroupTypeAndActions(val value: String, val actions: Map>) { + PROJECT_MANAGER( + DefaultGroupType.PROJECT_MANAGER.value, + mapOf( + ResourceType.PROJECT.id() to listOf( + ActionTypeMapping.PROJECT_VIEW.id(), + ActionTypeMapping.PROJECT_EDIT.id(), + ActionTypeMapping.PROJECT_MANAGE.id(), + ActionTypeMapping.REPO_CREATE.id() + ), + ResourceType.REPO.id() to listOf( + ActionTypeMapping.REPO_MANAGE.id(), + ActionTypeMapping.REPO_EDIT.id(), + ActionTypeMapping.REPO_VIEW.id(), + ActionTypeMapping.REPO_DELETE.id(), + ActionTypeMapping.NODE_CREATE.id() + ), + ResourceType.NODE.id() to listOf( + ActionTypeMapping.NODE_DELETE.id(), + ActionTypeMapping.NODE_EDIT.id(), + ActionTypeMapping.NODE_WRITE.id(), + ActionTypeMapping.NODE_VIEW.id(), + ActionTypeMapping.NODE_DOWNLOAD.id() + ), + ) + ), + PROJECT_DOWNLOAD(DefaultGroupType.PROJECT_DOWNLOAD.value, + mapOf( + ResourceType.PROJECT.id() to listOf(ActionTypeMapping.PROJECT_VIEW.id()), + ResourceType.REPO.id() to listOf(ActionTypeMapping.REPO_VIEW.id()), + ResourceType.NODE.id() to listOf( + ActionTypeMapping.NODE_DOWNLOAD.id(), + ActionTypeMapping.NODE_VIEW.id() + ), + ) + ), + PROJECT_UPLOAD_DELETE(DefaultGroupType.PROJECT_UPLOAD_DELETE.value, + mapOf( + ResourceType.PROJECT.id() to listOf(ActionTypeMapping.PROJECT_VIEW.id()), + ResourceType.REPO.id() to listOf( + ActionTypeMapping.REPO_VIEW.id(), + ActionTypeMapping.NODE_CREATE.id() + ), + ResourceType.NODE.id() to listOf( + ActionTypeMapping.NODE_DELETE.id(), + ActionTypeMapping.NODE_EDIT.id(), + ActionTypeMapping.NODE_WRITE.id(), + ActionTypeMapping.NODE_VIEW.id(), + ActionTypeMapping.NODE_DOWNLOAD.id() + ) + ) + ), + REPO_MANAGER(DefaultGroupType.REPO_MANAGER.value, + mapOf( + ResourceType.PROJECT.id() to listOf(ActionTypeMapping.PROJECT_VIEW.id()), + ResourceType.REPO.id() to listOf( + ActionTypeMapping.REPO_MANAGE.id(), + ActionTypeMapping.REPO_EDIT.id(), + ActionTypeMapping.REPO_VIEW.id(), + ActionTypeMapping.REPO_DELETE.id(), + ActionTypeMapping.NODE_CREATE.id() + ), + ResourceType.NODE.id() to listOf( + ActionTypeMapping.NODE_DELETE.id(), + ActionTypeMapping.NODE_EDIT.id(), + ActionTypeMapping.NODE_WRITE.id(), + ActionTypeMapping.NODE_VIEW.id(), + ActionTypeMapping.NODE_DOWNLOAD.id() + ) + ) + ), + REPO_DOWNLOAD( + DefaultGroupType.REPO_DOWNLOAD.value, + mapOf( + ResourceType.PROJECT.id() to listOf(ActionTypeMapping.PROJECT_VIEW.id()), + ResourceType.REPO.id() to listOf(ActionTypeMapping.REPO_VIEW.id()), + ResourceType.NODE.id() to listOf( + ActionTypeMapping.NODE_VIEW.id(), + ActionTypeMapping.NODE_DOWNLOAD.id() + ) + ) + ), + REPO_UPLOAD_DELETE( + DefaultGroupType.REPO_UPLOAD_DELETE.value, + mapOf( + ResourceType.PROJECT.id() to listOf(ActionTypeMapping.PROJECT_VIEW.id()), + ResourceType.REPO.id() to listOf( + ActionTypeMapping.REPO_VIEW.id(), + ActionTypeMapping.NODE_CREATE.id() + ), + ResourceType.NODE.id() to listOf( + ActionTypeMapping.NODE_DELETE.id(), + ActionTypeMapping.NODE_EDIT.id(), + ActionTypeMapping.NODE_WRITE.id(), + ActionTypeMapping.NODE_VIEW.id(), + ActionTypeMapping.NODE_DOWNLOAD.id() + ), + ) + ); + + companion object { + fun get(value: String): DefaultGroupTypeAndActions { + values().forEach { + if (value == it.value) return it + } + throw IllegalArgumentException("No enum for constant $value") + } + } +} + diff --git a/src/backend/auth/api-auth/src/main/kotlin/com/tencent/bkrepo/auth/pojo/enums/ResourceActionMapping.kt b/src/backend/auth/api-auth/src/main/kotlin/com/tencent/bkrepo/auth/pojo/enums/ResourceActionMapping.kt new file mode 100644 index 0000000000..7de46b97c3 --- /dev/null +++ b/src/backend/auth/api-auth/src/main/kotlin/com/tencent/bkrepo/auth/pojo/enums/ResourceActionMapping.kt @@ -0,0 +1,53 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.pojo.enums + +enum class ResourceActionMapping(val resourceType: String, val actions: List) { + PROJECT_ACTIONS(ResourceType.PROJECT.id(), listOf( + ActionTypeMapping.PROJECT_VIEW.id(), + ActionTypeMapping.PROJECT_EDIT.id(), + ActionTypeMapping.PROJECT_MANAGE.id(), + ActionTypeMapping.REPO_CREATE.id() + )), + REPO_ACTIONS(ResourceType.REPO.id(), + listOf( + ActionTypeMapping.REPO_VIEW.id(), + ActionTypeMapping.REPO_EDIT.id(), + ActionTypeMapping.REPO_MANAGE.id(), + ActionTypeMapping.REPO_DELETE.id(), + ActionTypeMapping.NODE_CREATE.id() + )), + NODE_ACTIONS(ResourceType.NODE.id(), + listOf( + ActionTypeMapping.NODE_DELETE.id(), + ActionTypeMapping.NODE_DOWNLOAD.id(), + ActionTypeMapping.NODE_EDIT.id(), + ActionTypeMapping.NODE_WRITE.id(), + ActionTypeMapping.NODE_VIEW.id() + )); +} diff --git a/src/backend/auth/biz-auth/build.gradle.kts b/src/backend/auth/biz-auth/build.gradle.kts index 38f6ca1e21..3e462c88fb 100644 --- a/src/backend/auth/biz-auth/build.gradle.kts +++ b/src/backend/auth/biz-auth/build.gradle.kts @@ -35,9 +35,11 @@ dependencies { api(project(":common:common-job")) api(project(":common:common-security")) api(project(":repository:api-repository")) + api(project(":common:common-redis")) + api(project(":common:common-lock")) implementation("com.google.guava:guava") implementation(project(":common:common-operate:operate-service")) - api(project(":common:common-redis")) + implementation("com.tencent.bk.sdk:iam-java-sdk:${Versions.IamJavaSdk}") implementation("org.apache.httpcomponents:httpclient") implementation("com.tencent.bk.sdk:crypto-java-sdk") } diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/condition/BkV3RbacAuthCondition.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/condition/BkV3RbacAuthCondition.kt new file mode 100644 index 0000000000..291426dd7e --- /dev/null +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/condition/BkV3RbacAuthCondition.kt @@ -0,0 +1,46 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.condition + +import com.tencent.bkrepo.auth.constant.AUTH_CONFIG_PREFIX +import com.tencent.bkrepo.auth.constant.AUTH_CONFIG_TYPE_NAME +import com.tencent.bkrepo.auth.constant.AUTH_CONFIG_TYPE_VALUE_BKIAMV3 +import org.springframework.context.annotation.Condition +import org.springframework.context.annotation.ConditionContext +import org.springframework.core.type.AnnotatedTypeMetadata + +/** + * 使用bkv3rbac权限(local+bkv3rbac) + */ +class BkV3RbacAuthCondition: Condition { + override fun matches(context: ConditionContext, metadata: AnnotatedTypeMetadata): Boolean { + val authType = + context.environment.getProperty("$AUTH_CONFIG_PREFIX.$AUTH_CONFIG_TYPE_NAME", String()::class.java) + return authType == AUTH_CONFIG_TYPE_VALUE_BKIAMV3 + } +} \ No newline at end of file diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/condition/DevopsAuthCondition.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/condition/DevopsAuthCondition.kt new file mode 100644 index 0000000000..6383e7e377 --- /dev/null +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/condition/DevopsAuthCondition.kt @@ -0,0 +1,46 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.condition + +import com.tencent.bkrepo.auth.constant.AUTH_CONFIG_PREFIX +import com.tencent.bkrepo.auth.constant.AUTH_CONFIG_TYPE_NAME +import com.tencent.bkrepo.auth.constant.AUTH_CONFIG_TYPE_VALUE_DEVOPS +import org.springframework.context.annotation.Condition +import org.springframework.context.annotation.ConditionContext +import org.springframework.core.type.AnnotatedTypeMetadata + +/** + * 使用bkdevops权限(local+bkv3rbac+bkdevops) + */ +class DevopsAuthCondition: Condition { + override fun matches(context: ConditionContext, metadata: AnnotatedTypeMetadata): Boolean { + val authType = + context.environment.getProperty("$AUTH_CONFIG_PREFIX.$AUTH_CONFIG_TYPE_NAME", String()::class.java) + return authType == AUTH_CONFIG_TYPE_VALUE_DEVOPS + } +} \ No newline at end of file diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/condition/LocalAuthCondition.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/condition/LocalAuthCondition.kt new file mode 100644 index 0000000000..699775dc05 --- /dev/null +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/condition/LocalAuthCondition.kt @@ -0,0 +1,73 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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. + */ + +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.condition + +import com.tencent.bkrepo.auth.constant.AUTH_CONFIG_PREFIX +import com.tencent.bkrepo.auth.constant.AUTH_CONFIG_TYPE_NAME +import com.tencent.bkrepo.auth.constant.AUTH_CONFIG_TYPE_VALUE_LOCAL +import org.springframework.context.annotation.Condition +import org.springframework.context.annotation.ConditionContext +import org.springframework.core.type.AnnotatedTypeMetadata + +/** + * 使用默认local权限 + */ +class LocalAuthCondition: Condition { + override fun matches(context: ConditionContext, metadata: AnnotatedTypeMetadata): Boolean { + val authType = + context.environment.getProperty("$AUTH_CONFIG_PREFIX.$AUTH_CONFIG_TYPE_NAME", String()::class.java) + return (authType == AUTH_CONFIG_TYPE_VALUE_LOCAL || authType.isNullOrEmpty()) + } +} \ No newline at end of file diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/condition/MultipleAuthCondition.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/condition/MultipleAuthCondition.kt new file mode 100644 index 0000000000..1e10453771 --- /dev/null +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/condition/MultipleAuthCondition.kt @@ -0,0 +1,44 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.condition + +import com.tencent.bkrepo.auth.constant.AUTH_CONFIG_PREFIX +import com.tencent.bkrepo.auth.constant.AUTH_CONFIG_TYPE_NAME +import com.tencent.bkrepo.auth.constant.AUTH_CONFIG_TYPE_VALUE_BKIAMV3 +import com.tencent.bkrepo.auth.constant.AUTH_CONFIG_TYPE_VALUE_DEVOPS +import org.springframework.context.annotation.Condition +import org.springframework.context.annotation.ConditionContext +import org.springframework.core.type.AnnotatedTypeMetadata + +class MultipleAuthCondition: Condition { + override fun matches(context: ConditionContext, metadata: AnnotatedTypeMetadata): Boolean { + val authType = + context.environment.getProperty("$AUTH_CONFIG_PREFIX.$AUTH_CONFIG_TYPE_NAME", String()::class.java) + return (authType == AUTH_CONFIG_TYPE_VALUE_DEVOPS || authType == AUTH_CONFIG_TYPE_VALUE_BKIAMV3) + } +} \ No newline at end of file diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/config/AuthServiceConfig.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/config/AuthServiceConfig.kt index fd5f9b0506..d6b9e7a727 100644 --- a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/config/AuthServiceConfig.kt +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/config/AuthServiceConfig.kt @@ -31,6 +31,9 @@ package com.tencent.bkrepo.auth.config +import com.tencent.bkrepo.auth.condition.DevopsAuthCondition +import com.tencent.bkrepo.auth.condition.BkV3RbacAuthCondition +import com.tencent.bkrepo.auth.condition.LocalAuthCondition import com.tencent.bkrepo.auth.repository.AccountRepository import com.tencent.bkrepo.auth.repository.OauthTokenRepository import com.tencent.bkrepo.auth.repository.PermissionRepository @@ -43,20 +46,19 @@ import com.tencent.bkrepo.auth.service.UserService import com.tencent.bkrepo.auth.service.bkauth.DevopsPermissionServiceImpl import com.tencent.bkrepo.auth.service.bkauth.DevopsPipelineService import com.tencent.bkrepo.auth.service.bkauth.DevopsProjectService -import com.tencent.bkrepo.auth.service.bkiam.BkiamPermissionServiceImpl -import com.tencent.bkrepo.auth.service.bkiam.BkiamService +import com.tencent.bkrepo.auth.service.bkiamv3.BkIamV3PermissionServiceImpl +import com.tencent.bkrepo.auth.service.bkiamv3.BkIamV3Service import com.tencent.bkrepo.auth.service.local.AccountServiceImpl import com.tencent.bkrepo.auth.service.local.PermissionServiceImpl import com.tencent.bkrepo.auth.service.local.RoleServiceImpl import com.tencent.bkrepo.auth.service.local.UserServiceImpl import com.tencent.bkrepo.repository.api.ProjectClient import com.tencent.bkrepo.repository.api.RepositoryClient -import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.autoconfigure.AutoConfigureOrder import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Conditional import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Lazy import org.springframework.core.Ordered @@ -84,7 +86,7 @@ class AuthServiceConfig { ) = AccountServiceImpl(accountRepository, oauthTokenRepository, userService, mongoTemplate) @Bean - @ConditionalOnProperty(prefix = "auth", name = ["realm"], havingValue = "local", matchIfMissing = true) + @Conditional(LocalAuthCondition::class) fun permissionService( userRepository: UserRepository, roleRepository: RoleRepository, @@ -104,29 +106,29 @@ class AuthServiceConfig { } @Bean - @ConditionalOnProperty(prefix = "auth", name = ["realm"], havingValue = "bkiam") - fun bkiamPermissionService( + @Conditional(BkV3RbacAuthCondition::class) + fun bkiamV3PermissionService( + bkiamV3Service: BkIamV3Service, userRepository: UserRepository, roleRepository: RoleRepository, accountRepository: AccountRepository, permissionRepository: PermissionRepository, - mongoTemplate: MongoTemplate, - bkiamService: BkiamService + mongoTemplate: MongoTemplate ): PermissionService { - return BkiamPermissionServiceImpl( + return BkIamV3PermissionServiceImpl( userRepository, roleRepository, accountRepository, permissionRepository, mongoTemplate, - bkiamService, + bkiamV3Service, repositoryClient, projectClient ) } @Bean - @ConditionalOnProperty(prefix = "auth", name = ["realm"], havingValue = "devops") + @Conditional(DevopsAuthCondition::class) fun bkAuthPermissionService( userRepository: UserRepository, roleRepository: RoleRepository, @@ -135,8 +137,9 @@ class AuthServiceConfig { mongoTemplate: MongoTemplate, bkAuthConfig: DevopsAuthConfig, bkAuthPipelineService: DevopsPipelineService, - bkAuthProjectService: DevopsProjectService - ): PermissionService { + bkAuthProjectService: DevopsProjectService, + bkiamV3Service: BkIamV3Service + ): PermissionService { return DevopsPermissionServiceImpl( userRepository, roleRepository, @@ -147,7 +150,8 @@ class AuthServiceConfig { bkAuthPipelineService, bkAuthProjectService, repositoryClient, - projectClient + projectClient, + bkiamV3Service ) } @@ -167,8 +171,4 @@ class AuthServiceConfig { roleRepository: RoleRepository, mongoTemplate: MongoTemplate ) = UserServiceImpl(userRepository, roleRepository, mongoTemplate) - - companion object { - private val logger = LoggerFactory.getLogger(AuthServiceConfig::class.java) - } } diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/config/BkiamConfiguration.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/config/BkiamConfiguration.kt index da212d06d8..223f3b390d 100644 --- a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/config/BkiamConfiguration.kt +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/config/BkiamConfiguration.kt @@ -33,24 +33,26 @@ package com.tencent.bkrepo.auth.config import com.tencent.bk.sdk.iam.config.IamConfiguration import com.tencent.bk.sdk.iam.helper.AuthHelper -import com.tencent.bk.sdk.iam.service.HttpClientService import com.tencent.bk.sdk.iam.service.PolicyService import com.tencent.bk.sdk.iam.service.TokenService +import com.tencent.bk.sdk.iam.service.impl.ApigwHttpClientServiceImpl import com.tencent.bk.sdk.iam.service.impl.DefaultHttpClientServiceImpl import com.tencent.bk.sdk.iam.service.impl.GrantServiceImpl -import com.tencent.bk.sdk.iam.service.impl.PolicyServiceImpl +import com.tencent.bk.sdk.iam.service.impl.ManagerServiceImpl import com.tencent.bk.sdk.iam.service.impl.TokenServiceImpl -import com.tencent.bkrepo.auth.service.bkiam.IamEsbClient +import com.tencent.bk.sdk.iam.service.v2.impl.V2ManagerServiceImpl +import com.tencent.bk.sdk.iam.service.v2.impl.V2PolicyServiceImpl +import com.tencent.bkrepo.auth.condition.MultipleAuthCondition +import com.tencent.bkrepo.auth.service.bkiamv3.IamEsbClient import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Value -import org.springframework.boot.autoconfigure.AutoConfigureOrder import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Conditional import org.springframework.context.annotation.Configuration -import org.springframework.core.Ordered @Configuration -@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE) +@Conditional(MultipleAuthCondition::class) class BkiamConfiguration { @Value("\${auth.iam.systemId:}") @@ -65,23 +67,24 @@ class BkiamConfiguration { @Value("\${auth.iam.appSecret:}") private val appSecret = "" + @Value("\${auth.iam.apigwBaseUrl:}") + private val apigwBaseUrl = "" + @Bean - fun iamConfiguration() = IamConfiguration(iamSystemId, appCode, appSecret, iamBaseUrl) + fun iamConfiguration() = IamConfiguration(iamSystemId, appCode, appSecret, iamBaseUrl, apigwBaseUrl) @Bean fun iamHttpClient(iamConfiguration: IamConfiguration) = DefaultHttpClientServiceImpl(iamConfiguration) @Bean fun iamPolicyService( - @Autowired iamConfiguration: IamConfiguration, - @Autowired httpClientService: HttpClientService - ) = PolicyServiceImpl(iamConfiguration, httpClientService) + @Autowired iamConfiguration: IamConfiguration + ) = V2PolicyServiceImpl(apigwHttpClientService(iamConfiguration), iamConfiguration) @Bean fun tokenService( - @Autowired iamConfiguration: IamConfiguration, - @Autowired httpClientService: HttpClientService - ) = TokenServiceImpl(iamConfiguration, httpClientService) + @Autowired iamConfiguration: IamConfiguration + ) = TokenServiceImpl(iamConfiguration, apigwHttpClientService(iamConfiguration)) @Bean fun authHelper( @@ -99,4 +102,27 @@ class BkiamConfiguration { @Bean @ConditionalOnMissingBean fun iamEsbService() = IamEsbClient() + + // 接入V3(RBAC) + /** + * 鉴权类http实例。 管理类与鉴权类http实例分开,防止相互影响 + */ + @Bean + fun apigwHttpClientService(iamConfiguration: IamConfiguration) = ApigwHttpClientServiceImpl(iamConfiguration) + + /** + * 管理类http实例。 管理类与鉴权类http实例分开,防止相互影响 + */ + @Bean + fun managerHttpClientService(iamConfiguration: IamConfiguration) = ApigwHttpClientServiceImpl(iamConfiguration) + + @Bean + fun iamManagerServiceV2( + iamConfiguration: IamConfiguration + ) = V2ManagerServiceImpl(managerHttpClientService(iamConfiguration), iamConfiguration) + + @Bean + fun iamManagerServiceV1( + iamConfiguration: IamConfiguration + ) = ManagerServiceImpl(managerHttpClientService(iamConfiguration), iamConfiguration) } diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/controller/UserBkiamv3AuthController.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/controller/UserBkiamv3AuthController.kt new file mode 100644 index 0000000000..f363385197 --- /dev/null +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/controller/UserBkiamv3AuthController.kt @@ -0,0 +1,106 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.controller + +import com.tencent.bkrepo.auth.pojo.permission.CheckPermissionRequest +import com.tencent.bkrepo.auth.service.bkiamv3.BkIamV3Service +import com.tencent.bkrepo.common.api.constant.StringPool +import com.tencent.bkrepo.common.api.exception.ErrorCodeException +import com.tencent.bkrepo.common.api.message.CommonMessageCode +import com.tencent.bkrepo.common.api.pojo.Response +import com.tencent.bkrepo.common.security.permission.Principal +import com.tencent.bkrepo.common.security.permission.PrincipalType +import com.tencent.bkrepo.common.service.util.ResponseBuilder +import io.swagger.annotations.ApiOperation +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping("/api/user/auth") +class UserBkiamv3AuthController { + + @Autowired + private var bkIamV3Service: BkIamV3Service? = null + + @ApiOperation("生成无权限申请url") + @PostMapping("/bkiamv3/permission/url") + fun queryProject( + @RequestBody request: CheckPermissionRequest + ): Response { + val result = bkIamV3Service?.let { + try { + bkIamV3Service!!.getPermissionUrl(request) ?: StringPool.EMPTY + } catch (e: Exception) { + throw ErrorCodeException(CommonMessageCode.PARAMETER_INVALID) + } + } + return ResponseBuilder.success(result) + } + + @ApiOperation("判断蓝鲸权限是否开启") + @GetMapping("/bkiamv3/status") + fun bkiamv3Status(): Response { + val result = bkIamV3Service?.let { + bkIamV3Service!!.checkIamConfiguration() + } ?: false + return ResponseBuilder.success(result) + } + + @ApiOperation("在权限中心生成对应项目以及其下所有仓库的管理权限") + @PostMapping("/bkiamv3/project/refresh/{projectId}") + @Principal(PrincipalType.ADMIN) + fun refreshProject( + @PathVariable projectId: String, + @RequestParam userId: String? = null + ): Response { + val result = bkIamV3Service?.let { + bkIamV3Service!!.refreshProjectManager(userId, projectId) + } ?: false + return ResponseBuilder.success(result) + } + + @ApiOperation("删除生成的管理员空间") + @DeleteMapping("/bkiamv3/manager/delete") + @Principal(PrincipalType.ADMIN) + fun deleteProjectManager( + @RequestParam projectId: String, + @RequestParam repoName: String? = null, + ): Response { + val result = bkIamV3Service?.let { + bkIamV3Service!!.deleteGradeManager(projectId, repoName) + } ?: false + return ResponseBuilder.success(result) + } +} diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/controller/service/ServiceBkiamV3ResourceController.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/controller/service/ServiceBkiamV3ResourceController.kt new file mode 100644 index 0000000000..73baa310d3 --- /dev/null +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/controller/service/ServiceBkiamV3ResourceController.kt @@ -0,0 +1,96 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.controller.service + +import com.tencent.bkrepo.auth.api.ServiceBkiamV3ResourceClient +import com.tencent.bkrepo.auth.service.bkiamv3.BkIamV3Service +import com.tencent.bkrepo.common.api.pojo.Response +import com.tencent.bkrepo.common.lock.service.LockOperation +import com.tencent.bkrepo.common.service.util.ResponseBuilder +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.web.bind.annotation.RestController + +@RestController +class ServiceBkiamV3ResourceController : ServiceBkiamV3ResourceClient { + @Autowired + private var bkIamV3Service: BkIamV3Service? = null + + @Autowired + lateinit var lockOperation: LockOperation + + override fun createProjectManage(userId: String, projectId: String): Response { + bkIamV3Service?.let { + val gradeId = lockAction(projectId) { + bkIamV3Service!!.createGradeManager(userId, projectId) + } + return ResponseBuilder.success(gradeId) + } ?: return ResponseBuilder.success() + } + + override fun createRepoManage(userId: String, projectId: String, repoName: String): Response { + bkIamV3Service?.let { + val repoGradeId = lockAction(projectId) { + bkIamV3Service!!.createGradeManager(userId, projectId, repoName) + } + return ResponseBuilder.success(repoGradeId) + } ?: return ResponseBuilder.success() + } + + override fun deleteRepoManageGroup(userId: String, projectId: String, repoName: String): Response { + bkIamV3Service?.let { + return ResponseBuilder.success(bkIamV3Service!!.deleteGradeManager(projectId, repoName)) + } ?: return ResponseBuilder.success(true) + } + + override fun getExistRbacDefaultGroupProjectIds(projectIds: List): Response> { + bkIamV3Service?.let { + return ResponseBuilder.success(bkIamV3Service!!.getExistRbacDefaultGroupProjectIds(projectIds)) + } ?: return ResponseBuilder.success(emptyMap()) + } + + /** + * 针对自旋达到次数后,还没有获取到锁的情况默认也会执行所传入的方法,确保业务流程不中断 + */ + private fun lockAction(projectId: String, action: () -> T): T { + val lockKey = "$AUTH_LOCK_KEY_PREFIX$projectId" + val lock = lockOperation.getLock(lockKey) + return if (lockOperation.getSpinLock(lockKey, lock)) { + try { + action() + } finally { + lockOperation.close(lockKey, lock) + } + } else { + action() + } + } + + companion object { + const val AUTH_LOCK_KEY_PREFIX = "auth:lock:gradeCreate:" + } +} diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/controller/service/ServicePipelineController.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/controller/service/ServicePipelineController.kt index c6fabc427d..97b06bb230 100644 --- a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/controller/service/ServicePipelineController.kt +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/controller/service/ServicePipelineController.kt @@ -39,14 +39,19 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.web.bind.annotation.RestController @RestController -class ServicePipelineController @Autowired constructor( - private val bkAuthPipelineService: DevopsPipelineService -) : ServicePipelineClient { +class ServicePipelineController : ServicePipelineClient { + @Autowired + private var bkAuthPipelineService: DevopsPipelineService? = null + override fun listPermissionedPipelines(uid: String, projectId: String): Response> { - return ResponseBuilder.success(bkAuthPipelineService.listPermissionPipelines(uid, projectId)) + return bkAuthPipelineService?.let { + ResponseBuilder.success(bkAuthPipelineService!!.listPermissionPipelines(uid, projectId)) + } ?: ResponseBuilder.success(emptyList()) } override fun hasPermission(uid: String, projectId: String, pipelineId: String): Response { - return ResponseBuilder.success((bkAuthPipelineService.hasPermission(uid, projectId, pipelineId, null))) + return bkAuthPipelineService?.let { + ResponseBuilder.success((bkAuthPipelineService!!.hasPermission(uid, projectId, pipelineId, null))) + } ?: ResponseBuilder.success(false) } } diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/controller/user/BkiamCallbackController.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/controller/user/BkiamCallbackController.kt index ef4fd1b46c..d878d9c6a6 100644 --- a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/controller/user/BkiamCallbackController.kt +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/controller/user/BkiamCallbackController.kt @@ -33,31 +33,61 @@ package com.tencent.bkrepo.auth.controller.user import com.tencent.bk.sdk.iam.dto.callback.request.CallbackRequestDTO import com.tencent.bk.sdk.iam.dto.callback.response.CallbackBaseResponseDTO +import com.tencent.bkrepo.auth.condition.MultipleAuthCondition import com.tencent.bkrepo.auth.pojo.bkiam.BkResult -import com.tencent.bkrepo.auth.service.bkiam.BkiamCallbackService +import com.tencent.bkrepo.auth.service.bkiamv3.callback.BkiamCallbackService import io.swagger.annotations.ApiOperation +import io.swagger.annotations.ApiParam import org.springframework.beans.factory.annotation.Autowired +import org.springframework.context.annotation.Conditional import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestHeader import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/external/bkiam/callback") +@Conditional(MultipleAuthCondition::class) class BkiamCallbackController @Autowired constructor(private val bkiamCallbackService: BkiamCallbackService) { @ApiOperation("项目列表") @PostMapping("/project") - fun queryProject(token: String, request: CallbackRequestDTO): CallbackBaseResponseDTO? { + fun queryProject( + @RequestHeader("Authorization") + @ApiParam("token") + token: String, + @ApiParam("回调信息") + @RequestBody request: CallbackRequestDTO + ): CallbackBaseResponseDTO? { return bkiamCallbackService.queryProject(token, request) } @ApiOperation("仓库列表") @PostMapping("/repo") - fun queryRepo(token: String, request: CallbackRequestDTO): CallbackBaseResponseDTO? { + fun queryRepo( + @RequestHeader("Authorization") + @ApiParam("token") + token: String, + @ApiParam("回调信息") + @RequestBody request: CallbackRequestDTO + ): CallbackBaseResponseDTO? { return bkiamCallbackService.queryRepo(token, request) } + @ApiOperation("节点列表") + @PostMapping("/node") + fun queryNode( + @RequestHeader("Authorization") + @ApiParam("token") + token: String, + @ApiParam("回调信息") + @RequestBody request: CallbackRequestDTO + ): CallbackBaseResponseDTO? { + return bkiamCallbackService.queryNode(token, request) + } + @ApiOperation("健康检查") @GetMapping("/health") fun health(): BkResult { diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/interceptor/AuthInterceptor.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/interceptor/AuthInterceptor.kt index 609af23180..584cd1d62e 100644 --- a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/interceptor/AuthInterceptor.kt +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/interceptor/AuthInterceptor.kt @@ -45,6 +45,7 @@ import com.tencent.bkrepo.auth.constant.AUTH_API_TOKEN_LIST_PREFIX import com.tencent.bkrepo.auth.constant.AUTH_API_TOKEN_PREFIX import com.tencent.bkrepo.auth.constant.AUTH_API_USER_ASSET_USER_GROUP_PREFIX import com.tencent.bkrepo.auth.constant.AUTH_API_USER_DELETE_PREFIX +import com.tencent.bkrepo.auth.constant.AUTH_API_USER_BKIAMV3_PREFIX import com.tencent.bkrepo.auth.constant.AUTH_API_USER_INFO_PREFIX import com.tencent.bkrepo.auth.constant.AUTH_API_USER_LIST_PREFIX import com.tencent.bkrepo.auth.constant.AUTH_API_USER_UPDATE_PREFIX @@ -271,7 +272,8 @@ class AuthInterceptor( AUTH_API_PERMISSION_USER_PREFIX, AUTH_API_USER_UPDATE_PREFIX, AUTH_API_USER_DELETE_PREFIX, - AUTH_API_USER_ASSET_USER_GROUP_PREFIX + AUTH_API_USER_ASSET_USER_GROUP_PREFIX, + AUTH_API_USER_BKIAMV3_PREFIX ) private val anonymousAccessApiSet = setOf( diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/model/TBkIamAuthManager.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/model/TBkIamAuthManager.kt new file mode 100644 index 0000000000..ff8a61daf6 --- /dev/null +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/model/TBkIamAuthManager.kt @@ -0,0 +1,56 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.model + +import com.tencent.bkrepo.auth.pojo.enums.ResourceType +import org.springframework.data.mongodb.core.index.CompoundIndex +import org.springframework.data.mongodb.core.index.CompoundIndexes +import org.springframework.data.mongodb.core.mapping.Document +import java.time.LocalDateTime + +/** + * 存储对应资源与创建的分级管理员id关联关系 + */ +@Document("bkiam_auth_manager") +@CompoundIndexes( + CompoundIndex( + name = "res_idx", + def = "{'type': 1, 'resourceId': 1, 'parentResId': 1}", + background = true + ) +) +data class TBkIamAuthManager( + var type: ResourceType, + var parentResId: String? = null, + var resourceId: String, + var managerId: Int, + var createdDate: LocalDateTime, + var createdBy: String, + var lastModifiedDate: LocalDateTime, + var lastModifiedBy: String +) diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/pojo/iam/ResourceInfo.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/pojo/iam/ResourceInfo.kt new file mode 100644 index 0000000000..20a6f5122e --- /dev/null +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/pojo/iam/ResourceInfo.kt @@ -0,0 +1,37 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.pojo.iam + +import com.tencent.bkrepo.auth.pojo.enums.ResourceType + +data class ResourceInfo( + val resId: String, + val resName: String, + val resType: ResourceType +) + diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/repository/BkIamAuthManagerRepository.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/repository/BkIamAuthManagerRepository.kt new file mode 100644 index 0000000000..b291f47373 --- /dev/null +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/repository/BkIamAuthManagerRepository.kt @@ -0,0 +1,52 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.repository + +import com.tencent.bkrepo.auth.model.TBkIamAuthManager +import com.tencent.bkrepo.auth.pojo.enums.ResourceType +import org.springframework.data.mongodb.repository.MongoRepository +import org.springframework.stereotype.Repository + +@Repository +interface BkIamAuthManagerRepository: MongoRepository { + fun findByTypeAndResourceIdAndParentResId( + type: ResourceType, resourceId: String, parentResId: String? + ) :TBkIamAuthManager? + + fun findAllByTypeAndParentResIdAndResourceIdIn( + type: ResourceType, parentResId: String?, resList: List + ) :List + + fun findAllByTypeAndParentResId( + type: ResourceType, parentResId: String + ) :List + + fun deleteByTypeAndResourceIdAndParentResId( + type: ResourceType, resourceId: String, parentResId: String? + ) +} diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkauth/CIAuthService.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkauth/CIAuthService.kt index b93fd0c9ae..06ac7245e2 100644 --- a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkauth/CIAuthService.kt +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkauth/CIAuthService.kt @@ -33,6 +33,7 @@ package com.tencent.bkrepo.auth.service.bkauth import com.fasterxml.jackson.module.kotlin.readValue import com.google.common.cache.CacheBuilder +import com.tencent.bkrepo.auth.condition.DevopsAuthCondition import com.tencent.bkrepo.auth.config.DevopsAuthConfig import com.tencent.bkrepo.auth.pojo.BkciAuthCheckResponse import com.tencent.bkrepo.auth.pojo.BkciAuthListResponse @@ -45,10 +46,12 @@ import com.tencent.bkrepo.common.api.util.JsonUtils.objectMapper import okhttp3.Request import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired +import org.springframework.context.annotation.Conditional import org.springframework.stereotype.Service import java.util.concurrent.TimeUnit @Service +@Conditional(DevopsAuthCondition::class) class CIAuthService @Autowired constructor(private val devopsAuthConfig: DevopsAuthConfig) { private val okHttpClient = okhttp3.OkHttpClient.Builder().connectTimeout(3L, TimeUnit.SECONDS) diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkauth/DevopsPermissionServiceImpl.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkauth/DevopsPermissionServiceImpl.kt index 8fe96eb2c8..b714959fee 100644 --- a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkauth/DevopsPermissionServiceImpl.kt +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkauth/DevopsPermissionServiceImpl.kt @@ -32,6 +32,10 @@ package com.tencent.bkrepo.auth.service.bkauth import com.tencent.bkrepo.auth.config.DevopsAuthConfig +import com.tencent.bkrepo.auth.constant.CUSTOM +import com.tencent.bkrepo.auth.constant.LOG +import com.tencent.bkrepo.auth.constant.PIPELINE +import com.tencent.bkrepo.auth.constant.REPORT import com.tencent.bkrepo.auth.pojo.enums.PermissionAction import com.tencent.bkrepo.auth.pojo.enums.ResourceType import com.tencent.bkrepo.auth.pojo.permission.CheckPermissionRequest @@ -39,7 +43,8 @@ import com.tencent.bkrepo.auth.repository.AccountRepository import com.tencent.bkrepo.auth.repository.PermissionRepository import com.tencent.bkrepo.auth.repository.RoleRepository import com.tencent.bkrepo.auth.repository.UserRepository -import com.tencent.bkrepo.auth.service.local.PermissionServiceImpl +import com.tencent.bkrepo.auth.service.bkiamv3.BkIamV3PermissionServiceImpl +import com.tencent.bkrepo.auth.service.bkiamv3.BkIamV3Service import com.tencent.bkrepo.common.artifact.path.PathUtils import com.tencent.bkrepo.repository.api.ProjectClient import com.tencent.bkrepo.repository.api.RepositoryClient @@ -59,13 +64,15 @@ class DevopsPermissionServiceImpl constructor( private val devopsPipelineService: DevopsPipelineService, private val devopsProjectService: DevopsProjectService, repositoryClient: RepositoryClient, - projectClient: ProjectClient -) : PermissionServiceImpl( + projectClient: ProjectClient, + bkIamV3Service: BkIamV3Service +) : BkIamV3PermissionServiceImpl( userRepository, roleRepository, accountRepository, permissionRepository, mongoTemplate, + bkIamV3Service, repositoryClient, projectClient ) { @@ -87,6 +94,12 @@ class DevopsPermissionServiceImpl constructor( // 校验平台账号操作范围 if (!super.checkPlatformPermission(request)) return false + // bkiamv3权限校验 + if (super.matchBkiamv3Cond(request)) { + // 当有v3权限时,返回成功;如没有v3权限则按devops账号体系继续进行判断 + if (super.checkBkIamV3Permission(request)) return true + } + return checkDevopsPermission(request) } @@ -120,6 +133,7 @@ class DevopsPermissionServiceImpl constructor( // project权限 if (resourceType == ResourceType.PROJECT.toString()) { return checkDevopsProjectPermission(uid, projectId!!, action) + || super.checkBkIamV3ProjectPermission(projectId!!, uid, action) } // repo或者node权限 @@ -204,9 +218,5 @@ class DevopsPermissionServiceImpl constructor( companion object { private val logger = LoggerFactory.getLogger(DevopsPermissionServiceImpl::class.java) - private const val CUSTOM = "custom" - private const val PIPELINE = "pipeline" - private const val REPORT = "report" - private const val LOG = "log" } } diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkauth/DevopsPipelineService.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkauth/DevopsPipelineService.kt index 39b5921594..f03800ce9a 100644 --- a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkauth/DevopsPipelineService.kt +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkauth/DevopsPipelineService.kt @@ -31,15 +31,18 @@ package com.tencent.bkrepo.auth.service.bkauth +import com.tencent.bkrepo.auth.condition.DevopsAuthCondition import com.tencent.bkrepo.auth.pojo.enums.BkAuthPermission import com.tencent.bkrepo.auth.pojo.enums.BkAuthResourceType import org.slf4j.LoggerFactory +import org.springframework.context.annotation.Conditional import org.springframework.stereotype.Service /** * ci 流水线权限查询 */ @Service +@Conditional(DevopsAuthCondition::class) class DevopsPipelineService( private val ciAuthService: CIAuthService ) { diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkauth/DevopsProjectService.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkauth/DevopsProjectService.kt index f2b4ef8bea..9a342f6b35 100644 --- a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkauth/DevopsProjectService.kt +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkauth/DevopsProjectService.kt @@ -31,12 +31,15 @@ package com.tencent.bkrepo.auth.service.bkauth +import com.tencent.bkrepo.auth.condition.DevopsAuthCondition import com.tencent.bkrepo.auth.pojo.enums.BkAuthPermission import com.tencent.bkrepo.auth.pojo.enums.BkAuthResourceType import org.springframework.beans.factory.annotation.Autowired +import org.springframework.context.annotation.Conditional import org.springframework.stereotype.Service @Service +@Conditional(DevopsAuthCondition::class) class DevopsProjectService @Autowired constructor(private val ciAuthService: CIAuthService) { fun isProjectMember(user: String, projectCode: String, permissionAction: String): Boolean { return ciAuthService.isProjectSuperAdmin( diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiam/BkiamCallbackService.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiam/BkiamCallbackService.kt deleted file mode 100644 index 5f0515bb52..0000000000 --- a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiam/BkiamCallbackService.kt +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. - * - * Copyright (C) 2020 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.bkrepo.auth.service.bkiam - -import com.tencent.bk.sdk.iam.constants.CallbackMethodEnum -import com.tencent.bk.sdk.iam.dto.PageInfoDTO -import com.tencent.bk.sdk.iam.dto.callback.request.CallbackRequestDTO -import com.tencent.bk.sdk.iam.dto.callback.response.BaseDataResponseDTO -import com.tencent.bk.sdk.iam.dto.callback.response.CallbackBaseResponseDTO -import com.tencent.bk.sdk.iam.dto.callback.response.FetchInstanceInfoResponseDTO -import com.tencent.bk.sdk.iam.dto.callback.response.InstanceInfoDTO -import com.tencent.bk.sdk.iam.dto.callback.response.ListInstanceResponseDTO -import com.tencent.bk.sdk.iam.service.TokenService -import com.tencent.bkrepo.auth.constant.BASIC_AUTH_HEADER_PREFIX -import com.tencent.bkrepo.auth.exception.AuthFailedException -import com.tencent.bkrepo.common.api.constant.StringPool -import com.tencent.bkrepo.repository.api.ProjectClient -import com.tencent.bkrepo.repository.api.RepositoryClient -import com.tencent.bkrepo.repository.pojo.project.ProjectRangeQueryRequest -import com.tencent.bkrepo.repository.pojo.project.RepoRangeQueryRequest -import org.slf4j.LoggerFactory -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.beans.factory.annotation.Value -import org.springframework.stereotype.Service -import java.util.Base64 - -@Service -class BkiamCallbackService @Autowired constructor( - private val projectClient: ProjectClient, - private val repositoryClient: RepositoryClient, - private val tokenService: TokenService -) { - @Value("\${auth.iam.callbackUser:}") - private val callbackUser = "" - - private var bufferedToken = "" - - fun queryProject(token: String, request: CallbackRequestDTO): CallbackBaseResponseDTO? { - logger.info("queryProject, token: $token, request: $request") - checkToken(token) - val method = request.method - if (method == CallbackMethodEnum.FETCH_INSTANCE_INFO) { - val ids = request.filter.idList.map { it.toString() } - return fetchProjectInfo(ids, request.filter.attributeList) - } - return listProject(request.page, method) - } - - fun queryRepo(token: String, request: CallbackRequestDTO): CallbackBaseResponseDTO? { - logger.info("queryRepo, token: $token, request: $request") - checkToken(token) - val method = request.method - val projectId = request.filter.parent.id - if (method == CallbackMethodEnum.FETCH_INSTANCE_INFO) { - val ids = request.filter.idList.map { it.toString() } - return fetchRepoInfo(projectId, ids, request.filter.attributeList) - } - return listRepo(projectId, request.page, request.method) - } - - private fun listRepo(projectId: String, page: PageInfoDTO?, method: CallbackMethodEnum): CallbackBaseResponseDTO? { - logger.info("listRepo, projectId: $projectId, page: $page, method: $method") - var offset = 0L - var limit = 20 - if (page != null) { - offset = page.offset - limit = page.limit.toInt() - } - val repoPage = repositoryClient.rangeQuery(RepoRangeQueryRequest(listOf(), projectId, offset, limit)).data!! - var result = ListInstanceResponseDTO() - val repos = repoPage.records.map { - val entity = InstanceInfoDTO() - entity.id = it!!.name - entity.displayName = it.name - entity - } - val data = BaseDataResponseDTO() - data.count = repoPage.totalRecords - data.result = repos - result.code = 0L - result.message = "" - result.data = data - logger.info("listRepo, result: $result") - return result - } - - private fun fetchRepoInfo(projectId: String, idList: List, attrs: List): CallbackBaseResponseDTO? { - logger.info("fetchRepoInfo, projectId: $projectId, idList: $idList, attrs: $attrs") - val repoPage = repositoryClient.rangeQuery(RepoRangeQueryRequest(idList, projectId, 0, 10000)).data!! - val repos = repoPage.records.map { - val entity = InstanceInfoDTO() - entity.id = it!!.name - entity.displayName = it.name - entity - } - val result = FetchInstanceInfoResponseDTO() - result.code = 0 - result.message = "" - result.data = repos - return result - } - - private fun listProject(page: PageInfoDTO?, method: CallbackMethodEnum): ListInstanceResponseDTO { - logger.info("listProject, page $method, method $page") - var offset = 0L - var limit = 20 - if (page != null) { - offset = page.offset - limit = page.limit.toInt() - } - val projectPage = projectClient.rangeQuery(ProjectRangeQueryRequest(listOf(), offset, limit)).data!! - val projects = projectPage.records.map { - val entity = InstanceInfoDTO() - entity.id = it!!.name - entity.displayName = it.displayName - entity - } - val result = ListInstanceResponseDTO() - val data = BaseDataResponseDTO() - data.count = projectPage.totalRecords - data.result = projects - result.code = 0L - result.message = "" - result.data = data - logger.info("listProject, result: $result") - return result - } - - private fun fetchProjectInfo(idList: List, attrs: List): FetchInstanceInfoResponseDTO { - logger.info("fetchProjectInfo, idList: $idList, attrs: $attrs") - val projectPage = projectClient.rangeQuery(ProjectRangeQueryRequest(idList, 0, 10000)).data!! - - val projects = projectPage.records.map { - val entity = InstanceInfoDTO() - entity.id = it!!.name - entity.displayName = it.displayName - entity - } - - val result = FetchInstanceInfoResponseDTO() - result.code = 0 - result.message = "" - result.data = projects - return result - } - - private fun checkToken(token: String) { - val credentials = parseCredentials(token) - val userName = credentials.first - val password = credentials.second - if (userName != callbackUser) { - throw AuthFailedException("invalid iam user: $userName") - } - val tokenToCheck = password - if (bufferedToken.isNotBlank() && bufferedToken == tokenToCheck) { - return - } - bufferedToken = tokenService.token - if (bufferedToken != tokenToCheck) { - throw AuthFailedException("[$tokenToCheck] is not a valid credentials") - } - } - - private fun parseCredentials(token: String): Pair { - return try { - val encodedCredentials = token.removePrefix(BASIC_AUTH_HEADER_PREFIX) - val decodedToken = String(Base64.getDecoder().decode(encodedCredentials)) - val parts = decodedToken.split(StringPool.COLON) - Pair(parts[0], parts[1]) - } catch (exception: IllegalArgumentException) { - throw AuthFailedException("[$token] is not a valid token") - } - } - - companion object { - private val logger = LoggerFactory.getLogger(BkiamCallbackService::class.java) - } -} diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiam/BkiamPermissionServiceImpl.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiam/BkiamPermissionServiceImpl.kt deleted file mode 100644 index a19ec30b46..0000000000 --- a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiam/BkiamPermissionServiceImpl.kt +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. - * - * Copyright (C) 2020 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.bkrepo.auth.service.bkiam - -import com.tencent.bkrepo.auth.pojo.permission.CheckPermissionRequest -import com.tencent.bkrepo.auth.pojo.ResourceBaseRequest -import com.tencent.bkrepo.auth.pojo.enums.ResourceType -import com.tencent.bkrepo.auth.pojo.enums.SystemCode -import com.tencent.bkrepo.auth.repository.AccountRepository -import com.tencent.bkrepo.auth.repository.PermissionRepository -import com.tencent.bkrepo.auth.repository.RoleRepository -import com.tencent.bkrepo.auth.repository.UserRepository -import com.tencent.bkrepo.auth.service.local.PermissionServiceImpl -import com.tencent.bkrepo.common.api.constant.StringPool -import com.tencent.bkrepo.repository.api.ProjectClient -import com.tencent.bkrepo.repository.api.RepositoryClient -import org.slf4j.LoggerFactory -import org.springframework.data.mongodb.core.MongoTemplate - -/** - * 对接蓝鲸权限中心3.0 - */ -class BkiamPermissionServiceImpl constructor( - userRepository: UserRepository, - roleRepository: RoleRepository, - accountRepository: AccountRepository, - permissionRepository: PermissionRepository, - mongoTemplate: MongoTemplate, - private val bkiamService: BkiamService, - repositoryClient: RepositoryClient, - projectClient: ProjectClient -) : PermissionServiceImpl( - userRepository, - roleRepository, - accountRepository, - permissionRepository, - mongoTemplate, - repositoryClient, - projectClient -) { - override fun checkPermission(request: CheckPermissionRequest): Boolean { - logger.info("checkPermission, request: $request") - if (request.resourceType != ResourceType.SYSTEM.toString() && checkBkiamPermission(request)) { - logger.debug("checkBkiamPermission passed") - return true - } - return super.checkPermission(request) - } - - private fun checkBkiamPermission(request: CheckPermissionRequest): Boolean { - return bkiamService.validateResourcePermission( - userId = request.uid, - systemCode = SystemCode.BK_REPO, - projectId = request.projectId!!, - resourceType = request.resourceType, - action = request.action, - resourceId = getResourceId(request) - ) - } - - private fun getResourceId(request: ResourceBaseRequest): String { - return when (request.resourceType) { - ResourceType.SYSTEM.toString() -> StringPool.EMPTY - ResourceType.PROJECT.toString() -> request.projectId!! - ResourceType.REPO.toString() -> request.repoName!! - ResourceType.NODE.toString() -> throw IllegalArgumentException("invalid resource type") - else -> throw IllegalArgumentException("invalid resource type") - } - } - - companion object { - private val logger = LoggerFactory.getLogger(BkiamPermissionServiceImpl::class.java) - } -} diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiam/BkiamService.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiam/BkiamService.kt deleted file mode 100644 index 94728a87d8..0000000000 --- a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiam/BkiamService.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. - * - * Copyright (C) 2020 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.bkrepo.auth.service.bkiam - -import com.tencent.bkrepo.auth.pojo.enums.SystemCode - -interface BkiamService { - fun validateResourcePermission( - userId: String, - systemCode: SystemCode, - projectId: String, - resourceType: String, - action: String, - resourceId: String - ): Boolean - - fun listResourceByPermission( - userId: String, - systemCode: SystemCode, - projectId: String, - resourceType: String, - action: String - ): List - - fun createResource( - userId: String, - systemCode: SystemCode, - projectId: String, - resourceType: String, - resourceId: String, - resourceName: String - ) -} diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiam/BkiamServiceImpl.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiam/BkiamServiceImpl.kt deleted file mode 100644 index bf29b6d51b..0000000000 --- a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiam/BkiamServiceImpl.kt +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. - * - * Copyright (C) 2020 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.bkrepo.auth.service.bkiam - -import com.tencent.bk.sdk.iam.config.IamConfiguration -import com.tencent.bk.sdk.iam.constants.ExpressionOperationEnum -import com.tencent.bk.sdk.iam.dto.InstanceDTO -import com.tencent.bk.sdk.iam.dto.PathInfoDTO -import com.tencent.bk.sdk.iam.dto.action.ActionDTO -import com.tencent.bk.sdk.iam.helper.AuthHelper -import com.tencent.bk.sdk.iam.service.PolicyService -import com.tencent.bkrepo.auth.pojo.iam.AncestorsApiReq -import com.tencent.bkrepo.auth.pojo.iam.IamCreateApiReq -import com.tencent.bkrepo.auth.pojo.enums.ResourceType -import com.tencent.bkrepo.auth.pojo.enums.SystemCode -import com.tencent.bkrepo.auth.util.BkiamUtils -import org.slf4j.LoggerFactory -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.stereotype.Service - -@Service -class BkiamServiceImpl @Autowired constructor( - private val iamConfiguration: IamConfiguration, - private val authHelper: AuthHelper, - private val policyService: PolicyService, - private val iamEsbClient: IamEsbClient -) : BkiamService { - override fun validateResourcePermission( - userId: String, - systemCode: SystemCode, - projectId: String, - resourceType: String, - action: String, - resourceId: String - ): Boolean { - logger.info( - "validateResourcePermission, userId: $userId, projectId: $projectId, systemCode: $systemCode," + - " resourceType: $resourceType, action: $action, resourceId: $resourceId" - ) - val resourceAction = BkiamUtils.buildAction(resourceType, action) - if (systemCode == SystemCode.BK_REPO && resourceType == ResourceType.PROJECT.toString()) { - return authHelper.isAllowed(userId, resourceAction) - } - - val instanceDTO = InstanceDTO() - instanceDTO.system = systemCode.id() - instanceDTO.id = resourceId - instanceDTO.type = resourceType - - val path = PathInfoDTO() - path.type = ResourceType.PROJECT.id() - path.id = projectId - instanceDTO.path = path - - return authHelper.isAllowed(userId, resourceAction, instanceDTO) - } - - override fun listResourceByPermission( - userId: String, - systemCode: SystemCode, - projectId: String, - resourceType: String, - action: String - ): List { - logger.info( - "listResourceByPermission, userId: $userId, projectId: $projectId, systemCode: $systemCode," + - " resourceType: $resourceType, action: $action" - ) - val actionDto = ActionDTO() - actionDto.id = BkiamUtils.buildAction(resourceType, action) - val expression = (policyService.getPolicyByAction(userId, actionDto, null) ?: return emptyList()) - logger.debug("listResourceByPermission, expression: $expression") - if (expression.operator == null && expression.content == null) { - return emptyList() - } - if (expression.operator == ExpressionOperationEnum.ANY) { - return listOf("*") - } - - return if (resourceType == ResourceType.PROJECT.toString()) { - BkiamUtils.getProjects(expression) - } else { - val instancesList = BkiamUtils.getResourceInstance(expression, projectId, resourceType) - logger.debug( - "getUserResourceByPermission getInstance project[$projectId], type[$resourceType]," + - " instances[$instancesList]" - ) - if (!instancesList.contains("*")) { - instancesList.toList() - } else { - listOf("*") - } - } - } - - override fun createResource( - userId: String, - systemCode: SystemCode, - projectId: String, - resourceType: String, - resourceId: String, - resourceName: String - ) { - logger.info( - "createResource, userId: $userId, projectId: $projectId, systemCode: $systemCode," + - " resourceType: $resourceType, resourceId: $resourceId, resourceName: $resourceName" - ) - val ancestors = mutableListOf() - if (resourceType != ResourceType.PROJECT.toString()) { - ancestors.add( - AncestorsApiReq( - system = iamConfiguration.systemId, - id = projectId, - type = ResourceType.PROJECT.id() - ) - ) - } - val iamApiReq = IamCreateApiReq( - creator = userId, - name = resourceName, - id = resourceId, - type = resourceType, - system = iamConfiguration.systemId, - ancestors = ancestors, - bk_app_code = "", - bk_app_secret = "", - bk_username = userId - ) - iamEsbClient.createRelationResource(iamApiReq) - } - - companion object { - private val logger = LoggerFactory.getLogger(BkiamServiceImpl::class.java) - } -} diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/BkIamV3PermissionServiceImpl.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/BkIamV3PermissionServiceImpl.kt new file mode 100644 index 0000000000..1e99464a04 --- /dev/null +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/BkIamV3PermissionServiceImpl.kt @@ -0,0 +1,199 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.service.bkiamv3 + +import com.tencent.bkrepo.auth.constant.CUSTOM +import com.tencent.bkrepo.auth.constant.LOG +import com.tencent.bkrepo.auth.constant.PIPELINE +import com.tencent.bkrepo.auth.constant.REPORT +import com.tencent.bkrepo.auth.pojo.enums.ActionTypeMapping +import com.tencent.bkrepo.auth.pojo.enums.ResourceType +import com.tencent.bkrepo.auth.pojo.permission.CheckPermissionRequest +import com.tencent.bkrepo.auth.repository.AccountRepository +import com.tencent.bkrepo.auth.repository.PermissionRepository +import com.tencent.bkrepo.auth.repository.RoleRepository +import com.tencent.bkrepo.auth.repository.UserRepository +import com.tencent.bkrepo.auth.service.local.PermissionServiceImpl +import com.tencent.bkrepo.auth.util.BkIamV3Utils.convertActionType +import com.tencent.bkrepo.common.api.constant.StringPool +import com.tencent.bkrepo.repository.api.ProjectClient +import com.tencent.bkrepo.repository.api.RepositoryClient +import org.slf4j.LoggerFactory +import org.springframework.data.mongodb.core.MongoTemplate + +/** + * 对接蓝鲸权限中心V3 RBAC + */ +open class BkIamV3PermissionServiceImpl( + userRepository: UserRepository, + roleRepository: RoleRepository, + accountRepository: AccountRepository, + permissionRepository: PermissionRepository, + mongoTemplate: MongoTemplate, + private val bkiamV3Service: BkIamV3Service, + repositoryClient: RepositoryClient, + projectClient: ProjectClient +) : PermissionServiceImpl( + userRepository, + roleRepository, + accountRepository, + permissionRepository, + mongoTemplate, + repositoryClient, + projectClient +) { + override fun checkPermission(request: CheckPermissionRequest): Boolean { + logger.debug("v3 checkPermission, request: $request") + return super.checkPermission(request) || checkBkIamV3Permission(request) + } + + override fun listPermissionRepo(projectId: String, userId: String, appId: String?): List { + logger.debug("v3 listPermissionRepo, projectId: $projectId, userId: $userId, appId: $appId") + return mergeResult( + super.listPermissionRepo(projectId, userId, appId), + listV3PermissionRepo(projectId, userId) + ) + } + + override fun listPermissionProject(userId: String): List { + logger.debug("v3 listPermissionProject, userId: $userId") + return mergeResult( + super.listPermissionProject(userId), + listV3PermissionProject(userId) + ) + } + + /** + * 判断仓库创建时是否开启权限校验 + */ + fun matchBkiamv3Cond(request: CheckPermissionRequest): Boolean { + with(request) { + if (!bkiamV3Service.checkIamConfiguration()) return false + return bkiamV3Service.checkBkiamv3Config(projectId, repoName) + } + } + + fun checkBkIamV3Permission(request: CheckPermissionRequest): Boolean { + with(request) { + if (projectId == null) return false + val resourceId = bkiamV3Service.getResourceId( + resourceType, projectId, repoName, path + ) ?: StringPool.EMPTY + return if (checkDefaultRepository(resourceType, resourceId, repoName)) { + checkBkIamV3ProjectPermission(projectId!!, uid, action) + } else { + bkiamV3Service.validateResourcePermission( + userId = uid, + projectId = projectId!!, + repoName = repoName, + resourceType = resourceType.toLowerCase(), + action = convertActionType(resourceType, action), + resourceId = resourceId, + appId = appId + ) + } + } + } + + /** + * 针对默认创建的4个仓库不开启v3-rbac校验,只校验项目权限 + */ + private fun checkDefaultRepository(resourceType: String, resourceId: String, repoName: String?): Boolean { + return when (resourceType) { + ResourceType.SYSTEM.toString() -> false + ResourceType.PROJECT.toString() -> false + ResourceType.REPO.toString() -> { + defaultRepoList.contains(resourceId) + } + ResourceType.NODE.toString() -> { + defaultRepoList.contains(repoName) + } + else -> false + } + } + + fun checkBkIamV3ProjectPermission(projectId: String, userId: String, action: String): Boolean { + logger.info("v3 checkBkIamV3ProjectPermission userId: $userId, projectId: $projectId, action: $action") + return bkiamV3Service.validateResourcePermission( + userId = userId, + projectId = projectId, + repoName = null, + resourceType = ResourceType.PROJECT.id(), + action = try { + convertActionType(ResourceType.PROJECT.name, action) + } catch (e: IllegalArgumentException) { + ActionTypeMapping.PROJECT_MANAGE.id() + }, + resourceId = projectId, + appId = null + ) + } + + private fun listV3PermissionRepo(projectId: String, userId: String) : List { + val pList = bkiamV3Service.listPermissionResources( + userId = userId, + projectId = projectId, + resourceType = ResourceType.REPO.id(), + action = ActionTypeMapping.REPO_VIEW.id() + ) + return if (pList.contains(StringPool.POUND)) { + repoClient.listRepo(projectId).data?.map { it.name } ?: emptyList() + } else { + pList + } + } + + private fun listV3PermissionProject(userId: String) : List { + val pList = bkiamV3Service.listPermissionResources( + userId = userId, + resourceType = ResourceType.PROJECT.id(), + action = ActionTypeMapping.PROJECT_VIEW.id() + ) + return if (pList.contains(StringPool.POUND)) { + projectClient.listProject().data?.map { it.name } ?: emptyList() + } else { + pList + } + } + + private fun mergeResult( + list: List, + v3list: List + ) : List { + val set = mutableSetOf() + set.addAll(list) + set.addAll(v3list) + return set.toList() + } + + companion object { + private val logger = LoggerFactory.getLogger(BkIamV3PermissionServiceImpl::class.java) + private val defaultRepoList = listOf(CUSTOM, PIPELINE, LOG, REPORT) + } +} + diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/BkIamV3Service.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/BkIamV3Service.kt new file mode 100644 index 0000000000..40f2e2d10e --- /dev/null +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/BkIamV3Service.kt @@ -0,0 +1,118 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.service.bkiamv3 + +import com.tencent.bkrepo.auth.pojo.permission.CheckPermissionRequest + +/** + * bk iamv3接口调用 + */ +interface BkIamV3Service { + + /** + * 判断权限中心相关配置是否配置 + */ + fun checkIamConfiguration(): Boolean + + /** + * 判断是否开启了蓝鲸权限配置 + */ + fun checkBkiamv3Config(projectId: String?, repoName: String?): Boolean + + /** + * 生成无权限跳转url + */ + fun getPermissionUrl(request: CheckPermissionRequest): String? + + /** + * 鉴权 + */ + fun validateResourcePermission( + userId: String, + projectId: String, + repoName: String?, + resourceType: String, + action: String, + resourceId: String, + appId: String? + ): Boolean + + /** + * 仓库资源id转换 + */ + fun convertRepoResourceId(projectId: String, repoName: String): String? + + /** + * 节点资源id转换 + */ + fun convertNodeResourceId(projectId: String, repoName: String, fullPath: String): String? + + /** + * 获取有权限的资源列表 + */ + fun listPermissionResources( + userId: String, + projectId: String? = null, + resourceType: String, + action: String, + ): List + + /** + * 刷新项目以及旗下仓库对应的权限中心权限 + */ + fun refreshProjectManager(userId: String? = null, projectId: String): Boolean + + + /** + * 创建项目分级管理员 + */ + fun createGradeManager( + userId: String, + projectId: String, + repoName: String? = null + ): String? + + /** + * 删除分级管理员 + */ + fun deleteGradeManager( + projectId: String, + repoName: String? = null + ): Boolean + + /** + * 资源id转换 + */ + fun getResourceId(resourceType: String, projectId: String?, repoName: String?, path: String?): String? + + + /** + * 查询列表中的项目是否已生成rbac默认用户组 + */ + fun getExistRbacDefaultGroupProjectIds(ids: List) : Map +} diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/BkIamV3ServiceImpl.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/BkIamV3ServiceImpl.kt new file mode 100644 index 0000000000..9ecae86e27 --- /dev/null +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/BkIamV3ServiceImpl.kt @@ -0,0 +1,711 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.service.bkiamv3 + +import com.google.common.cache.CacheBuilder +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.PermissionUrlDTO +import com.tencent.bk.sdk.iam.dto.RelatedResourceTypes +import com.tencent.bk.sdk.iam.dto.RelationResourceInstance +import com.tencent.bk.sdk.iam.dto.action.ActionDTO +import com.tencent.bk.sdk.iam.dto.action.UrlAction +import com.tencent.bk.sdk.iam.dto.manager.ManagerMember +import com.tencent.bk.sdk.iam.dto.manager.ManagerRoleGroup +import com.tencent.bk.sdk.iam.dto.manager.ManagerScopes +import com.tencent.bk.sdk.iam.dto.manager.dto.CreateManagerDTO +import com.tencent.bk.sdk.iam.dto.manager.dto.CreateSubsetManagerDTO +import com.tencent.bk.sdk.iam.dto.manager.dto.ManagerMemberGroupDTO +import com.tencent.bk.sdk.iam.dto.manager.dto.ManagerRoleGroupDTO +import com.tencent.bk.sdk.iam.exception.IamException +import com.tencent.bk.sdk.iam.helper.AuthHelper +import com.tencent.bk.sdk.iam.service.ManagerService +import com.tencent.bk.sdk.iam.service.v2.V2ManagerService +import com.tencent.bkrepo.auth.condition.MultipleAuthCondition +import com.tencent.bkrepo.auth.constant.AUTH_CONFIG_PREFIX +import com.tencent.bkrepo.auth.constant.AUTH_CONFIG_TYPE_NAME +import com.tencent.bkrepo.auth.constant.AUTH_CONFIG_TYPE_VALUE_BKIAMV3 +import com.tencent.bkrepo.auth.constant.BKIAMV3_CHECK +import com.tencent.bkrepo.auth.model.TBkIamAuthManager +import com.tencent.bkrepo.auth.pojo.enums.DefaultGroupType +import com.tencent.bkrepo.auth.pojo.enums.DefaultGroupTypeAndActions +import com.tencent.bkrepo.auth.pojo.enums.ResourceType +import com.tencent.bkrepo.auth.pojo.iam.ResourceInfo +import com.tencent.bkrepo.auth.pojo.permission.CheckPermissionRequest +import com.tencent.bkrepo.auth.repository.BkIamAuthManagerRepository +import com.tencent.bkrepo.auth.service.UserService +import com.tencent.bkrepo.auth.util.BkIamV3Utils +import com.tencent.bkrepo.auth.util.BkIamV3Utils.buildId +import com.tencent.bkrepo.auth.util.BkIamV3Utils.buildResource +import com.tencent.bkrepo.auth.util.IamGroupUtils +import com.tencent.bkrepo.common.api.constant.StringPool +import com.tencent.bkrepo.common.api.exception.ErrorCodeException +import com.tencent.bkrepo.common.api.message.CommonMessageCode +import com.tencent.bkrepo.common.mongo.dao.util.sharding.HashShardingUtils +import com.tencent.bkrepo.common.security.util.SecurityUtils +import com.tencent.bkrepo.repository.api.NodeClient +import com.tencent.bkrepo.repository.api.ProjectClient +import com.tencent.bkrepo.repository.api.RepositoryClient +import com.tencent.bkrepo.repository.pojo.repo.RepositoryInfo +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Value +import org.springframework.context.annotation.Conditional +import org.springframework.data.mongodb.core.MongoTemplate +import org.springframework.stereotype.Service +import java.time.LocalDateTime +import java.util.concurrent.TimeUnit + +@Service +@Conditional(MultipleAuthCondition::class) +class BkIamV3ServiceImpl( + private val iamConfiguration: IamConfiguration, + private val authHelper: AuthHelper, + private val projectClient: ProjectClient, + private val managerService: V2ManagerService, + private val managerServiceV1: ManagerService, + private val repositoryClient: RepositoryClient, + private val nodeClient: NodeClient, + private val authManagerRepository: BkIamAuthManagerRepository, + private val userService: UserService, + val mongoTemplate: MongoTemplate + ) : BkIamV3Service, BkiamV3BaseService(mongoTemplate) { + + @Value("\${$AUTH_CONFIG_PREFIX.$AUTH_CONFIG_TYPE_NAME}") + private var ciAuthServer: String = "" + + @Value("\${auth.iam.applyJoinUserGroupUrl:}") + private val applyJoinUserGroupUrl = "" + + private val iamAuthCache = CacheBuilder.newBuilder() + .maximumSize(1000) + .expireAfterWrite(1, TimeUnit.MINUTES) + .build() + + override fun checkIamConfiguration(): Boolean { + if (iamConfiguration.systemId.isNullOrEmpty()) { + return false + } + if (iamConfiguration.apigwBaseUrl.isNullOrEmpty()) { + return false + } + if (iamConfiguration.appCode.isNullOrEmpty()) { + return false + } + if (iamConfiguration.appSecret.isNullOrEmpty()) { + return false + } + return true + } + + override fun checkBkiamv3Config(projectId: String?, repoName: String?): Boolean { + // 如果配置是bkiamv3,默认走bkiamv3校验 + if (ciAuthServer == AUTH_CONFIG_TYPE_VALUE_BKIAMV3) return true + if (projectId != null && repoName != null) { + val repoInfo = repositoryClient.getRepoInfo(projectId, repoName).data ?: return false + return repoInfo.configuration.getBooleanSetting(BKIAMV3_CHECK) ?: false + } + return false + } + + override fun getPermissionUrl( + request: CheckPermissionRequest + ): String? { + logger.debug( + "v3 getPermissionUrl, userId: ${request.uid}, projectId: ${request.projectId}, " + + "repoName: ${request.repoName} resourceType: ${request.resourceType}, " + + "action: ${request.action}, path: ${request.path}" + ) + if (!checkIamConfiguration()) return null + return if (request.projectId.isNullOrEmpty() && request.repoName.isNullOrEmpty()) { + getDefaultPermissionApplyUrl() + } else { + generatePermissionUrl(request) + } + } + + private fun getDefaultPermissionApplyUrl(): String? { + if (applyJoinUserGroupUrl.isEmpty()) return null + return applyJoinUserGroupUrl + } + + private fun generatePermissionUrl(request: CheckPermissionRequest): String? { + with(request) { + val resourceId = getResourceId( + resourceType, projectId, repoName, path + ) + val action = BkIamV3Utils.convertActionType(request.resourceType, request.action) + val resourceType = request.resourceType.toLowerCase() + if (repoName != null && !checkBkiamv3Config(projectId, repoName)) return null + authManagerRepository.findByTypeAndResourceIdAndParentResId( + ResourceType.PROJECT, projectId!!, null + )?.managerId ?: return null + + val instanceList = mutableListOf() + val projectInstance = RelationResourceInstance( + iamConfiguration.systemId, + ResourceType.PROJECT.id(), + projectId, + null + ) + instanceList.add(projectInstance) + if (repoName != null) { + val repoInstance = RelationResourceInstance( + iamConfiguration.systemId, + ResourceType.REPO.id(), + convertRepoResourceId(projectId!!, repoName!!), + null + ) + instanceList.add(repoInstance) + if (resourceType == ResourceType.NODE.id()) { + val nodeInstance = RelationResourceInstance( + iamConfiguration.systemId, + ResourceType.NODE.id(), + resourceId, + null + ) + instanceList.add(nodeInstance) + } + } + val instances: List> = listOf(instanceList) + val relatedResourceTypes = RelatedResourceTypes( + iamConfiguration.systemId, + resourceType, + instances, + emptyList() + ) + val actions = listOf(UrlAction(action, listOf(relatedResourceTypes))) + + val pUrlRequest = PermissionUrlDTO( + iamConfiguration.systemId, + actions + ) + logger.info("v3 get permissionUrl pUrlRequest: $pUrlRequest") + val pUrl = try { + managerServiceV1.getPermissionUrl(pUrlRequest) + } catch (e: Exception) { + logger.error( "v3 getPermissionUrl with userId: $uid, action: $action," + + " pUrlRequest: $pUrlRequest\" error: ${e.message}") + StringPool.EMPTY + } + return pUrl + } + } + + override fun validateResourcePermission( + userId: String, + projectId: String, + repoName: String?, + resourceType: String, + action: String, + resourceId: String, + appId: String? + ): Boolean { + logger.debug( + "v3 validateResourcePermission, userId: $userId, projectId: $projectId, repoName: $repoName" + + " resourceType: $resourceType, action: $action, resourceId: $resourceId, appId: $appId" + ) + if (!checkIamConfiguration()) return false + val instanceDTO = InstanceDTO() + instanceDTO.system = iamConfiguration.systemId + instanceDTO.id = resourceId + instanceDTO.type = resourceType + + val projectPath = PathInfoDTO() + projectPath.type = ResourceType.PROJECT.id() + projectPath.id = projectId + if (repoName != null) { + val repoPath = PathInfoDTO() + repoPath.type = ResourceType.REPO.id() + repoPath.id = convertRepoResourceId(projectId, repoName) + if (resourceType == ResourceType.NODE.id()) { + val nodePath = PathInfoDTO() + nodePath.type = ResourceType.NODE.id() + nodePath.id = resourceId + repoPath.child = nodePath + } + projectPath.child = repoPath + } + instanceDTO.path = projectPath + + val cacheKey = userId + action + resourceId + // 优先从缓存内获取 + val cachedResult = iamAuthCache.getIfPresent(cacheKey) + cachedResult?.let { + logger.debug("v3 validateResourcePermission match in cache: $cacheKey|$cachedResult") + return cachedResult + } + var allowed: Boolean + try { + allowed = authHelper.isAllowed(userId, action, instanceDTO) + iamAuthCache.put(cacheKey, allowed) + } catch (e: Exception) { + logger.error( + "try bkiamv3 check with userId: $userId, action: $action," + + " instanceDTO: $instanceDTO\" error: ${e.message}" + ) + allowed = false + } + logger.debug( + "v3 isAllowed $allowed for userId: $userId, action: $action, instanceDTO: $instanceDTO" + ) + return allowed + } + + override fun convertRepoResourceId(projectId: String, repoName: String): String? { + return repositoryClient.getRepoInfo(projectId, repoName).data?.id + } + + override fun convertNodeResourceId(projectId: String, repoName: String, fullPath: String): String? { + val index = HashShardingUtils.shardingSequenceFor(projectId, 256).toString() + val nodeId = nodeClient.getNodeDetail(projectId, repoName, fullPath).data?.nodeInfo?.id ?: return null + return buildId(nodeId, index) + } + + override fun listPermissionResources( + userId: String, + projectId: String?, + resourceType: String, + action: String, + ): List { + logger.debug( + "v3 listPermissionResources, userId: $userId, projectId: $projectId" + + " resourceType: $resourceType, action: $action" + ) + if (!checkIamConfiguration()) return emptyList() + val actionDto = ActionDTO() + actionDto.id = action + return when(resourceType) { + ResourceType.PROJECT.id() -> { + authHelper.getInstanceList(userId, action, resourceType) + } + ResourceType.REPO.id() -> { + val pathInfoDTO = PathInfoDTO() + pathInfoDTO.id = projectId + pathInfoDTO.type = ResourceType.PROJECT.id() + val idList = authHelper.getInstanceList(userId, action, resourceType, pathInfoDTO) + if (idList.contains(StringPool.POUND)) { + return idList + } + convertRepoResourceIdToRepoName(idList).map { + it[RepositoryInfo::name.name].toString() + } + } + else -> emptyList() + } + } + + override fun refreshProjectManager(userId: String?, projectId: String): Boolean { + logger.info("v3 refreshProjectManager projectId: $projectId and userId: $userId") + val projectInfo = projectClient.getProjectInfo(projectId).data + ?: throw ErrorCodeException(CommonMessageCode.PARAMETER_INVALID, projectId) + val uId = if (userId.isNullOrEmpty()) { + projectInfo.createdBy + } else { + userId + } + return !(createGradeManager(uId, projectId) + ?: createGradeManager(SecurityUtils.getUserId(), projectId)).isNullOrEmpty() + } + + /** + * 创建项目分级管理员 + */ + override fun createGradeManager( + userId: String, + projectId: String, + repoName: String? + ): String? { + if (!checkIamConfiguration()) return null + val realUserId = userService.getUserInfoById(userId)?.asstUsers?.firstOrNull() ?: userId + return if (repoName == null) { + createProjectGradeManager(realUserId, projectId) + } else { + // 只针对开启权限开关的仓库才创建对应用户组 + if (!checkBkiamv3Config(projectId, repoName)) return null + createRepoGradeManager(realUserId, projectId, repoName) + } + } + + override fun deleteGradeManager(projectId: String, repoName: String?): Boolean { + if (!checkIamConfiguration()) return false + logger.info("Manager for $projectId|$repoName will be deleted") + return if (repoName != null) { + deleteRepoManager(projectId, repoName) + } else { + deleteProjectManager(projectId) + } + } + + private fun deleteRepoManager(projectId: String, repoName: String): Boolean { + val managerId = authManagerRepository.findByTypeAndResourceIdAndParentResId( + ResourceType.REPO, repoName, projectId + )?.managerId ?: return true + return try { + managerService.deleteSubsetManager(managerId.toString()) + authManagerRepository.deleteByTypeAndResourceIdAndParentResId(ResourceType.REPO, repoName, projectId) + true + } catch (e: Exception) { + logger.error("v3 deleteRepoGradeManager for repo $projectId|$repoName error: ${e.message}") + false + } + } + + private fun deleteProjectManager(projectId: String): Boolean { + val managerId = authManagerRepository.findByTypeAndResourceIdAndParentResId( + ResourceType.PROJECT, projectId, null + )?.managerId ?: return true + return try { + managerService.deleteManagerV2(managerId.toString()) + authManagerRepository.findAllByTypeAndParentResId(ResourceType.REPO, projectId).forEach{ + authManagerRepository.deleteByTypeAndResourceIdAndParentResId( + ResourceType.REPO, it.resourceId, projectId + ) + } + authManagerRepository.deleteByTypeAndResourceIdAndParentResId(ResourceType.PROJECT, projectId, null) + true + } catch (e: Exception) { + logger.error("v3 deleteProjectManager for repo $projectId error: ${e.message}") + false + } + } + fun createProjectGradeManager( + userId: String, + projectId: String + ): String? { + val projectInfo = projectClient.getProjectInfo(projectId).data!! + logger.debug("v3 start to create grade manager for project $projectId with user $userId") + // 如果已经创建project管理员,则返回 + var managerId = authManagerRepository.findByTypeAndResourceIdAndParentResId( + ResourceType.PROJECT, projectId, null + )?.managerId + if (managerId != null) { + logger.debug("v3 grade manager for project $projectId already existed") + return managerId.toString() + } + // 授权人员范围默认设置为全部人员 + val iamSubjectScopes = listOf(ManagerScopes(ManagerScopesEnum.getType(ManagerScopesEnum.ALL), "*")) + val projectResInfo = ResourceInfo(projectInfo.name, projectInfo.displayName, ResourceType.PROJECT) + val authorizationScopes = BkIamV3Utils.buildManagerResources( + projectResInfo = projectResInfo, + resActionMap = DefaultGroupTypeAndActions.PROJECT_MANAGER.actions, + iamConfiguration = iamConfiguration + ) + var name = "$SYSTEM_DEFAULT_NAME-$PROJECT_DEFAULT_NAME-${projectInfo.displayName}" + for (retry in 0..CONFLICT_RETRY) { + val createManagerDTO = CreateManagerDTO.builder().system(iamConfiguration.systemId) + .name(name) + .description(IamGroupUtils.buildManagerDescription(projectInfo.displayName, userId)) + .members(arrayListOf(userId)) + .authorization_scopes(authorizationScopes) + .subject_scopes(iamSubjectScopes).build() + try { + managerId = managerService.createManagerV2(createManagerDTO) + break + } catch (e: Exception) { + if (retry != CONFLICT_RETRY && e is IamException && e.errorCode == IAM_NAME_CONFLICT_ERROR) { + logger.warn("v3 create grade manager for project ${projectInfo.name} conflict: ${e.errorMsg}") + name += retry + } else { + logger.error("v3 create grade manager for project ${projectInfo.name} error: ${e.message}") + return null + } + } + } + + logger.debug("v3 The id of project [${projectInfo.name}]'s grade manager is $managerId") + saveTBkIamAuthManager(projectId, null, managerId!!, userId) + batchCreateDefaultGroups( + userId = userId, + gradeManagerId = managerId, + projectResInfo = projectResInfo, + members = setOf(userId), + groupList = listOf( + DefaultGroupType.PROJECT_MANAGER, + DefaultGroupType.PROJECT_DOWNLOAD, + DefaultGroupType.PROJECT_UPLOAD_DELETE + ) + ) + return managerId.toString() + } + + + /** + * 创建项目分级管理员 + */ + private fun createRepoGradeManager( + userId: String, + projectId: String, + repoName: String + ): String? { + val projectInfo = projectClient.getProjectInfo(projectId).data!! + val repoDetail = repositoryClient.getRepoInfo(projectId, repoName).data!! + // 如果已经创建repo管理员,则返回 + var repoManagerId = authManagerRepository.findByTypeAndResourceIdAndParentResId( + ResourceType.REPO, repoName, projectId + )?.managerId + if (repoManagerId != null) { + logger.debug("v3 grade manager for repo $projectId|$repoName already existed") + return repoManagerId.toString() + } + logger.debug("v3 start to create grade manager for repo $projectId|$repoName") + val projectResInfo = ResourceInfo(projectInfo.name, projectInfo.displayName, ResourceType.PROJECT) + val repoResInfo = ResourceInfo(repoDetail.id!!, repoDetail.name, ResourceType.REPO) + // 授权人员范围默认设置为全部人员 + val iamSubjectScopes = listOf(ManagerScopes(ManagerScopesEnum.getType(ManagerScopesEnum.ALL), "*")) + val authorizationScopes = BkIamV3Utils.buildManagerResources( + projectResInfo = projectResInfo, + repoResInfo = repoResInfo, + resActionMap = DefaultGroupTypeAndActions.REPO_MANAGER.actions, + iamConfiguration = iamConfiguration + ) + try { + // 如果项目没有创建managerId,则补充创建 + var projectManagerId = authManagerRepository.findByTypeAndResourceIdAndParentResId( + ResourceType.PROJECT, projectId, null + )?.managerId + ?: run { + val realUserId = userService.getUserInfoById(projectInfo.createdBy)?.asstUsers?.firstOrNull() + ?: projectInfo.createdBy + createProjectGradeManager(realUserId, projectId) + } + if (projectManagerId == null) { + projectManagerId = createProjectGradeManager(userId, projectId) + } + logger.debug("v3 create grade manager for repo [${projectInfo.name}|$repoName]," + + " projectManagerId: $projectManagerId") + val secondManagerMembers = mutableSetOf() + secondManagerMembers.add(userId) + val createRepoManagerDTO = CreateSubsetManagerDTO.builder() + .name("$SYSTEM_DEFAULT_NAME-$PROJECT_DEFAULT_NAME-${projectInfo.displayName}" + + "-$REPO_DEFAULT_NAME-${repoDetail.name}") + .description(IamGroupUtils.buildManagerDescription("${projectInfo.displayName}-${repoDetail.name}", userId)) + .members(secondManagerMembers.toList()) + .authorizationScopes(authorizationScopes) + .subjectScopes(iamSubjectScopes).build() + repoManagerId= managerService.createSubsetManager(projectManagerId.toString(), createRepoManagerDTO) + logger.debug("v3 The id of repo [${projectInfo.name}|$repoName]'s grade manager is $repoManagerId") + saveTBkIamAuthManager(projectId, repoName, repoManagerId, userId) + batchCreateDefaultGroups( + userId = userId, + gradeManagerId = repoManagerId, + projectResInfo = projectResInfo, + repoResInfo = repoResInfo, + members = secondManagerMembers, + groupList = listOf( + DefaultGroupType.REPO_MANAGER, + DefaultGroupType.REPO_DOWNLOAD, + DefaultGroupType.REPO_UPLOAD_DELETE + ) + ) + return repoManagerId.toString() + } catch (e: Exception) { + logger.error("v3 create grade manager for repo [${projectInfo.name}|$repoName] error: ${e.message}") + return null + } + } + + override fun getResourceId(resourceType: String, projectId: String?, repoName: String?, path: String?): String? { + return when (resourceType) { + ResourceType.SYSTEM.toString() -> StringPool.EMPTY + ResourceType.PROJECT.toString() -> projectId!! + ResourceType.REPO.toString() -> + convertRepoResourceId(projectId!!, repoName!!) + ResourceType.NODE.toString() -> + convertNodeResourceId(projectId!!, repoName!!, path!!) + else -> throw IllegalArgumentException("invalid resource type") + } + } + + override fun getExistRbacDefaultGroupProjectIds(ids: List): Map { + if (ids.isEmpty()) return emptyMap() + val existProjectIds = authManagerRepository.findAllByTypeAndParentResIdAndResourceIdIn( + ResourceType.PROJECT, null, ids + ) + val result: MutableMap = mutableMapOf() + existProjectIds.forEach { + result[it!!.resourceId] = true + } + return result + } + + private fun saveTBkIamAuthManager( + projectId: String, + repoName: String?, + managerId: Int, + userId: String + ) { + val tBkIamAuthManager = if (repoName == null) { + TBkIamAuthManager( + resourceId = projectId, + type = ResourceType.PROJECT, + managerId = managerId, + createdBy = userId, + createdDate = LocalDateTime.now(), + lastModifiedBy = userId, + lastModifiedDate = LocalDateTime.now()) + } else { + TBkIamAuthManager( + resourceId = repoName, + type = ResourceType.REPO, + managerId = managerId, + parentResId = projectId, + createdBy = userId, + createdDate = LocalDateTime.now(), + lastModifiedBy = userId, + lastModifiedDate = LocalDateTime.now() + ) + } + authManagerRepository.save( + tBkIamAuthManager + ) + } + + /** + * 批量创建默认group + */ + private fun batchCreateDefaultGroups( + userId: String, + gradeManagerId: Int, + projectResInfo: ResourceInfo, + repoResInfo: ResourceInfo? = null, + members: Set, + groupList: List + ) { + groupList.forEach { + createDefaultGroup( + userId = userId, + gradeManagerId = gradeManagerId, + projectResInfo = projectResInfo, + repoResInfo = repoResInfo, + defaultGroupType = it, + members = members + ) + } + } + + /** + * 创建默认用户组 + */ + private fun createDefaultGroup( + userId: String, + gradeManagerId: Int, + projectResInfo: ResourceInfo, + repoResInfo: ResourceInfo? = null, + defaultGroupType: DefaultGroupType, + members: Set + ) { + logger.debug("v3 start to create default group $defaultGroupType for $projectResInfo|$repoResInfo") + val (resName, resType) = if (repoResInfo == null) { + Pair(projectResInfo.resName, projectResInfo.resType) + } else { + Pair(repoResInfo.resName, repoResInfo.resType) + } + val defaultGroup = ManagerRoleGroup( + IamGroupUtils.buildIamGroup(resName, defaultGroupType.displayName), + IamGroupUtils.buildDefaultDescription(resName, defaultGroupType.displayName, userId), + false + ) + val managerRoleGroup = ManagerRoleGroupDTO.builder().groups(listOf(defaultGroup)).build() + val roleId = try { + when(resType) { + ResourceType.PROJECT -> managerService.batchCreateRoleGroupV2(gradeManagerId, managerRoleGroup) + ResourceType.REPO -> managerService.batchCreateSubsetRoleGroup(gradeManagerId, managerRoleGroup) + else -> return + } + } catch (e: Exception) { + logger.error("v3 batch create role for $projectResInfo|$repoResInfo error: ${e.message}") + return + } + logger.debug("v3 The id of default group $defaultGroupType for $projectResInfo|$repoResInfo is $roleId") + // 赋予权限 + try { + createRoleGroupMember(defaultGroupType, roleId, members) + val actions = DefaultGroupTypeAndActions.get(defaultGroupType.name.toLowerCase()).actions + grantGroupPermission(projectResInfo, repoResInfo, roleId, actions) + } catch (e: Exception) { + managerService.deleteRoleGroupV2(roleId) + logger.error( + "v3 create iam group permission fail : $projectResInfo|$repoResInfo" + + " iamRoleId = $roleId | groupInfo = ${defaultGroupType.value}", + e + ) + } + } + + private fun createRoleGroupMember(defaultGroupType: DefaultGroupType, roleId: Int, userIds: Set) { + if (defaultGroupType != DefaultGroupType.PROJECT_MANAGER && defaultGroupType != DefaultGroupType.REPO_MANAGER) { + return + } + val groupMembers = userIds.map { ManagerMember(ManagerScopesEnum.getType(ManagerScopesEnum.USER), it) } + val expired = System.currentTimeMillis() / 1000 + TimeUnit.DAYS.toSeconds(DEFAULT_EXPIRED_AT) + val managerMemberGroup = ManagerMemberGroupDTO.builder().members(groupMembers) + .expiredAt(expired).build() + // 项目创建人添加至管理员分组 + managerService.createRoleGroupMemberV2(roleId, managerMemberGroup) + } + + /** + * 用户组授权 + */ + private fun grantGroupPermission( + projectResInfo: ResourceInfo, + repoResInfo: ResourceInfo? = null, + roleId: Int, + actions: Map> + ) { + logger.debug("v3 grant role permission for group $roleId in $projectResInfo|$repoResInfo with actions $actions") + try { + actions.forEach{ + val permission = buildResource( + projectResInfo = projectResInfo, + repoResInfo = repoResInfo, + iamConfiguration = iamConfiguration, + actions = it.value, + resourceType = it.key + ) + managerService.grantRoleGroupV2(roleId, permission) + } + } catch (e: Exception) { + logger.error( + "v3 create role permission for $projectResInfo|$repoResInfo with actions $actions error: ${e.message}" + ) + } + } + + companion object { + private val logger = LoggerFactory.getLogger(BkIamV3ServiceImpl::class.java) + private const val DEFAULT_EXPIRED_AT = 365L // 用户组默认一年有效期 + private const val IAM_NAME_CONFLICT_ERROR = 1902409L + private const val CONFLICT_RETRY = 3 + private const val SYSTEM_DEFAULT_NAME = "制品库" + private const val PROJECT_DEFAULT_NAME = "项目" + private const val REPO_DEFAULT_NAME = "仓库" + } +} diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/BkiamV3BaseService.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/BkiamV3BaseService.kt new file mode 100644 index 0000000000..80a187f5b6 --- /dev/null +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/BkiamV3BaseService.kt @@ -0,0 +1,48 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.service.bkiamv3 + +import org.springframework.data.mongodb.core.MongoTemplate +import org.springframework.data.mongodb.core.find +import org.springframework.data.mongodb.core.query.Criteria +import org.springframework.data.mongodb.core.query.Query + +open class BkiamV3BaseService( + private val mongoTemplate: MongoTemplate +) { + + fun convertRepoResourceIdToRepoName(idList: List) : List> { + val repoQuery = Query.query(Criteria.where(ID).`in`(idList)) + return mongoTemplate.find>(repoQuery, COLLECTION_NAME) + } + + companion object { + private const val COLLECTION_NAME = "repository" + const val ID = "_id" + } +} diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiam/IamEsbClient.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/IamEsbClient.kt similarity index 84% rename from src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiam/IamEsbClient.kt rename to src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/IamEsbClient.kt index a98107f213..5c18599f32 100644 --- a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiam/IamEsbClient.kt +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/IamEsbClient.kt @@ -1,7 +1,7 @@ /* * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. * - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. * * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. * @@ -10,26 +10,22 @@ * * 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: + * 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 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. + * 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.bkrepo.auth.service.bkiam +package com.tencent.bkrepo.auth.service.bkiamv3 import com.fasterxml.jackson.module.kotlin.readValue import com.tencent.bkrepo.auth.pojo.iam.IamBaseReq diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/callback/BkiamCallbackService.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/callback/BkiamCallbackService.kt new file mode 100644 index 0000000000..d44cfbe39d --- /dev/null +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/callback/BkiamCallbackService.kt @@ -0,0 +1,104 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.service.bkiamv3.callback + +import com.tencent.bk.sdk.iam.dto.callback.request.CallbackRequestDTO +import com.tencent.bk.sdk.iam.dto.callback.response.CallbackBaseResponseDTO +import com.tencent.bk.sdk.iam.service.TokenService +import com.tencent.bkrepo.auth.condition.MultipleAuthCondition +import com.tencent.bkrepo.auth.constant.BASIC_AUTH_HEADER_PREFIX +import com.tencent.bkrepo.auth.exception.AuthFailedException +import com.tencent.bkrepo.auth.pojo.enums.ResourceType +import com.tencent.bkrepo.common.api.constant.StringPool +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Value +import org.springframework.context.annotation.Conditional +import org.springframework.stereotype.Service +import java.util.Base64 + +@Service +@Conditional(MultipleAuthCondition::class) +class BkiamCallbackService @Autowired constructor( + private val tokenService: TokenService +) { + @Value("\${auth.iam.callbackUser:}") + private val callbackUser = "" + + private var bufferedToken = "" + + fun queryProject(token: String, request: CallbackRequestDTO): CallbackBaseResponseDTO? { + logger.info("v3 queryProject, token: $token, request: $request") + checkToken(token) + return ResourceMappings.functionMap(ResourceType.PROJECT, request) + } + + fun queryRepo(token: String, request: CallbackRequestDTO): CallbackBaseResponseDTO? { + logger.info("v3 queryRepo, token: $token, request: $request") + checkToken(token) + return ResourceMappings.functionMap(ResourceType.REPO, request) + } + + fun queryNode(token: String, request: CallbackRequestDTO): CallbackBaseResponseDTO? { + logger.info("v3 queryNode, token: $token, request: $request") + checkToken(token) + return ResourceMappings.functionMap(ResourceType.NODE, request) + } + + private fun checkToken(token: String) { + val credentials = parseCredentials(token) + val userName = credentials.first + val password = credentials.second + if (userName != callbackUser) { + throw AuthFailedException("invalid iam user: $userName") + } + val tokenToCheck = password + if (bufferedToken.isNotBlank() && bufferedToken == tokenToCheck) { + return + } + bufferedToken = tokenService.token + if (bufferedToken != tokenToCheck) { + throw AuthFailedException("[$tokenToCheck] is not a valid credentials") + } + } + + private fun parseCredentials(token: String): Pair { + return try { + val encodedCredentials = token.removePrefix(BASIC_AUTH_HEADER_PREFIX) + val decodedToken = String(Base64.getDecoder().decode(encodedCredentials)) + val parts = decodedToken.split(StringPool.COLON) + Pair(parts[0], parts[1]) + } catch (exception: IllegalArgumentException) { + throw AuthFailedException("[$token] is not a valid token") + } + } + + companion object { + private val logger = LoggerFactory.getLogger(BkiamCallbackService::class.java) + } +} diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/callback/BkiamNodeResourceService.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/callback/BkiamNodeResourceService.kt new file mode 100644 index 0000000000..528e879d6c --- /dev/null +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/callback/BkiamNodeResourceService.kt @@ -0,0 +1,146 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.service.bkiamv3.callback + +import com.tencent.bk.sdk.iam.dto.PageInfoDTO +import com.tencent.bk.sdk.iam.dto.callback.request.CallbackRequestDTO +import com.tencent.bk.sdk.iam.dto.callback.response.BaseDataResponseDTO +import com.tencent.bk.sdk.iam.dto.callback.response.CallbackBaseResponseDTO +import com.tencent.bk.sdk.iam.dto.callback.response.InstanceInfoDTO +import com.tencent.bkrepo.auth.pojo.enums.ResourceType +import com.tencent.bkrepo.auth.util.BkIamV3Utils.buildId +import com.tencent.bkrepo.auth.util.BkIamV3Utils.splitId +import com.tencent.bkrepo.common.mongo.dao.util.sharding.HashShardingUtils +import com.tencent.bkrepo.repository.api.NodeClient +import com.tencent.bkrepo.repository.pojo.node.NodeInfo +import com.tencent.bkrepo.repository.pojo.node.NodeListOption +import com.tencent.bkrepo.repository.pojo.repo.RepositoryInfo +import org.slf4j.LoggerFactory +import org.springframework.data.mongodb.core.MongoTemplate +import org.springframework.data.mongodb.core.find +import org.springframework.data.mongodb.core.query.Criteria +import org.springframework.data.mongodb.core.query.Query +import org.springframework.data.mongodb.core.query.isEqualTo +import org.springframework.stereotype.Component + +/** + * 节点资源回调实现 + */ +@Component +class BkiamNodeResourceService( + private val nodeClient: NodeClient, + private val mongoTemplate: MongoTemplate + ): BkiamResourceBaseService { + override fun resourceType(): ResourceType { + return ResourceType.NODE + } + + override fun fetchInstanceInfo(request: CallbackRequestDTO): CallbackBaseResponseDTO { + logger.info("v3 Node fetchInstanceInfo, request $request") + val ids = request.filter.idList.map { it.toString() } + return buildFetchInstanceInfoResponseDTO(filterNodeInfo(ids)) + } + + override fun searchInstanceInfo(request: CallbackRequestDTO): CallbackBaseResponseDTO { + logger.info("v3 Node searchInstanceInfo, request $request") + val parentId = request.filter.parent.id + return buildSearchInstanceResponseDTO( + listNode(parentId = parentId, page = request.page, path = request.filter.keyword) + ) + } + + override fun listInstanceInfo(request: CallbackRequestDTO): CallbackBaseResponseDTO { + logger.info("v3 Node listInstanceInfo, request $request") + val parentId = request.filter.parent.id + return buildListInstanceResponseDTO( + listNode(parentId = parentId, page = request.page) + ) + } + + + private fun filterNodeInfo( + idList: List + ): List { + logger.info("v3 filterNodeInfo, idList: $idList") + val result = mutableListOf() + idList.forEach { + val (id, index) = splitId(it) + val nodeQuery = Query.query(Criteria.where(ID).isEqualTo(id)) + val data = mongoTemplate.find>(nodeQuery, "$NODE_COLLECTION_NAME$index") + if (data.isEmpty()) return@forEach + val entity = InstanceInfoDTO() + entity.id = it + entity.displayName = data.first()[NodeInfo::fullPath.name].toString() + result.add(entity) + } + return result + } + + private fun getRepoNameById(id: String?): Pair?{ + if (id == null) return null + val nodeQuery = Query.query(Criteria.where(ID).isEqualTo(id)) + val data = mongoTemplate.find>(nodeQuery, REPO_COLLECTION_NAME) + if (data.isEmpty()) return null + return Pair( + data.first()[RepositoryInfo::projectId.name].toString(), + data.first()[RepositoryInfo::name.name].toString() + ) + } + + private fun listNode( + parentId: String, + page: PageInfoDTO? = null, + path: String = "/" + ): BaseDataResponseDTO { + logger.info("v3 listNode, parentId: $parentId, page $page, id: $path") + val (projectId, repoName) = getRepoNameById(parentId) ?: return buildBaseDataResponseDTO(0, emptyList()) + val index = HashShardingUtils.shardingSequenceFor(projectId, 256).toString() + var offset = 0 + var limit = 20 + if (page != null) { + offset = page.offset.toInt() + limit = page.limit.toInt() + } + val nodePage = nodeClient.listNodePage( + projectId, repoName, path, NodeListOption(pageNumber = offset, pageSize = limit, deep = true) + ).data!! + val nodes = nodePage.records.map { + val entity = InstanceInfoDTO() + entity.id = buildId(it.id!!, index) + entity.displayName = it.fullPath + entity + } + return buildBaseDataResponseDTO(nodePage.totalRecords, nodes) + } + companion object { + private val logger = LoggerFactory.getLogger(BkiamNodeResourceService::class.java) + private const val REPO_COLLECTION_NAME = "repository" + private const val NODE_COLLECTION_NAME = "node_" + private const val ID = "_id" + } +} diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/callback/BkiamProjectResourceService.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/callback/BkiamProjectResourceService.kt new file mode 100644 index 0000000000..e83c9bdbe7 --- /dev/null +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/callback/BkiamProjectResourceService.kt @@ -0,0 +1,105 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.service.bkiamv3.callback + +import com.tencent.bk.sdk.iam.dto.PageInfoDTO +import com.tencent.bk.sdk.iam.dto.callback.request.CallbackRequestDTO +import com.tencent.bk.sdk.iam.dto.callback.response.BaseDataResponseDTO +import com.tencent.bk.sdk.iam.dto.callback.response.CallbackBaseResponseDTO +import com.tencent.bk.sdk.iam.dto.callback.response.InstanceInfoDTO +import com.tencent.bkrepo.auth.pojo.enums.ResourceType +import com.tencent.bkrepo.repository.api.ProjectClient +import com.tencent.bkrepo.repository.pojo.project.ProjectRangeQueryRequest +import org.slf4j.LoggerFactory +import org.springframework.stereotype.Component + +/** + * 项目资源回调实现 + */ +@Component +class BkiamProjectResourceService( + private val projectClient: ProjectClient +): BkiamResourceBaseService { + override fun resourceType(): ResourceType { + return ResourceType.PROJECT + } + + override fun fetchInstanceInfo(request: CallbackRequestDTO): CallbackBaseResponseDTO { + logger.info("v3 Project fetchInstanceInfo, request $request") + val ids = request.filter.idList.map { it.toString() } + return buildFetchInstanceInfoResponseDTO(filterProjectInfo(ids)) + } + + override fun searchInstanceInfo(request: CallbackRequestDTO): CallbackBaseResponseDTO { + logger.info("v3 Project searchInstanceInfo, request $request") + val ids = listOf(request.filter.keyword) + return buildSearchInstanceResponseDTO(listProject(page = request.page, idList = ids)) + } + + override fun listInstanceInfo(request: CallbackRequestDTO): CallbackBaseResponseDTO { + logger.info("v3 Project listInstanceInfo, request $request") + return buildListInstanceResponseDTO(listProject(page = request.page)) + } + + + private fun filterProjectInfo(idList: List): List { + logger.info("v3 filterProjectInfo, idList: $idList") + val projectPage = projectClient.rangeQuery(ProjectRangeQueryRequest(idList, 0, 10000)).data!! + + return projectPage.records.map { + val entity = InstanceInfoDTO() + entity.id = it!!.name + entity.displayName = it.displayName + entity + } + } + + private fun listProject( + page: PageInfoDTO? = null, + idList: List = emptyList() + ): BaseDataResponseDTO { + logger.info("v3 listProject, page $page, ids: $idList") + var offset = 0L + var limit = 20 + if (page != null) { + offset = page.offset + limit = page.limit.toInt() + } + val projectPage = projectClient.rangeQuery(ProjectRangeQueryRequest(idList, offset, limit)).data!! + val projects = projectPage.records.map { + val entity = InstanceInfoDTO() + entity.id = it!!.name + entity.displayName = it.displayName + entity + } + return buildBaseDataResponseDTO(projectPage.totalRecords, projects) + } + companion object { + private val logger = LoggerFactory.getLogger(BkiamProjectResourceService::class.java) + } +} diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/callback/BkiamRepoResourceService.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/callback/BkiamRepoResourceService.kt new file mode 100644 index 0000000000..fa2fcac48f --- /dev/null +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/callback/BkiamRepoResourceService.kt @@ -0,0 +1,113 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.service.bkiamv3.callback + +import com.tencent.bk.sdk.iam.dto.PageInfoDTO +import com.tencent.bk.sdk.iam.dto.callback.request.CallbackRequestDTO +import com.tencent.bk.sdk.iam.dto.callback.response.BaseDataResponseDTO +import com.tencent.bk.sdk.iam.dto.callback.response.CallbackBaseResponseDTO +import com.tencent.bk.sdk.iam.dto.callback.response.InstanceInfoDTO +import com.tencent.bkrepo.auth.pojo.enums.ResourceType +import com.tencent.bkrepo.auth.service.bkiamv3.BkiamV3BaseService +import com.tencent.bkrepo.repository.api.RepositoryClient +import com.tencent.bkrepo.repository.pojo.project.RepoRangeQueryRequest +import com.tencent.bkrepo.repository.pojo.repo.RepositoryInfo +import org.slf4j.LoggerFactory +import org.springframework.data.mongodb.core.MongoTemplate +import org.springframework.stereotype.Component + +/** + * 仓库资源回调实现 + */ +@Component +class BkiamRepoResourceService( + private val repositoryClient: RepositoryClient, + val mongoTemplate: MongoTemplate +): BkiamResourceBaseService, BkiamV3BaseService(mongoTemplate) { + override fun resourceType(): ResourceType { + return ResourceType.REPO + } + + override fun fetchInstanceInfo(request: CallbackRequestDTO): CallbackBaseResponseDTO { + logger.info("v3 Repo fetchInstanceInfo, request $request") + val ids = request.filter.idList.map { it.toString() } + return buildFetchInstanceInfoResponseDTO(filterRepoInfo(ids)) + } + + override fun searchInstanceInfo(request: CallbackRequestDTO): CallbackBaseResponseDTO { + logger.info("v3 Repo searchInstanceInfo, request $request") + val projectId = request.filter.parent.id + val ids = listOf(request.filter.keyword) + return buildSearchInstanceResponseDTO(listRepo(projectId = projectId, page = request.page, idList = ids)) + } + + override fun listInstanceInfo(request: CallbackRequestDTO): CallbackBaseResponseDTO { + logger.info("v3 Repo listInstanceInfo, request $request") + val projectId = request.filter.parent.id + return buildListInstanceResponseDTO(listRepo(projectId = projectId, page = request.page)) + } + + + private fun filterRepoInfo(idList: List): List { + logger.info("v3 filterRepoInfo, idList: $idList") + val data = convertRepoResourceIdToRepoName(idList) + return data.map { + val entity = InstanceInfoDTO() + entity.id = it[ID].toString() + entity.displayName = it[RepositoryInfo::name.name].toString() + entity + } + } + + + private fun listRepo( + projectId: String, + page: PageInfoDTO? = null, + idList: List = emptyList() + ): BaseDataResponseDTO { + logger.info("v3 listRepo, projectId: $projectId, page: $page, ids: $idList") + var offset = 0L + var limit = 20 + if (page != null) { + offset = page.offset + limit = page.limit.toInt() + } + val repoPage = repositoryClient.rangeQuery(RepoRangeQueryRequest(idList, projectId, offset, limit)).data!! + val repos = repoPage.records.map { + val entity = InstanceInfoDTO() + entity.id = it!!.id + entity.displayName = it.name + entity + } + return buildBaseDataResponseDTO(repoPage.totalRecords, repos) + } + + companion object { + private val logger = LoggerFactory.getLogger(BkiamRepoResourceService::class.java) + } +} diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/callback/BkiamResourceBaseService.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/callback/BkiamResourceBaseService.kt new file mode 100644 index 0000000000..cde446ba77 --- /dev/null +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/callback/BkiamResourceBaseService.kt @@ -0,0 +1,84 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.service.bkiamv3.callback + +import com.tencent.bk.sdk.iam.dto.callback.request.CallbackRequestDTO +import com.tencent.bk.sdk.iam.dto.callback.response.BaseDataResponseDTO +import com.tencent.bk.sdk.iam.dto.callback.response.CallbackBaseResponseDTO +import com.tencent.bk.sdk.iam.dto.callback.response.FetchInstanceInfoResponseDTO +import com.tencent.bk.sdk.iam.dto.callback.response.InstanceInfoDTO +import com.tencent.bk.sdk.iam.dto.callback.response.ListInstanceResponseDTO +import com.tencent.bk.sdk.iam.dto.callback.response.SearchInstanceResponseDTO +import com.tencent.bkrepo.auth.pojo.enums.ResourceType + +/** + * 权限中心资源反向拉取 + */ +interface BkiamResourceBaseService { + fun resourceType(): ResourceType + + fun fetchInstanceInfo(request: CallbackRequestDTO): CallbackBaseResponseDTO + + fun searchInstanceInfo(request: CallbackRequestDTO): CallbackBaseResponseDTO + + fun listInstanceInfo(request: CallbackRequestDTO): CallbackBaseResponseDTO + + fun buildFetchInstanceInfoResponseDTO(data: List) : CallbackBaseResponseDTO { + val result = FetchInstanceInfoResponseDTO() + result.code = 0 + result.message = "" + result.data = data + return result + } + + fun buildSearchInstanceResponseDTO(data: BaseDataResponseDTO): CallbackBaseResponseDTO { + val result = SearchInstanceResponseDTO() + result.code = 0L + result.message = "" + result.data = data + return result + } + + fun buildListInstanceResponseDTO(data: BaseDataResponseDTO): CallbackBaseResponseDTO { + val result = ListInstanceResponseDTO() + result.code = 0L + result.message = "" + result.data = data + return result + } + + fun buildBaseDataResponseDTO( + count: Long, + records: List + ): BaseDataResponseDTO { + val data = BaseDataResponseDTO() + data.count = count + data.result = records + return data + } +} diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/callback/ResourceMappings.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/callback/ResourceMappings.kt new file mode 100644 index 0000000000..0e673fb7da --- /dev/null +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/bkiamv3/callback/ResourceMappings.kt @@ -0,0 +1,65 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.service.bkiamv3.callback + +import com.tencent.bk.sdk.iam.constants.CallbackMethodEnum +import com.tencent.bk.sdk.iam.dto.callback.request.CallbackRequestDTO +import com.tencent.bk.sdk.iam.dto.callback.response.CallbackBaseResponseDTO +import com.tencent.bkrepo.auth.pojo.enums.ResourceType +import com.tencent.bkrepo.common.service.util.SpringContextUtils + +object ResourceMappings { + + private val mappers = mutableMapOf() + + init { + addMapper(SpringContextUtils.getBean(BkiamProjectResourceService::class.java)) + addMapper(SpringContextUtils.getBean(BkiamRepoResourceService::class.java)) + addMapper(SpringContextUtils.getBean(BkiamNodeResourceService::class.java)) + } + + private fun addMapper(service: BkiamResourceBaseService) { + mappers[service.resourceType()] = service + } + + fun functionMap(resType: ResourceType, request: CallbackRequestDTO): CallbackBaseResponseDTO { + val resourceService = mappers[resType] + check(resourceService != null) { "mapper[$resType] not found" } + return when(request.method) { + CallbackMethodEnum.FETCH_INSTANCE_INFO -> { + resourceService.fetchInstanceInfo(request) + } + CallbackMethodEnum.SEARCH_INSTANCE -> { + resourceService.searchInstanceInfo(request) + } + else -> { + resourceService.listInstanceInfo(request) + } + } + } +} diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/local/PermissionServiceImpl.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/local/PermissionServiceImpl.kt index 2620284509..7bca0437f1 100644 --- a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/local/PermissionServiceImpl.kt +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/service/local/PermissionServiceImpl.kt @@ -79,8 +79,8 @@ open class PermissionServiceImpl constructor( private val account: AccountRepository, private val permissionRepository: PermissionRepository, private val mongoTemplate: MongoTemplate, - private val repoClient: RepositoryClient, - private val projectClient: ProjectClient + val repoClient: RepositoryClient, + val projectClient: ProjectClient ) : PermissionService, AbstractServiceImpl(mongoTemplate, userRepository, roleRepository) { override fun deletePermission(id: String): Boolean { diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/util/BkIamV3Utils.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/util/BkIamV3Utils.kt new file mode 100644 index 0000000000..b30a3f5946 --- /dev/null +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/util/BkIamV3Utils.kt @@ -0,0 +1,352 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.util + +import com.tencent.bk.sdk.iam.config.IamConfiguration +import com.tencent.bk.sdk.iam.constants.ExpressionOperationEnum +import com.tencent.bk.sdk.iam.dto.expression.ExpressionDTO +import com.tencent.bk.sdk.iam.dto.manager.Action +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 +import com.tencent.bkrepo.auth.pojo.enums.ActionTypeMapping +import com.tencent.bkrepo.auth.pojo.enums.ResourceType +import com.tencent.bkrepo.auth.pojo.iam.ResourceInfo +import com.tencent.bkrepo.common.api.constant.StringPool + +object BkIamV3Utils { + fun buildManagerResources( + projectResInfo: ResourceInfo, + repoResInfo: ResourceInfo? = null, + resActionMap: Map>, + iamConfiguration: IamConfiguration + ): List { + val authorizationScopes = mutableListOf() + resActionMap.forEach { + authorizationScopes.add( + buildResource( + projectResInfo = projectResInfo, + repoResInfo = repoResInfo, + iamConfiguration = iamConfiguration, + actions = it.value, + resourceType = it.key + ) + ) + } + return authorizationScopes + } + + fun buildResource( + projectResInfo: ResourceInfo, + repoResInfo: ResourceInfo? = null, + iamConfiguration: IamConfiguration, + actions: List, + resourceType: String + ): AuthorizationScopes { + val realRepoResInfo = if (resourceType == ResourceType.PROJECT.id()) { + null + } else { + repoResInfo + } + val projectManagerPath = ManagerPath( + iamConfiguration.systemId, + projectResInfo.resType.id(), + projectResInfo.resId, + projectResInfo.resName + ) + val managerPaths = mutableListOf() + managerPaths.add(projectManagerPath) + realRepoResInfo?.let { + val repoManagerPath = ManagerPath( + iamConfiguration.systemId, + realRepoResInfo.resType.id(), + realRepoResInfo.resId, + realRepoResInfo.resName + ) + managerPaths.add(repoManagerPath) + } + val paths = mutableListOf>() + paths.add(managerPaths) + val resource = ManagerResources.builder() + .system(iamConfiguration.systemId) + .type(resourceType) + .paths(paths) + .build() + val resources = mutableListOf() + resources.add(resource) + val action = mutableListOf() + actions.forEach { + action.add(Action(it)) + } + return AuthorizationScopes + .builder() + .system(iamConfiguration.systemId) + .actions(action) + .resources(resources) + .build() + } + + /** + * 节点因为分表,节点资源唯一id由数据库_id和分表index组成 + * 权限中心id限制长度为36个字符 + */ + fun buildId(first: String, second: String): String { + val stringBuilder = StringBuilder() + return stringBuilder.append(first).append(StringPool.COLON).append(second).toString() + } + + fun splitId(id: String) : Pair { + val values = id.split(StringPool.COLON) + return Pair(values.first(), values.last()) + } + + + fun convertActionType(resourceTyp: String, action: String) : String { + return ActionTypeMapping.lookup(resourceTyp, action).id() + } + + fun getProjects(content: ExpressionDTO): List { + + if (content.field != "project.id") { + when(content.operator) { + ExpressionOperationEnum.ANY, + ExpressionOperationEnum.OR, + ExpressionOperationEnum.AND, + ExpressionOperationEnum.START_WITH -> { + } + else -> return emptyList() + } + } + val projectList = mutableListOf() + when (content.operator) { + ExpressionOperationEnum.START_WITH -> getProjectFromExpression(content)?.let {projectList.add(it) } + ExpressionOperationEnum.ANY -> projectList.add("*") + ExpressionOperationEnum.EQUAL -> projectList.add(content.value.toString()) + ExpressionOperationEnum.IN -> projectList.addAll(StringUtils.obj2List(content.value.toString())) + ExpressionOperationEnum.OR, ExpressionOperationEnum.AND -> content.content.forEach { + projectList.addAll(getProjects(it)) + } + else -> { + } + } + return projectList + } + + // 无content怎么处理 一层怎么处理,二层怎么处理。 默认只有两层。 + fun getResourceInstance(expression: ExpressionDTO, projectId: String, resourceType: String): Set { + val instantList = mutableSetOf() + if (expression.content.isNullOrEmpty()) { + instantList.addAll(getInstanceByField(expression, projectId, resourceType)) + } else { + instantList.addAll(getInstanceByContent(expression.content, expression, projectId, resourceType)) + } + return instantList + } + + private fun getInstanceByContent( + childExpression: List, + parentExpression: ExpressionDTO, + projectId: String, + resourceType: String + ): Set { + return getInstanceByContent( + childExpression = childExpression, + projectId = projectId, + resourceType = resourceType, + type = parentExpression.operator + ) + } + + private fun getInstanceByContent( + childExpression: List, + projectId: String, + resourceType: String, + type: ExpressionOperationEnum + ): Set { + val cacheList = mutableSetOf() + + childExpression.map { + if (!it.content.isNullOrEmpty()) { + val result = filterNonNullContent(it, projectId, resourceType, type, cacheList) + if (result != null) { + return result + } + return@map + } + + if (!checkField(it.field, resourceType) && !checkField(it.value.toString(), resourceType)) { + if (!andCheck(cacheList, type)) { + return emptySet() + } + return@map + } + val compareResult = compareOperatorWithNullContent(it, projectId, type, cacheList) + if (compareResult != null) { + return compareResult + } + if (!andCheck(cacheList, type)) { + return emptySet() + } + + // 如果有“*” 表示项目下所有的实例都有权限,直接按“*”返回 + if (cacheList.contains("*")) { + return cacheList + } + } + + return cacheList + } + + private fun filterNonNullContent( + exp: ExpressionDTO, + projectId: String, + resourceType: String, + type: ExpressionOperationEnum, + cacheList: MutableSet + ): Set? { + val childInstanceList = getInstanceByContent(exp.content, projectId, resourceType, exp.operator) + if (childInstanceList.isNotEmpty()) { + // 如果有策略解析出来为“*”,则直接返回 + if (childInstanceList.contains("*")) { + return childInstanceList + } + cacheList.addAll(childInstanceList) + } else { + // 若表达式为AND拼接,检测到不满足条件则直接返回空数组 + if (!andCheck(cacheList, type)) { + return emptySet() + } + } + return null + } + + private fun compareOperatorWithNullContent( + exp: ExpressionDTO, + projectId: String, + type: ExpressionOperationEnum, + cacheList: MutableSet + ): Set? { + when (exp.operator) { + ExpressionOperationEnum.ANY -> { + cacheList.add("*") + return cacheList + } + ExpressionOperationEnum.IN -> { + cacheList.addAll(StringUtils.obj2List(exp.value.toString())) + StringUtils.removeAllElement(cacheList) + } + ExpressionOperationEnum.EQUAL -> { + cacheList.add(exp.value.toString()) + StringUtils.removeAllElement(cacheList) + } + ExpressionOperationEnum.START_WITH -> { + // 两种情况: 1. 跟IN,EQUAL组合成项目下的某实例 2. 单指某个项目下的所有实例 + val startWithPair = checkProject(projectId, exp) + // 跟IN,EQUAL结合才会出现type = AND + if (type == ExpressionOperationEnum.AND) { + // 项目未命中直接返回空数组 + // 命中则引用IN,EQUAL的数据,不将“*”加入到cacheList + if (!startWithPair.first) { + return emptySet() + } + } else { + // 若为项目级别,直接按projectCheck结果返回 + cacheList.addAll(startWithPair.second) + } + } + else -> cacheList.clear() + } + return null + } + + private fun getInstanceByField(expression: ExpressionDTO, projectId: String, resourceType: String): Set { + val instanceList = mutableSetOf() + val value = expression.value + + // 如果权限为整个项目, 直接返回 + if (expression.value == projectId && expression.operator == ExpressionOperationEnum.EQUAL) { + instanceList.add("*") + return instanceList + } + + if (!checkField(expression.field, resourceType)) { + return emptySet() + } + + when (expression.operator) { + ExpressionOperationEnum.ANY -> instanceList.add("*") + ExpressionOperationEnum.EQUAL -> instanceList.add(value.toString()) + ExpressionOperationEnum.IN -> instanceList.addAll(StringUtils.obj2List(value.toString())) + ExpressionOperationEnum.START_WITH -> { + instanceList.addAll(checkProject(projectId, expression).second) + } + else -> { + } + } + + return instanceList + } + + + private fun checkProject(projectId: String, expression: ExpressionDTO): Pair> { + val instanceList = mutableSetOf() + val values = expression.value.toString().split(",") + if (values[0] != "/project") { + return Pair(false, emptySet()) + } + if (values[1].substringBefore("/") != projectId) { + return Pair(false, emptySet()) + } + instanceList.add("*") + return Pair(true, instanceList) + } + + private fun getProjectFromExpression(expression: ExpressionDTO): String? { + val values = expression.value.toString().split(",") + if (values[0] != "/project") return null + return values[1].substringBefore("/") + } + + private fun checkField(field: String, resourceType: String): Boolean { + if (field.contains(resourceType)) { + return true + } + return false + } + + private fun andCheck(instanceList: Set, op: ExpressionOperationEnum): Boolean { + if (op == ExpressionOperationEnum.AND) { + if (instanceList.isEmpty()) { + return false + } + return true + } + return true + } + +} diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/util/BkiamUtils.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/util/BkiamUtils.kt deleted file mode 100644 index c9dac76911..0000000000 --- a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/util/BkiamUtils.kt +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. - * - * Copyright (C) 2020 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.bkrepo.auth.util - -import com.tencent.bk.sdk.iam.constants.ExpressionOperationEnum -import com.tencent.bk.sdk.iam.dto.expression.ExpressionDTO -import com.tencent.bkrepo.auth.exception.BkiamException - -object BkiamUtils { - - fun buildAction(resourceType: String, action: String) = "${resourceType}_$action" - - fun getProjects(content: ExpressionDTO): List { - if (content.field != "project.id") { - if (content.operator != ExpressionOperationEnum.ANY) { - return emptyList() - } - } - val projectList = mutableListOf() - when (content.operator) { - ExpressionOperationEnum.ANY -> projectList.add("*") - ExpressionOperationEnum.EQUAL -> projectList.add(content.value.toString()) - ExpressionOperationEnum.IN -> projectList.addAll(StringUtils.obj2List(content.value.toString())) - else -> throw BkiamException("unsupported operation") - } - return projectList - } - - fun getResourceInstance( - content: List, - projectId: String, - resourceType: String - ): Set { - val instantList = mutableSetOf() - content.map { - val field = it.field - val op = it.operator - if (!field.contains("_bk_iam_path_") || op != ExpressionOperationEnum.START_WITH) { - return@map - } - val value = it.value.toString().split(",") - if (value[0] != "/project") { - return@map - } - - // 选中了项目下 “无限制”选项 - if (value.size == 2) { - if (value[1].substringBefore("/") == projectId) { - return setOf("*") - } else { - return@map - } - } - - // 选中了项目下某资源的 特定实例 - // 如 /project,projectA/pipeline,pipelineB/ - if (value[1].substringBefore("/") != projectId || value[1].substringAfter("/") != resourceType) { - return@map - } - val instance = value[2].substringBefore("/") - if (instance == "*") { - return setOf("*") - } else { - instantList.add(value[2].substringBefore("/")) - } - } - return instantList - } - - // 无content怎么处理 一层怎么处理,二层怎么处理。 默认只有两层。 - fun getResourceInstance(expression: ExpressionDTO, projectId: String, resourceType: String): Set { - val instantList = mutableSetOf() - // 项目下无限制 {"field":"pipeline._bk_iam_path_","op":"starts_with","value":"/project,test1/"} - if (expression.content == null || expression.content.isEmpty()) { - instantList.addAll(getInstanceByField(expression, projectId, resourceType)) - } else { - instantList.addAll(getInstanceByContent(expression.content, expression, projectId, resourceType)) - } - - // 单个项目下有特定资源若干实例 - // [{"field":"pipeline.id","op":"in","value":["p-098b68a251ae4ec4b6f4fde87767387f", - // "p-12b2c343109f43a58a79dcb9e3721c1b","p-54a8619d1f754d32b5b2bc249a74f26c"]}, - // {"field":"pipeline._bk_iam_path_","op":"starts_with","value":"/project,demo/"}] - - // 多个项目下有特定资源若干实例 - // [{"content":[{"field":"pipeline.id","op":"in","value":["p-0d1fff4dabca4fc282e5ff63644bd339", - // "p-54fb8b6562584df4b3693f7c787c105a"]},{"field":"pipeline._bk_iam_path_","op":"starts_with", - // "value":"/project,v3test/"}],"op":"AND"},{"content":[{"field":"pipeline.id","op":"in", - // "value":["p-098b68a251ae4ec4b6f4fde87767387f","p-12b2c343109f43a58a79dcb9e3721c1b", - // "p-54a8619d1f754d32b5b2bc249a74f26c"]},{"field":"pipeline._bk_iam_path_", - // "op":"starts_with","value":"/project,demo/"}],"op":"AND"}] - - // 多个项目下有特定资源权限,且有项目勾选任意 - // [{"field":"pipeline._bk_iam_path_","op":"starts_with","value":"/project,demo/"}, - // {"content":[{"field":"pipeline.id","op":"in","value":["p-0d1fff4dabca4fc282e5ff63644bd339", - // "p-54fb8b6562584df4b3693f7c787c105a"]},{"field":"pipeline._bk_iam_path_","op":"starts_with", - // "value":"/project,v3test/"}],"op":"AND"}] - return instantList - } - - private fun getInstanceByContent( - childExpression: List, - parentExpression: ExpressionDTO, - projectId: String, - resourceType: String - ): Set { - val instantList = mutableSetOf() - when (parentExpression.operator) { - ExpressionOperationEnum.AND -> instantList.addAll( - getInstanceByContent( - childExpression, - projectId, - resourceType, - parentExpression.operator - ) - ) - ExpressionOperationEnum.OR -> instantList.addAll( - getInstanceByContent( - childExpression, - projectId, - resourceType, - parentExpression.operator - ) - ) - else -> throw BkiamException("unsupported operation") - } - return instantList - } - - @Suppress("ALL") - private fun getInstanceByContent( - childExpression: List, - projectId: String, - resourceType: String, - type: ExpressionOperationEnum - ): Set { - var cacheList = mutableSetOf() - var isReturn = false - var successCount = 0 - childExpression.map { - if (it.content != null && it.content.isNotEmpty()) { - val childInstanceList = getInstanceByContent(it.content, projectId, resourceType, it.operator) - if (childInstanceList.isNotEmpty()) { - cacheList.addAll(childInstanceList) - isReturn = true - successCount += 1 - } else { - if (!andCheck(cacheList, type)) { - return emptySet() - } - } - return@map - } - - if (!checkField(it.field, resourceType) && !checkField(it.value.toString(), resourceType)) { - if (!andCheck(cacheList, type)) { - return emptySet() - } - return@map - } - when (it.operator) { - ExpressionOperationEnum.IN -> { - cacheList.addAll(StringUtils.obj2List(it.value.toString())) - StringUtils.removeAllElement(cacheList) - isReturn = true - successCount += 1 - } - ExpressionOperationEnum.EQUAL -> { - cacheList.add(it.value.toString()) - StringUtils.removeAllElement(cacheList) - isReturn = true - successCount += 1 - } - ExpressionOperationEnum.START_WITH -> { - val startWithPair = checkProject(projectId, it) - if (!startWithPair.first && type == ExpressionOperationEnum.AND) { - cacheList.clear() - if (!andCheck(cacheList, type)) { - return emptySet() - } - } - isReturn = startWithPair.first - if (isReturn && cacheList.size == 0) { - cacheList.addAll(startWithPair.second) - } - } - else -> cacheList = emptySet() as MutableSet - } - if (!andCheck(cacheList, type)) { - return emptySet() - } - } - - return when { - isReturn -> { - cacheList - } - successCount > 0 -> { - cacheList - } - else -> { - emptySet() - } - } - } - - fun getInstanceByField(expression: ExpressionDTO, projectId: String, resourceType: String): Set { - val instanceList = mutableSetOf() - val value = expression.value - - if (!checkField(expression.field, resourceType)) { - return emptySet() - } - - when (expression.operator) { - ExpressionOperationEnum.ANY -> instanceList.add("*") - ExpressionOperationEnum.EQUAL -> instanceList.add(value.toString()) - ExpressionOperationEnum.IN -> instanceList.addAll(StringUtils.obj2List(value.toString())) - ExpressionOperationEnum.START_WITH -> { - instanceList.addAll(checkProject(projectId, expression).second) - } - else -> throw BkiamException("unsupported operation") - } - - return instanceList - } - - private fun checkProject(projectId: String, expression: ExpressionDTO): Pair> { - val instanceList = mutableSetOf() - val values = expression.value.toString().split(",") - if (values[0] != "/project") { - return Pair(false, emptySet()) - } - if (values[1].substringBefore("/") != projectId) { - return Pair(false, emptySet()) - } - instanceList.add("*") - return Pair(true, instanceList) - } - - private fun checkField(field: String, resourceType: String): Boolean { - if (field.contains(resourceType)) { - return true - } - return false - } - - private fun andCheck(instanceList: Set, op: ExpressionOperationEnum): Boolean { - if (op == ExpressionOperationEnum.AND) { - if (instanceList.isEmpty()) { - return false - } - return true - } - return true - } -} diff --git a/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/util/IamGroupUtils.kt b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/util/IamGroupUtils.kt new file mode 100644 index 0000000000..63dd06e8cf --- /dev/null +++ b/src/backend/auth/biz-auth/src/main/kotlin/com/tencent/bkrepo/auth/util/IamGroupUtils.kt @@ -0,0 +1,62 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2022 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.bkrepo.auth.util + +import java.text.SimpleDateFormat +import java.time.LocalDateTime +import java.time.ZoneId +import java.util.Date + +object IamGroupUtils { + fun buildIamGroup(projectName: String, groupName: String): String { + return "$projectName-$groupName" + } + + fun buildDefaultDescription(projectName: String, groupName: String, userId: String): String { + return "$projectName 用户组:$groupName,由$userId 创建于 " + + toDateTime(LocalDateTime.now(), "yyyy-MM-dd'T'HH:mm:ssZ") + } + + fun buildManagerDescription(projectName: String, userId: String): String { + return "$projectName 分级管理员, 由$userId 创建于" + + toDateTime(LocalDateTime.now(), "yyyy-MM-dd'T'HH:mm:ssZ") + } + + fun renameSystemLable(groupName: String): String { + return groupName.substringAfterLast("-") + } + fun toDateTime(dateTime: LocalDateTime?, format: String): String { + if (dateTime == null) { + return "" + } + val zone = ZoneId.systemDefault() + val instant = dateTime.atZone(zone).toInstant() + val simpleDateFormat = SimpleDateFormat(format) + return simpleDateFormat.format(Date.from(instant)) + } +} diff --git a/src/backend/build.sh b/src/backend/build.sh index be6c5bc750..d55b9bad66 100755 --- a/src/backend/build.sh +++ b/src/backend/build.sh @@ -12,6 +12,7 @@ ALL=1 GATEWAY=0 BACKEND=0 INIT=0 +INIT_RBAC=0 VERSION=latest PUSH=0 REGISTRY=docker.io/bkrepo @@ -34,6 +35,7 @@ usage () { [ --gateway [可选] 打包gateway镜像 ] [ --backend [可选] 打包backend镜像 ] [ --init [可选] 打包init镜像 ] + [ --init-rbac [可选] 打包init-rbac镜像 ] [ -v, --version [可选] 镜像版本tag, 默认latest ] [ -p, --push [可选] 推送镜像到docker远程仓库,默认不推送 ] [ -r, --registry [可选] docker仓库地址, 默认docker.io ] @@ -78,6 +80,10 @@ while (( $# > 0 )); do ALL=0 INIT=1 ;; + --init-rbac ) + ALL=0 + INIT_RBAC=1 + ;; -v | --version ) shift VERSION=$1 @@ -167,4 +173,16 @@ if [[ $ALL -eq 1 || $INIT -eq 1 ]] ; then docker push $REGISTRY/bkrepo-init:$VERSION fi fi + +# 构建init-rbac镜像 +if [[ $ALL -eq 1 || $INIT_RBAC -eq 1 ]] ; then + log "构建init-rbac镜像..." + rm -rf $tmp_dir/* + mkdir -p $tmp_dir/support-files/bkiam + cp -rf $ROOT_DIR/support-files/bkiam/* $tmp_dir/support-files/bkiam + docker build -f init/init-rbac.Dockerfile -t $REGISTRY/bkrepo-init-rbac:$VERSION $tmp_dir --no-cache --network=host + if [[ $PUSH -eq 1 ]] ; then + docker push $REGISTRY/bkrepo-init-rbac:$VERSION + fi +fi echo "BUILD SUCCESSFUL!" diff --git a/src/backend/buildSrc/src/main/kotlin/Versions.kt b/src/backend/buildSrc/src/main/kotlin/Versions.kt index 4a51ab4f3c..043f10082a 100644 --- a/src/backend/buildSrc/src/main/kotlin/Versions.kt +++ b/src/backend/buildSrc/src/main/kotlin/Versions.kt @@ -65,4 +65,5 @@ object Versions { const val ReactiveFeign = "3.2.6" const val Jasypt = "3.0.5" const val CryptoJavaSdk = "1.1.0" + const val IamJavaSdk = "1.0.30-SNAPSHOT" } diff --git a/src/backend/repository/api-repository/src/main/kotlin/com/tencent/bkrepo/repository/pojo/node/NodeInfo.kt b/src/backend/repository/api-repository/src/main/kotlin/com/tencent/bkrepo/repository/pojo/node/NodeInfo.kt index 640d6e716d..f5b9a91566 100644 --- a/src/backend/repository/api-repository/src/main/kotlin/com/tencent/bkrepo/repository/pojo/node/NodeInfo.kt +++ b/src/backend/repository/api-repository/src/main/kotlin/com/tencent/bkrepo/repository/pojo/node/NodeInfo.kt @@ -41,6 +41,7 @@ import io.swagger.annotations.ApiModelProperty */ @ApiModel("节点信息") data class NodeInfo( + var id: String? = null, @ApiModelProperty("创建者") val createdBy: String, @ApiModelProperty("创建时间") diff --git a/src/backend/repository/api-repository/src/main/kotlin/com/tencent/bkrepo/repository/pojo/project/ProjectInfo.kt b/src/backend/repository/api-repository/src/main/kotlin/com/tencent/bkrepo/repository/pojo/project/ProjectInfo.kt index d17fa1c5b1..9a48d8a22d 100644 --- a/src/backend/repository/api-repository/src/main/kotlin/com/tencent/bkrepo/repository/pojo/project/ProjectInfo.kt +++ b/src/backend/repository/api-repository/src/main/kotlin/com/tencent/bkrepo/repository/pojo/project/ProjectInfo.kt @@ -50,6 +50,8 @@ data class ProjectInfo( val lastModifiedBy: String, @ApiModelProperty("上次修改日期") val lastModifiedDate: String, + @ApiModelProperty("是否已生成蓝鲸v3-rbac默认项目组") + val rbacFlag: Boolean = false, @ApiModelProperty("项目元数据") val metadata: List = emptyList(), ) diff --git a/src/backend/repository/api-repository/src/main/kotlin/com/tencent/bkrepo/repository/pojo/repo/RepositoryInfo.kt b/src/backend/repository/api-repository/src/main/kotlin/com/tencent/bkrepo/repository/pojo/repo/RepositoryInfo.kt index dcc01397bb..b9ab73cab6 100644 --- a/src/backend/repository/api-repository/src/main/kotlin/com/tencent/bkrepo/repository/pojo/repo/RepositoryInfo.kt +++ b/src/backend/repository/api-repository/src/main/kotlin/com/tencent/bkrepo/repository/pojo/repo/RepositoryInfo.kt @@ -42,6 +42,7 @@ import io.swagger.annotations.ApiModelProperty */ @ApiModel("仓库信息") data class RepositoryInfo( + val id: String? = null, @ApiModelProperty("所属项目id") val projectId: String, @ApiModelProperty("仓库名称") diff --git a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/controller/user/UserProjectController.kt b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/controller/user/UserProjectController.kt index ad0dfb2b9c..60d52ab7a4 100644 --- a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/controller/user/UserProjectController.kt +++ b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/controller/user/UserProjectController.kt @@ -114,6 +114,7 @@ class UserProjectController( @PathVariable name: String, @RequestBody projectUpdateRequest: ProjectUpdateRequest ): Response { + permissionManager.checkProjectPermission(PermissionAction.UPDATE, name) return ResponseBuilder.success(projectService.updateProject(name, projectUpdateRequest)) } diff --git a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/listener/ResourcePermissionListener.kt b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/listener/ResourcePermissionListener.kt index 9471fa3aba..f22166dc20 100644 --- a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/listener/ResourcePermissionListener.kt +++ b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/listener/ResourcePermissionListener.kt @@ -31,11 +31,14 @@ package com.tencent.bkrepo.repository.listener +import com.tencent.bkrepo.auth.api.ServiceBkiamV3ResourceClient import com.tencent.bkrepo.auth.api.ServiceRoleClient import com.tencent.bkrepo.auth.api.ServiceUserClient import com.tencent.bkrepo.common.api.constant.ANONYMOUS_USER import com.tencent.bkrepo.common.artifact.event.project.ProjectCreatedEvent import com.tencent.bkrepo.common.artifact.event.repo.RepoCreatedEvent +import com.tencent.bkrepo.common.artifact.event.repo.RepoDeletedEvent +import com.tencent.bkrepo.common.artifact.event.repo.RepoUpdatedEvent import com.tencent.bkrepo.repository.constant.SYSTEM_USER import org.springframework.context.event.EventListener import org.springframework.scheduling.annotation.Async @@ -48,7 +51,8 @@ import org.springframework.stereotype.Component @Component class ResourcePermissionListener( private val roleResource: ServiceRoleClient, - private val userResource: ServiceUserClient + private val userResource: ServiceUserClient, + private val bkiamV3Resource: ServiceBkiamV3ResourceClient ) { /** @@ -62,6 +66,7 @@ class ResourcePermissionListener( if (isAuthedNormalUser(userId) && isNeedLocalPermission(projectId)) { val projectManagerRoleId = roleResource.createProjectManage(projectId).data!! userResource.addUserRole(userId, projectManagerRoleId) + bkiamV3Resource.createProjectManage(userId, projectId) } } } @@ -76,10 +81,32 @@ class ResourcePermissionListener( if (isAuthedNormalUser(userId) && isNeedLocalPermission(projectId)) { val repoManagerRoleId = roleResource.createRepoManage(projectId, repoName).data!! userResource.addUserRole(userId, repoManagerRoleId) + bkiamV3Resource.createRepoManage(userId, projectId, repoName) } } } + @Async + @EventListener(RepoUpdatedEvent::class) + fun handle(event: RepoUpdatedEvent) { + with(event) { + if (isAuthedNormalUser(userId) && isNeedLocalPermission(projectId)) { + bkiamV3Resource.createRepoManage(userId, projectId, repoName) + } + } + } + + /** + * 删除仓库时,需要删除当前在权限中心创建的分级管理员 + */ + @Async + @EventListener(RepoDeletedEvent::class) + fun handle(event: RepoDeletedEvent) { + with(event) { + bkiamV3Resource.deleteRepoManageGroup(userId, projectId, repoName) + } + } + /** * 判断是否为经过认证的普通用户(非匿名用户 & 非系统用户) * diff --git a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/node/impl/NodeBaseService.kt b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/node/impl/NodeBaseService.kt index 98b58c2b75..028cb3f4c8 100644 --- a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/node/impl/NodeBaseService.kt +++ b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/node/impl/NodeBaseService.kt @@ -415,6 +415,7 @@ abstract class NodeBaseService( return tNode?.let { val metadata = MetadataUtils.toMap(it.metadata) NodeInfo( + id = it.id, createdBy = it.createdBy, createdDate = it.createdDate.format(DateTimeFormatter.ISO_DATE_TIME), lastModifiedBy = it.lastModifiedBy, diff --git a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/repo/impl/ProjectServiceImpl.kt b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/repo/impl/ProjectServiceImpl.kt index 4619c88035..3f3396945f 100644 --- a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/repo/impl/ProjectServiceImpl.kt +++ b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/repo/impl/ProjectServiceImpl.kt @@ -27,6 +27,7 @@ package com.tencent.bkrepo.repository.service.repo.impl +import com.tencent.bkrepo.auth.api.ServiceBkiamV3ResourceClient import com.tencent.bkrepo.auth.api.ServicePermissionClient import com.tencent.bkrepo.common.api.constant.DEFAULT_PAGE_NUMBER import com.tencent.bkrepo.common.api.constant.DEFAULT_PAGE_SIZE @@ -79,7 +80,8 @@ import java.util.regex.Pattern class ProjectServiceImpl( private val projectDao: ProjectDao, private val servicePermissionClient: ServicePermissionClient, - private val projectMetricsRepository: ProjectMetricsRepository + private val projectMetricsRepository: ProjectMetricsRepository, + private val serviceBkiamV3ResourceClient: ServiceBkiamV3ResourceClient ) : ProjectService { @Autowired @@ -126,14 +128,20 @@ class ProjectServiceImpl( query.with(Sort.by(Sort.Direction.valueOf(it.first), it.second)) } } - return if (option?.pageNumber == null && option?.pageSize == null) { - projectDao.find(query).map { convert(it)!! } + val projectList = if (option?.pageNumber == null && option?.pageSize == null) { + projectDao.find(query) } else { val pageRequest = Pages.ofRequest( option.pageNumber ?: DEFAULT_PAGE_NUMBER, option.pageSize ?: DEFAULT_PAGE_SIZE ) - projectDao.find(query.with(pageRequest)).map { convert(it)!! } + projectDao.find(query.with(pageRequest)) + } + val projectIdList = projectList.map { it.name } + val existProjectMap = serviceBkiamV3ResourceClient.getExistRbacDefaultGroupProjectIds(projectIdList).data + return projectList.map { + val exist = existProjectMap?.get(it.name) ?: false + convert(it, exist)!! } } @@ -259,6 +267,10 @@ class ProjectServiceImpl( private const val DISPLAY_NAME_LENGTH_MAX = 32 private fun convert(tProject: TProject?): ProjectInfo? { + return convert(tProject, false) + } + + private fun convert(tProject: TProject?, rbacFlag: Boolean): ProjectInfo? { return tProject?.let { ProjectInfo( name = it.name, diff --git a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/repo/impl/RepositoryServiceImpl.kt b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/repo/impl/RepositoryServiceImpl.kt index b396486b17..fb02c5a190 100644 --- a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/repo/impl/RepositoryServiceImpl.kt +++ b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/repo/impl/RepositoryServiceImpl.kt @@ -663,6 +663,7 @@ class RepositoryServiceImpl( return tRepository?.let { handlerConfiguration(it) RepositoryInfo( + id = it.id, name = it.name, type = it.type, category = it.category, diff --git a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/repo/impl/center/CommitEdgeCenterProjectServiceImpl.kt b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/repo/impl/center/CommitEdgeCenterProjectServiceImpl.kt index a756dd0e42..0a72e19ca0 100644 --- a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/repo/impl/center/CommitEdgeCenterProjectServiceImpl.kt +++ b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/repo/impl/center/CommitEdgeCenterProjectServiceImpl.kt @@ -27,6 +27,7 @@ package com.tencent.bkrepo.repository.service.repo.impl.center +import com.tencent.bkrepo.auth.api.ServiceBkiamV3ResourceClient import com.tencent.bkrepo.auth.api.ServicePermissionClient import com.tencent.bkrepo.common.service.cluster.CommitEdgeCenterCondition import com.tencent.bkrepo.repository.dao.ProjectDao @@ -40,9 +41,11 @@ import org.springframework.stereotype.Service class CommitEdgeCenterProjectServiceImpl( projectDao: ProjectDao, servicePermissionClient: ServicePermissionClient, - projectMetricsRepository: ProjectMetricsRepository + projectMetricsRepository: ProjectMetricsRepository, + serviceBkiamV3ResourceClient: ServiceBkiamV3ResourceClient ) : ProjectServiceImpl( projectDao, servicePermissionClient, - projectMetricsRepository + projectMetricsRepository, + serviceBkiamV3ResourceClient ) diff --git a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/repo/impl/edge/EdgeProjectServiceImpl.kt b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/repo/impl/edge/EdgeProjectServiceImpl.kt index 7cfaee6a10..cdec18b79d 100644 --- a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/repo/impl/edge/EdgeProjectServiceImpl.kt +++ b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/repo/impl/edge/EdgeProjectServiceImpl.kt @@ -27,6 +27,7 @@ package com.tencent.bkrepo.repository.service.repo.impl.edge +import com.tencent.bkrepo.auth.api.ServiceBkiamV3ResourceClient import com.tencent.bkrepo.auth.api.ServicePermissionClient import com.tencent.bkrepo.common.artifact.message.ArtifactMessageCode import com.tencent.bkrepo.common.service.cluster.ClusterProperties @@ -47,12 +48,14 @@ import org.springframework.stereotype.Service class EdgeProjectServiceImpl( projectDao: ProjectDao, servicePermissionClient: ServicePermissionClient, + serviceBkiamV3ResourceClient: ServiceBkiamV3ResourceClient, clusterProperties: ClusterProperties, projectMetricsRepository: ProjectMetricsRepository ) : ProjectServiceImpl( projectDao, servicePermissionClient, - projectMetricsRepository + projectMetricsRepository, + serviceBkiamV3ResourceClient ) { private val centerProjectClient: ClusterProjectClient by lazy { diff --git a/src/backend/repository/biz-repository/src/test/kotlin/com/tencent/bkrepo/repository/service/ServiceBaseTest.kt b/src/backend/repository/biz-repository/src/test/kotlin/com/tencent/bkrepo/repository/service/ServiceBaseTest.kt index 8e5ea3481b..6cdb17e5ad 100644 --- a/src/backend/repository/biz-repository/src/test/kotlin/com/tencent/bkrepo/repository/service/ServiceBaseTest.kt +++ b/src/backend/repository/biz-repository/src/test/kotlin/com/tencent/bkrepo/repository/service/ServiceBaseTest.kt @@ -31,6 +31,7 @@ package com.tencent.bkrepo.repository.service +import com.tencent.bkrepo.auth.api.ServiceBkiamV3ResourceClient import com.tencent.bkrepo.auth.api.ServicePermissionClient import com.tencent.bkrepo.auth.api.ServiceRoleClient import com.tencent.bkrepo.auth.api.ServiceUserClient @@ -105,6 +106,9 @@ open class ServiceBaseTest { @MockBean lateinit var servicePermissionClient: ServicePermissionClient + @MockBean + lateinit var serviceBkiamV3ResourceClient: ServiceBkiamV3ResourceClient + @MockBean lateinit var permissionManager: PermissionManager diff --git a/src/frontend/devops-repository/src/components/GlobalUploadViewport/index.vue b/src/frontend/devops-repository/src/components/GlobalUploadViewport/index.vue index 319dec5e74..631f8014ef 100644 --- a/src/frontend/devops-repository/src/components/GlobalUploadViewport/index.vue +++ b/src/frontend/devops-repository/src/components/GlobalUploadViewport/index.vue @@ -72,16 +72,18 @@ :root-data="rootData" @confirm="addFilesToFileList"> + + + diff --git a/src/frontend/devops-repository/src/store/actions/permission.js b/src/frontend/devops-repository/src/store/actions/permission.js index 221b762b66..d07735da1e 100644 --- a/src/frontend/devops-repository/src/store/actions/permission.js +++ b/src/frontend/devops-repository/src/store/actions/permission.js @@ -246,6 +246,22 @@ export default { } ) }, + getPermissionUrl (_, { body }) { + return Vue.prototype.$ajax.post( + `${authPrefix}/user/auth/bkiamv3/permission/url`, + body + ) + }, + refreshIamPermission (_, { projectId }) { + return Vue.prototype.$ajax.post( + `${authPrefix}/user/auth/bkiamv3/project/refresh/${projectId}` + ) + }, + getIamPermissionStatus () { + return Vue.prototype.$ajax.get( + `${authPrefix}/user/auth/bkiamv3/status` + ) + }, // 创建项目用户 createProjectUser (_, { body }) { return Vue.prototype.$ajax.post( diff --git a/src/frontend/devops-repository/src/store/actions/repoGeneric.js b/src/frontend/devops-repository/src/store/actions/repoGeneric.js index 32e7343f94..fdad233326 100644 --- a/src/frontend/devops-repository/src/store/actions/repoGeneric.js +++ b/src/frontend/devops-repository/src/store/actions/repoGeneric.js @@ -214,7 +214,7 @@ export default { if (xhr.status === 200) { resolve(xhr.response) } else { - reject(xhr.response) + reject(xhr) } } } diff --git a/src/frontend/devops-repository/src/store/publicEnum.js b/src/frontend/devops-repository/src/store/publicEnum.js index 31e39ead55..c576bc722e 100644 --- a/src/frontend/devops-repository/src/store/publicEnum.js +++ b/src/frontend/devops-repository/src/store/publicEnum.js @@ -145,3 +145,11 @@ export const FILTER_METHOD_SEVERITY = 1 export const FILTER_METHOD_RISKY_COMPONENT = 2 // 通过风险组件版本过滤 export const FILTER_METHOD_RISKY_COMPONENT_VERSION = 3 + +// 特殊的4个repo仓名称 +export const specialRepoEnum = [ + 'log', + 'pipeline', + 'report', + 'custom' +] diff --git a/src/frontend/devops-repository/src/views/projectManage/index.vue b/src/frontend/devops-repository/src/views/projectManage/index.vue index 2355223bff..21d2b75d98 100644 --- a/src/frontend/devops-repository/src/views/projectManage/index.vue +++ b/src/frontend/devops-repository/src/views/projectManage/index.vue @@ -54,6 +54,11 @@ {{ userList[row.createdBy] ? userList[row.createdBy].name : row.createdBy }} + + + { + this.iamStatus = res + }) }, methods: { - ...mapActions([ - 'queryProjectList' - ]), + ...mapActions(['refreshIamPermission', 'getIamPermissionStatus', 'queryProjectList', 'getProjectList']), formatDate, handlerPaginationChange ({ current = 1, limit = this.pagination.limit } = {}) { this.pagination.current = current @@ -154,6 +161,21 @@ this.filterProjectList = res.filter(project => { return Boolean(~project.id.indexOf(this.projectInput) || ~project.name.indexOf(this.projectInput)) }).slice((this.pagination.current - 1) * this.pagination.limit, this.pagination.current * this.pagination.limit) + }, + createPermission (projectId) { + this.refreshIamPermission({ projectId: projectId }).then(res => { + if (res === true) { + this.$bkMessage({ + theme: 'success', + message: this.$t('permissionsGeneratedSuccessTip') + }) + } else { + this.$bkMessage({ + theme: 'error', + message: this.$t('permissionsGeneratedFailTip') + }) + } + }) } } } diff --git a/src/frontend/devops-repository/src/views/repoCommon/commonFormDialog.vue b/src/frontend/devops-repository/src/views/repoCommon/commonFormDialog.vue index 0160d5f9cb..7d4d9269b9 100644 --- a/src/frontend/devops-repository/src/views/repoCommon/commonFormDialog.vue +++ b/src/frontend/devops-repository/src/views/repoCommon/commonFormDialog.vue @@ -28,12 +28,15 @@ {{$t('cancel')}} {{$t('confirm')}} +