diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/UserOauthInfo.kt b/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/UserOauthInfo.kt deleted file mode 100644 index 4763f8a5b62d..000000000000 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/UserOauthInfo.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.tencent.devops.auth.pojo - -import com.tencent.devops.auth.pojo.enum.OauthType -import io.swagger.v3.oas.annotations.media.Schema - -@Schema(title = "用户Oauth授权信息") -data class UserOauthInfo( - @get:Schema(title = "授权账号") - val username: String, - @get:Schema(title = "授权代码库数量") - val repoCount: Long, - @get:Schema(title = "创建时间") - val createTime: Long?, - @get:Schema(title = "授权类型") - val type: OauthType, - @get:Schema(title = "授权类型") - val expired: Boolean -) diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/UserOauthResourceImpl.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/UserOauthResourceImpl.kt deleted file mode 100644 index bb718a68b273..000000000000 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/resources/UserOauthResourceImpl.kt +++ /dev/null @@ -1,71 +0,0 @@ -package com.tencent.devops.auth.resources - -import com.tencent.devops.auth.api.user.UserOauthResource -import com.tencent.devops.auth.pojo.OauthRelResource -import com.tencent.devops.auth.pojo.OauthResetUrl -import com.tencent.devops.auth.pojo.UserOauthInfo -import com.tencent.devops.auth.pojo.enum.OauthType -import com.tencent.devops.auth.service.UserOauthService -import com.tencent.devops.common.api.pojo.Page -import com.tencent.devops.common.api.pojo.Result -import com.tencent.devops.common.web.RestResource -import org.springframework.beans.factory.annotation.Autowired - -@RestResource -class UserOauthResourceImpl @Autowired constructor( - val userOauthService: UserOauthService -) : UserOauthResource { - override fun list(userId: String, projectId: String?): Result> { - return Result( - userOauthService.list( - userId = userId, - projectId = projectId - ) - ) - } - - override fun relSource( - userId: String, - projectId: String?, - oauthType: OauthType, - page: Int?, - pageSize: Int? - ): Result> { - return Result( - userOauthService.relSource( - userId = userId, - projectId = projectId, - oauthType = oauthType, - page = page ?: 1, - pageSize = pageSize ?: 20 - ) - ) - } - - override fun delete( - userId: String, - projectId: String?, - oauthType: OauthType - ): Result { - userOauthService.delete( - userId = userId, - projectId = projectId, - oauthType = oauthType - ) - return Result(true) - } - - override fun reOauth( - userId: String, - oauthType: OauthType, - redirectUrl: String - ): Result { - return Result( - userOauthService.reOauth( - userId = userId, - oauthType = oauthType, - redirectUrl = redirectUrl - ) - ) - } -} diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/UserOauthService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/UserOauthService.kt deleted file mode 100644 index 87d8d7bb3c0a..000000000000 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/UserOauthService.kt +++ /dev/null @@ -1,76 +0,0 @@ -package com.tencent.devops.auth.service - -import com.tencent.devops.auth.pojo.OauthRelResource -import com.tencent.devops.auth.pojo.OauthResetUrl -import com.tencent.devops.auth.pojo.UserOauthInfo -import com.tencent.devops.auth.pojo.enum.OauthType -import com.tencent.devops.auth.service.self.OauthService -import com.tencent.devops.auth.service.self.RepoGitOauthService -import com.tencent.devops.auth.service.self.RepoGithubOauthService -import com.tencent.devops.common.api.pojo.Page -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.stereotype.Service - -@Service -class UserOauthService @Autowired constructor( - val repoGithubOauthService: RepoGithubOauthService, - val repoGitOauthService: RepoGitOauthService -) { - fun list(userId: String, projectId: String?): List { - val list = mutableListOf() - listOf( - repoGitOauthService, - repoGithubOauthService - ).forEach { - val userOauthInfo = it.get(userId, projectId) - if (userOauthInfo != null) { - list.add(userOauthInfo) - } - } - return list - } - - fun relSource( - userId: String, - projectId: String?, - oauthType: OauthType, - page: Int, - pageSize: Int - ): Page { - return getService(oauthType).relSource( - userId = userId, - projectId = projectId, - page = page, - pageSize = pageSize - ) - } - - fun delete( - projectId: String?, - userId: String, - oauthType: OauthType - ) { - getService(oauthType).delete( - projectId = projectId, - userId = userId - ) - } - - fun reOauth( - userId: String, - oauthType: OauthType, - redirectUrl: String - ): OauthResetUrl { - return getService(oauthType).reOauth( - userId = userId, - redirectUrl = redirectUrl - ) - } - - private fun getService(oauthType: OauthType): OauthService { - return when (oauthType) { - OauthType.GIT -> repoGitOauthService - OauthType.GITHUB -> repoGithubOauthService - } - } -} diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/self/AbstractRepoOauthService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/self/AbstractRepoOauthService.kt deleted file mode 100644 index 9c78d9130c9d..000000000000 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/self/AbstractRepoOauthService.kt +++ /dev/null @@ -1,80 +0,0 @@ -package com.tencent.devops.auth.service.self - -import com.tencent.devops.auth.constant.AuthMessageCode -import com.tencent.devops.auth.pojo.OauthRelResource -import com.tencent.devops.auth.pojo.OauthResetUrl -import com.tencent.devops.auth.pojo.enum.OauthType -import com.tencent.devops.common.api.enums.ScmType -import com.tencent.devops.common.api.exception.ErrorCodeException -import com.tencent.devops.common.api.pojo.Page -import com.tencent.devops.common.client.Client -import com.tencent.devops.repository.api.ServiceOauthResource -import com.tencent.devops.repository.api.ServiceRepositoryResource - -/** - * 代码库OAUTH授权抽象类 - */ -abstract class AbstractRepoOauthService( - open val client: Client, - open val oauthType: OauthType -) : OauthService { - override fun relSource(userId: String, projectId: String?, page: Int, pageSize: Int): Page { - return client.get(ServiceRepositoryResource::class).listOauthRepo( - projectId = projectId, - userId = userId, - scmType = convertOauthType(), - page = page, - pageSize = pageSize - ).data?.let { pageInfo -> - Page( - records = pageInfo.records.map { - OauthRelResource( - name = it.aliasName, - url = it.detailUrl ?: "" - ) - }, - count = pageInfo.count, - page = pageInfo.page, - pageSize = pageSize - ) - } ?: Page(page = page, pageSize = pageSize, records = listOf(), count = 0) - } - - override fun delete(userId: String, projectId: String?) { - // 检查是否还有关联代码库 - if (countOauthRepo(projectId = projectId, userId = userId) > 0) { - throw ErrorCodeException( - errorCode = AuthMessageCode.OAUTH_INFO_OCCUPIED_CANNOT_DELETE - ) - } - // 调用接口删除oauth信息 - client.get(ServiceOauthResource::class).deleteOauth( - userId = userId, - scmType = convertOauthType() - ) - } - - override fun reOauth(userId: String, redirectUrl: String): OauthResetUrl { - val reOauthUrl = client.get(ServiceOauthResource::class).reOauthUrl( - userId = userId, - scmType = convertOauthType(), - redirectUrl = redirectUrl - ).data ?: "" - return OauthResetUrl(reOauthUrl) - } - - private fun convertOauthType(): ScmType { - return when (oauthType) { - OauthType.GIT -> ScmType.CODE_GIT - OauthType.GITHUB -> ScmType.GITHUB - } - } - - fun countOauthRepo(projectId: String?, userId: String): Long { - return client.get(ServiceRepositoryResource::class).countOauthRepo( - projectId = projectId, - userId = userId, - scmType = convertOauthType() - ).data ?: 0 - } -} diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/self/OauthService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/self/OauthService.kt deleted file mode 100644 index dee6e9335f97..000000000000 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/self/OauthService.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.tencent.devops.auth.service.self - -import com.tencent.devops.auth.pojo.OauthRelResource -import com.tencent.devops.auth.pojo.OauthResetUrl -import com.tencent.devops.auth.pojo.UserOauthInfo -import com.tencent.devops.common.api.pojo.Page - -/** - * 用户OAUTH资源接口 - */ -interface OauthService { - /** - * 获取授权信息 - */ - fun get(userId: String, projectId: String?): UserOauthInfo? - - /** - * 授权信息关联的资源列表 - */ - fun relSource(userId: String, projectId: String?, page: Int, pageSize: Int): Page - - /** - * 删除授权 - */ - fun delete(userId: String, projectId: String?) - - /** - * 重置授权 - */ - fun reOauth(userId: String, redirectUrl: String): OauthResetUrl -} diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/self/RepoGitOauthService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/self/RepoGitOauthService.kt deleted file mode 100644 index 2b50bd3bb138..000000000000 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/self/RepoGitOauthService.kt +++ /dev/null @@ -1,50 +0,0 @@ -package com.tencent.devops.auth.service.self - -import com.tencent.devops.auth.pojo.UserOauthInfo -import com.tencent.devops.auth.pojo.enum.OauthType -import com.tencent.devops.common.client.Client -import com.tencent.devops.repository.api.ServiceOauthResource -import com.tencent.devops.repository.api.scm.ServiceGitResource -import com.tencent.devops.repository.pojo.enums.TokenTypeEnum -import org.slf4j.LoggerFactory -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.stereotype.Service - -/** - * 代码库OAUTH授权 - */ -@Service -class RepoGitOauthService @Autowired constructor( - override val client: Client -) : AbstractRepoOauthService( - oauthType = OauthType.GIT, - client = client -) { - override fun get(userId: String, projectId: String?): UserOauthInfo? { - val gitToken = client.get(ServiceOauthResource::class).gitGet(userId).data ?: return null - // 授权过期 - var expired = false - // 存量数据中可能存在A用户授权到B用户的情况 - val oauthUserName = try { - client.get(ServiceGitResource::class).getUserInfoByToken( - token = gitToken.accessToken, - tokenType = TokenTypeEnum.OAUTH - ).data - } catch (ignored: Exception) { - logger.warn("get user info failed", ignored) - expired = true - null - }?.username ?: "" - return UserOauthInfo( - username = oauthUserName, - repoCount = countOauthRepo(projectId = projectId, userId = userId), - createTime = gitToken.createTime, - type = oauthType, - expired = expired - ) - } - - companion object { - private val logger = LoggerFactory.getLogger(RepoGitOauthService::class.java) - } -} \ No newline at end of file diff --git a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/self/RepoGithubOauthService.kt b/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/self/RepoGithubOauthService.kt deleted file mode 100644 index fe4dd6834eb1..000000000000 --- a/src/backend/ci/core/auth/biz-auth/src/main/kotlin/com/tencent/devops/auth/service/self/RepoGithubOauthService.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.tencent.devops.auth.service.self - -import com.tencent.devops.auth.pojo.UserOauthInfo -import com.tencent.devops.auth.pojo.enum.OauthType -import com.tencent.devops.common.client.Client -import com.tencent.devops.repository.api.ServiceGithubResource -import com.tencent.devops.repository.api.github.ServiceGithubUserResource -import org.slf4j.LoggerFactory -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.stereotype.Service - -/** - * 代码库OAUTH授权 - */ -@Service -class RepoGithubOauthService @Autowired constructor( - override val client: Client -) : AbstractRepoOauthService( - oauthType = OauthType.GITHUB, - client = client -) { - override fun get(userId: String, projectId: String?): UserOauthInfo? { - val gitToken = client.get(ServiceGithubResource::class).getAccessToken( - userId = userId - ).data ?: return null - var expired = false - // github用户名和userId不一致 - val oauthUserName = try { - client.get(ServiceGithubUserResource::class).getUser( - token = gitToken.accessToken - ).data - } catch (ignored: Exception) { - logger.warn("get user info failed", ignored) - expired = true - null - }?.login ?: "" - return UserOauthInfo( - username = oauthUserName, - repoCount = countOauthRepo(projectId = projectId, userId = userId), - createTime = gitToken.createTime, - type = oauthType, - expired = expired - ) - } - - companion object { - val logger = LoggerFactory.getLogger(RepoGithubOauthService::class.java) - } -} \ No newline at end of file diff --git a/src/backend/ci/core/common/common-api/src/main/kotlin/com/tencent/devops/common/api/enums/ScmCode.kt b/src/backend/ci/core/common/common-api/src/main/kotlin/com/tencent/devops/common/api/enums/ScmCode.kt new file mode 100644 index 000000000000..c02296597472 --- /dev/null +++ b/src/backend/ci/core/common/common-api/src/main/kotlin/com/tencent/devops/common/api/enums/ScmCode.kt @@ -0,0 +1,43 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. + * + * A copy of the MIT License is included in this file. + * + * + * Terms of the MIT License: + * --------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.tencent.devops.common.api.enums + +/** + * 代码库类型 + */ +enum class ScmCode { + TGIT, // 内部工蜂 + GITHUB; // github + + fun convertScmType(): ScmType { + return when (this) { + TGIT -> ScmType.CODE_GIT + GITHUB -> ScmType.GITHUB + } + } +} diff --git a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/api/ServiceRepositoryResource.kt b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/api/ServiceRepositoryResource.kt index bc84adfe1517..36d4d0f53fa4 100644 --- a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/api/ServiceRepositoryResource.kt +++ b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/api/ServiceRepositoryResource.kt @@ -279,9 +279,6 @@ interface ServiceRepositoryResource { @Parameter(description = "用户ID", required = true) @HeaderParam(AUTH_HEADER_USER_ID) userId: String, - @Parameter(description = "项目ID", required = false) - @QueryParam("projectId") - projectId: String?, @Parameter(description = "代码库类型") @QueryParam("scmType") scmType: ScmType, @@ -292,19 +289,4 @@ interface ServiceRepositoryResource { @QueryParam("pageSize") pageSize: Int? = null ): Result> - - @Operation(summary = "获取指定用户授权的代码库") - @POST - @Path("/countOauthRepo") - fun countOauthRepo( - @Parameter(description = "用户ID", required = true) - @HeaderParam(AUTH_HEADER_USER_ID) - userId: String, - @Parameter(description = "项目ID", required = false) - @QueryParam("projectId") - projectId: String?, - @Parameter(description = "代码库类型") - @QueryParam("scmType") - scmType: ScmType - ): Result } diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserOauthResource.kt b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/api/UserOauthResource.kt similarity index 79% rename from src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserOauthResource.kt rename to src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/api/UserOauthResource.kt index 7d4e806fa883..ec073474baf4 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/api/user/UserOauthResource.kt +++ b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/api/UserOauthResource.kt @@ -26,15 +26,15 @@ * */ -package com.tencent.devops.auth.api.user +package com.tencent.devops.repository.api -import com.tencent.devops.auth.pojo.OauthRelResource -import com.tencent.devops.auth.pojo.OauthResetUrl -import com.tencent.devops.auth.pojo.UserOauthInfo -import com.tencent.devops.auth.pojo.enum.OauthType import com.tencent.devops.common.api.auth.AUTH_HEADER_USER_ID +import com.tencent.devops.common.api.enums.ScmCode import com.tencent.devops.common.api.pojo.Page import com.tencent.devops.common.api.pojo.Result +import com.tencent.devops.repository.pojo.OauthRepositoryResource +import com.tencent.devops.repository.pojo.OauthResetUrl +import com.tencent.devops.repository.pojo.UserOauthRepositoryInfo import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter import io.swagger.v3.oas.annotations.tags.Tag @@ -49,7 +49,7 @@ import javax.ws.rs.QueryParam import javax.ws.rs.core.MediaType @Tag(name = "AUTH_RESOURCE", description = "用户态-iam资源映射") -@Path("/user/oauth/resource/") +@Path("/user/repositories/oauth/") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) interface UserOauthResource { @@ -59,11 +59,8 @@ interface UserOauthResource { fun list( @Parameter(description = "用户名", required = true) @HeaderParam(AUTH_HEADER_USER_ID) - userId: String, - @Parameter(description = "项目ID", required = false) - @QueryParam(value = "projectId") - projectId: String? - ): Result> + userId: String + ): Result> @GET @Path("/relSource") @@ -72,19 +69,16 @@ interface UserOauthResource { @Parameter(description = "用户名", required = true) @HeaderParam(AUTH_HEADER_USER_ID) userId: String, - @Parameter(description = "项目ID", required = false) - @QueryParam("projectId") - projectId: String?, @Parameter(description = "授权类型", required = true) - @QueryParam("oauthType") - oauthType: OauthType, + @QueryParam("scmCode") + scmCode: ScmCode, @Parameter(description = "第几页", required = false, example = "1") @QueryParam("page") page: Int? = null, @Parameter(description = "每页多少条", required = false, example = "20") @QueryParam("pageSize") pageSize: Int? = null - ): Result> + ): Result> @DELETE @Path("/delete") @@ -93,24 +87,21 @@ interface UserOauthResource { @Parameter(description = "用户名", required = true) @HeaderParam(AUTH_HEADER_USER_ID) userId: String, - @Parameter(description = "项目ID", required = false) - @QueryParam("projectId") - projectId: String?, @Parameter(description = "授权类型", required = true) - @QueryParam("oauthType") - oauthType: OauthType + @QueryParam("scmCode") + scmCode: ScmCode ): Result @POST - @Path("/reOauth") + @Path("/reset") @Operation(summary = "重置授权") - fun reOauth( + fun reset( @Parameter(description = "用户名", required = true) @HeaderParam(AUTH_HEADER_USER_ID) userId: String, @Parameter(description = "授权类型", required = true) - @QueryParam("oauthType") - oauthType: OauthType, + @QueryParam("scmCode") + scmCode: ScmCode, @Parameter(description = "回调链接(授权完以后的链接地址)", required = true) @QueryParam("redirectUrl") redirectUrl: String diff --git a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/CodeGitRepository.kt b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/CodeGitRepository.kt index 5490ee419cbf..4eeafb6eff6b 100644 --- a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/CodeGitRepository.kt +++ b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/CodeGitRepository.kt @@ -61,6 +61,8 @@ data class CodeGitRepository( ) : Repository { companion object { const val classType = "codeGit" + // 内部工蜂 + const val SCM_CODE = "TGIT" } override fun getStartPrefix(): String { diff --git a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/GithubRepository.kt b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/GithubRepository.kt index b2d86a038da8..e8cf984b1c48 100644 --- a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/GithubRepository.kt +++ b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/GithubRepository.kt @@ -56,6 +56,7 @@ data class GithubRepository( ) : Repository { companion object { const val classType = "github" + const val SCM_CODE = "GITHUB" } override fun getStartPrefix() = "https://github.com/" diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/OauthRelResource.kt b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/OauthRepositoryResource.kt similarity index 55% rename from src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/OauthRelResource.kt rename to src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/OauthRepositoryResource.kt index f83be79b7102..e3e6ce7656a1 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/OauthRelResource.kt +++ b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/OauthRepositoryResource.kt @@ -1,9 +1,9 @@ -package com.tencent.devops.auth.pojo +package com.tencent.devops.repository.pojo import io.swagger.v3.oas.annotations.media.Schema -@Schema(title = "用户Oauth关联的资源") -data class OauthRelResource( +@Schema(title = "Oauth授权类型的代码库资源信息") +data class OauthRepositoryResource( @get:Schema(title = "资源名称") val name: String, @get:Schema(title = "资源链接") diff --git a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/OauthResetUrl.kt b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/OauthResetUrl.kt similarity index 76% rename from src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/OauthResetUrl.kt rename to src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/OauthResetUrl.kt index b829733e1f1f..b2f39bb691ed 100644 --- a/src/backend/ci/core/auth/api-auth/src/main/kotlin/com/tencent/devops/auth/pojo/OauthResetUrl.kt +++ b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/OauthResetUrl.kt @@ -1,4 +1,4 @@ -package com.tencent.devops.auth.pojo +package com.tencent.devops.repository.pojo import io.swagger.v3.oas.annotations.media.Schema diff --git a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/UserOauthRepositoryInfo.kt b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/UserOauthRepositoryInfo.kt new file mode 100644 index 000000000000..90ef4566d804 --- /dev/null +++ b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/UserOauthRepositoryInfo.kt @@ -0,0 +1,20 @@ +package com.tencent.devops.repository.pojo + +import com.tencent.devops.common.api.enums.ScmCode +import io.swagger.v3.oas.annotations.media.Schema + +@Schema(title = "用户代码库Oauth授权信息") +data class UserOauthRepositoryInfo( + @get:Schema(title = "授权账号") + val username: String, + @get:Schema(title = "授权代码库数量") + val repoCount: Long, + @get:Schema(title = "创建时间") + val createTime: Long? = null, + @get:Schema(title = "授权类型") + val type: ScmCode, + @get:Schema(title = "是否过期") + val expired: Boolean = false, + @get:Schema(title = "是否已授权") + val authorized: Boolean = true +) diff --git a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/oauth/Oauth2AccessToken.java b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/oauth/Oauth2AccessToken.java new file mode 100644 index 000000000000..f3d7e07bdb47 --- /dev/null +++ b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/oauth/Oauth2AccessToken.java @@ -0,0 +1,17 @@ +package com.tencent.devops.repository.pojo.oauth; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class Oauth2AccessToken { + private String accessToken; + private String tokenType; + private Long expiresIn; + private String refreshToken; +} \ No newline at end of file diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/dao/RepositoryCodeGitDao.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/dao/RepositoryCodeGitDao.kt index 58cae5fe1be7..ccc4d526f665 100644 --- a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/dao/RepositoryCodeGitDao.kt +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/dao/RepositoryCodeGitDao.kt @@ -27,8 +27,11 @@ package com.tencent.devops.repository.dao +import com.tencent.devops.common.api.enums.ScmType +import com.tencent.devops.model.repository.tables.TRepository import com.tencent.devops.model.repository.tables.TRepositoryCodeGit import com.tencent.devops.model.repository.tables.records.TRepositoryCodeGitRecord +import com.tencent.devops.repository.pojo.RepoOauthRefVo import com.tencent.devops.repository.pojo.UpdateRepositoryInfoRequest import com.tencent.devops.repository.pojo.enums.RepoAuthType import org.jooq.DSLContext @@ -188,4 +191,58 @@ class RepositoryCodeGitDao { .fetch() } } + + fun countOauthRepo( + dslContext: DSLContext, + userId: String + ): Long { + val t1 = TRepository.T_REPOSITORY + val t2 = TRepositoryCodeGit.T_REPOSITORY_CODE_GIT + return dslContext.selectCount() + .from(t1) + .leftJoin(t2) + .on(t1.REPOSITORY_ID.eq(t2.REPOSITORY_ID)) + .where( + listOf( + t1.IS_DELETED.eq(false), + t1.TYPE.eq(ScmType.CODE_GIT.name), + t2.AUTH_TYPE.eq(RepoAuthType.OAUTH.name), + t2.USER_NAME.eq(userId) + ) + ) + .fetchOne(0, Long::class.java)!! + } + + fun listOauthRepo( + dslContext: DSLContext, + userId: String, + limit: Int, + offset: Int, + ): List { + val t1 = TRepository.T_REPOSITORY + val t2 = TRepositoryCodeGit.T_REPOSITORY_CODE_GIT + return dslContext.select(t1.ALIAS_NAME, t1.URL, t1.PROJECT_ID, t1.REPOSITORY_HASH_ID) + .from(t1) + .leftJoin(t2) + .on(t1.REPOSITORY_ID.eq(t2.REPOSITORY_ID)) + .where( + listOf( + t1.IS_DELETED.eq(false), + t1.TYPE.eq(ScmType.CODE_GIT.name), + t2.AUTH_TYPE.eq(RepoAuthType.OAUTH.name), + t2.USER_NAME.eq(userId) + ) + ) + .limit(limit) + .offset(offset) + .fetch() + .map { + RepoOauthRefVo( + aliasName = it.get(0).toString(), + url = it.get(1).toString(), + projectId = it.get(2).toString(), + hashId = it.get(3).toString() + ) + } + } } diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/dao/RepositoryDao.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/dao/RepositoryDao.kt index 5ddea6c4ffb4..8cca0ff5383e 100644 --- a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/dao/RepositoryDao.kt +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/dao/RepositoryDao.kt @@ -34,10 +34,8 @@ import com.tencent.devops.common.db.utils.skipCheck import com.tencent.devops.common.web.utils.I18nUtil import com.tencent.devops.model.repository.tables.TRepository import com.tencent.devops.model.repository.tables.TRepositoryCodeGit -import com.tencent.devops.model.repository.tables.TRepositoryGithub import com.tencent.devops.model.repository.tables.records.TRepositoryRecord import com.tencent.devops.repository.constant.RepositoryMessageCode.GIT_NOT_FOUND -import com.tencent.devops.repository.pojo.RepoOauthRefVo import com.tencent.devops.repository.pojo.RepositoryInfo import com.tencent.devops.repository.pojo.enums.RepoAuthType import com.tencent.devops.repository.pojo.enums.RepositorySortEnum @@ -49,7 +47,6 @@ import org.jooq.Record1 import org.jooq.Result import org.jooq.SelectForStep import org.jooq.impl.DSL -import org.jooq.impl.TableImpl import org.springframework.stereotype.Repository import java.time.LocalDateTime import javax.ws.rs.NotFoundException @@ -652,82 +649,4 @@ class RepositoryDao { .execute() } } - - fun listOauthRepo( - dslContext: DSLContext, - projectId: String?, - userId: String, - limit: Int, - offset: Int, - scmType: ScmType - ): List { - val t1 = TRepository.T_REPOSITORY - val (t2, conditions, joinConditions) = oauthRepoConditions(t1, projectId, userId, scmType) ?: return listOf() - return dslContext.select(t1.ALIAS_NAME, t1.URL, t1.PROJECT_ID, t1.REPOSITORY_HASH_ID) - .from(t1) - .leftJoin(t2) - .on(joinConditions) - .where(conditions) - .limit(limit).offset(offset) - .fetch() - .map { - RepoOauthRefVo( - aliasName = it.get(0).toString(), - url = it.get(1).toString(), - projectId = it.get(2).toString(), - hashId = it.get(3).toString() - ) - } - } - - fun countOauthRepo( - dslContext: DSLContext, - projectId: String?, - userId: String, - scmType: ScmType - ): Long { - val t1 = TRepository.T_REPOSITORY - val (t2, conditions, joinConditions) = oauthRepoConditions(t1, projectId, userId, scmType) ?: return 0 - return dslContext.selectCount() - .from(t1) - .leftJoin(t2) - .on(joinConditions) - .where(conditions) - .fetchOne(0, Long::class.java)!! - } - - fun oauthRepoConditions( - t1: TRepository, - projectId: String?, - userId: String, - scmType: ScmType - ): Triple, List, Condition>? { - val conditions = mutableListOf( - t1.IS_DELETED.eq(false), - t1.TYPE.eq(scmType.name) - ) - if (!projectId.isNullOrBlank()) { - conditions.add(t1.PROJECT_ID.eq(projectId)) - } - val joinConditions: Condition - val t2 = when (scmType) { - ScmType.CODE_GIT -> { - val table = TRepositoryCodeGit.T_REPOSITORY_CODE_GIT - joinConditions = t1.REPOSITORY_ID.eq(table.REPOSITORY_ID) - conditions.add(table.AUTH_TYPE.eq(RepoAuthType.OAUTH.name)) - conditions.add(table.USER_NAME.eq(userId)) - table - } - - ScmType.GITHUB -> { - val table = TRepositoryGithub.T_REPOSITORY_GITHUB - joinConditions = t1.REPOSITORY_ID.eq(table.REPOSITORY_ID) - conditions.add(table.USER_NAME.eq(userId)) - table - } - - else -> return null - } - return Triple(t2, conditions, joinConditions) - } } diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/dao/RepositoryGithubDao.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/dao/RepositoryGithubDao.kt index 015e79bb4be4..4a4290edaa12 100644 --- a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/dao/RepositoryGithubDao.kt +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/dao/RepositoryGithubDao.kt @@ -27,9 +27,12 @@ package com.tencent.devops.repository.dao +import com.tencent.devops.common.api.enums.ScmType +import com.tencent.devops.model.repository.tables.TRepository import com.tencent.devops.model.repository.tables.TRepositoryCodeGitlab import com.tencent.devops.model.repository.tables.TRepositoryGithub import com.tencent.devops.model.repository.tables.records.TRepositoryGithubRecord +import com.tencent.devops.repository.pojo.RepoOauthRefVo import com.tencent.devops.repository.pojo.UpdateRepositoryInfoRequest import org.jooq.DSLContext import org.jooq.Result @@ -162,4 +165,56 @@ class RepositoryGithubDao { .execute() } } + + fun countOauthRepo( + dslContext: DSLContext, + userId: String + ): Long { + val t1 = TRepository.T_REPOSITORY + val t2 = TRepositoryGithub.T_REPOSITORY_GITHUB + return dslContext.selectCount() + .from(t1) + .leftJoin(t2) + .on(t1.REPOSITORY_ID.eq(t2.REPOSITORY_ID)) + .where( + listOf( + t1.IS_DELETED.eq(false), + t1.TYPE.eq(ScmType.GITHUB.name), + t2.USER_NAME.eq(userId) + ) + ) + .fetchOne(0, Long::class.java)!! + } + + fun listOauthRepo( + dslContext: DSLContext, + userId: String, + limit: Int, + offset: Int, + ): List { + val t1 = TRepository.T_REPOSITORY + val t2 = TRepositoryGithub.T_REPOSITORY_GITHUB + return dslContext.select(t1.ALIAS_NAME, t1.URL, t1.PROJECT_ID, t1.REPOSITORY_HASH_ID) + .from(t1) + .leftJoin(t2) + .on(t1.REPOSITORY_ID.eq(t2.REPOSITORY_ID)) + .where( + listOf( + t1.IS_DELETED.eq(false), + t1.TYPE.eq(ScmType.GITHUB.name), + t2.USER_NAME.eq(userId) + ) + ) + .limit(limit) + .offset(offset) + .fetch() + .map { + RepoOauthRefVo( + aliasName = it.get(0).toString(), + url = it.get(1).toString(), + projectId = it.get(2).toString(), + hashId = it.get(3).toString() + ) + } + } } diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/resources/ServiceRepositoryResourceImpl.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/resources/ServiceRepositoryResourceImpl.kt index 15b213d1471c..c157395b9afb 100644 --- a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/resources/ServiceRepositoryResourceImpl.kt +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/resources/ServiceRepositoryResourceImpl.kt @@ -250,7 +250,6 @@ class ServiceRepositoryResourceImpl @Autowired constructor( override fun listOauthRepo( userId: String, - projectId: String?, scmType: ScmType, page: Int?, pageSize: Int? @@ -260,21 +259,10 @@ class ServiceRepositoryResourceImpl @Autowired constructor( val limit = PageUtil.convertPageSizeToSQLLimit(pageNotNull, pageSizeNotNull) val result = repositoryService.listOauthRepo( userId = userId, - projectId = projectId, scmType = scmType, limit = limit.limit, offset = limit.offset ) return Result(Page(pageNotNull, pageSizeNotNull, result.count, result.records)) } - - override fun countOauthRepo(userId: String, projectId: String?, scmType: ScmType): Result { - return Result( - repositoryService.countOauthRepo( - userId = userId, - projectId = projectId, - scmType = scmType - ) - ) - } } diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/resources/UserOauthResourceImpl.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/resources/UserOauthResourceImpl.kt new file mode 100644 index 000000000000..46052332084d --- /dev/null +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/resources/UserOauthResourceImpl.kt @@ -0,0 +1,75 @@ +package com.tencent.devops.repository.resources + +import com.tencent.devops.repository.api.UserOauthResource +import com.tencent.devops.repository.pojo.OauthRepositoryResource +import com.tencent.devops.repository.pojo.OauthResetUrl +import com.tencent.devops.repository.pojo.UserOauthRepositoryInfo +import com.tencent.devops.common.api.enums.ScmCode +import com.tencent.devops.common.api.pojo.Page +import com.tencent.devops.common.api.pojo.Result +import com.tencent.devops.common.web.RestResource +import com.tencent.devops.repository.service.OauthRepositoryService +import org.springframework.beans.factory.annotation.Autowired + +@RestResource +class UserOauthResourceImpl @Autowired constructor( + val oauthRepositoryService: OauthRepositoryService +) : UserOauthResource { + override fun list(userId: String): Result> { + return Result(oauthRepositoryService.list(userId)) + } + + override fun relSource( + userId: String, + scmCode: ScmCode, + page: Int?, + pageSize: Int? + ): Result> { + val targetPage = page ?: 1 + val targetPageSize = pageSize ?: 20 + val resources = oauthRepositoryService.relSource( + userId = userId, + scmCode = scmCode, + page = targetPage, + pageSize = targetPageSize + ).let { pageInfo -> + Page( + records = pageInfo.records.map { + OauthRepositoryResource( + name = it.aliasName, + url = it.detailUrl ?: "" + ) + }, + count = pageInfo.count, + page = pageInfo.page, + pageSize = targetPageSize + ) + } + return Result(resources) + } + + override fun delete( + userId: String, + scmCode: ScmCode + ): Result { + oauthRepositoryService.delete( + userId = userId, + scmCode = scmCode + ) + return Result(true) + } + + override fun reset( + userId: String, + scmCode: ScmCode, + redirectUrl: String + ): Result { + return Result( + oauthRepositoryService.reset( + userId = userId, + scmCode = scmCode, + redirectUrl = redirectUrl + ) + ) + } +} diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/OauthRepositoryService.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/OauthRepositoryService.kt new file mode 100644 index 000000000000..9bd21f7741da --- /dev/null +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/OauthRepositoryService.kt @@ -0,0 +1,157 @@ +package com.tencent.devops.repository.service + +import com.tencent.devops.auth.constant.AuthMessageCode +import com.tencent.devops.repository.pojo.OauthResetUrl +import com.tencent.devops.repository.pojo.UserOauthRepositoryInfo +import com.tencent.devops.common.api.enums.ScmCode +import com.tencent.devops.common.api.exception.ErrorCodeException +import com.tencent.devops.common.api.pojo.Page +import com.tencent.devops.common.api.util.PageUtil +import com.tencent.devops.repository.pojo.RepoOauthRefVo +import com.tencent.devops.repository.pojo.enums.RedirectUrlTypeEnum +import com.tencent.devops.repository.pojo.enums.TokenTypeEnum +import com.tencent.devops.repository.service.github.GithubOAuthService +import com.tencent.devops.repository.service.oauth2.Oauth2TokenStoreManager +import com.tencent.devops.repository.service.scm.IGitOauthService +import com.tencent.devops.repository.service.scm.IGitService +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service + +/** + * OAUTH授权代码库服务类 + */ +@Service +class OauthRepositoryService @Autowired constructor( + val oauth2TokenStoreManager: Oauth2TokenStoreManager, + val gitService: IGitService, + val gitOauthService: IGitOauthService, + val githubOAuthService: GithubOAuthService, + val repositoryService: RepositoryService +) { + fun list(userId: String): List { + val list = mutableListOf() + listOf( + ScmCode.TGIT, + ScmCode.GITHUB + ).forEach { scmCode -> + val userOauthInfo = oauth2TokenStoreManager.get( + userId = userId, + scmCode = scmCode.name + )?.let { + val (expired, username) = getRealUsername(scmCode, userId) + UserOauthRepositoryInfo( + username = username ?: "", + repoCount = repositoryService.countOauthRepo( + userId = userId, + scmType = scmCode.convertScmType() + ), + type = scmCode, + expired = expired, + authorized = true + ) + } ?: UserOauthRepositoryInfo( + username = userId, + repoCount = 0L, + type = scmCode, + expired = true, + authorized = false + ) + list.add(userOauthInfo) + } + return list + } + + fun relSource( + userId: String, + scmCode: ScmCode, + page: Int, + pageSize: Int + ): Page { + val limit = PageUtil.convertPageSizeToSQLLimit(page, pageSize) + val result = repositoryService.listOauthRepo( + userId = userId, + scmType = scmCode.convertScmType(), + limit = limit.limit, + offset = limit.offset + ) + return Page(page, pageSize, result.count, result.records) + } + + fun delete( + userId: String, + scmCode: ScmCode + ) { + // 检查是否还有关联代码库 + if (countOauthRepo(userId, scmCode) > 0) { + throw ErrorCodeException( + errorCode = AuthMessageCode.OAUTH_INFO_OCCUPIED_CANNOT_DELETE + ) + } + oauth2TokenStoreManager.delete(userId = userId, scmCode = scmCode.name) + } + + fun countOauthRepo(userId: String, scmCode: ScmCode) = repositoryService.countOauthRepo( + userId = userId, + scmType = scmCode.convertScmType() + ) + + fun reset( + userId: String, + scmCode: ScmCode, + redirectUrl: String + ): OauthResetUrl { + val url = when (scmCode) { + ScmCode.TGIT -> { + gitOauthService.getOauthUrl( + userId = userId, + redirectUrl = redirectUrl + ) + } + + ScmCode.GITHUB -> { + githubOAuthService.getGithubOauth( + userId = userId, + projectId = "", + redirectUrlTypeEnum = RedirectUrlTypeEnum.SPEC, + specRedirectUrl = redirectUrl, + repoHashId = null + ).redirectUrl + } + } + return OauthResetUrl(url) + } + + /** + * 获取git server端真实用户名 + */ + private fun getRealUsername( + scmCode: ScmCode, + accessToken: String + ): Pair { + var expired = false + val username = try { + when (scmCode) { + ScmCode.TGIT -> { + gitService.getUserInfoByToken( + token = accessToken, + tokenType = TokenTypeEnum.OAUTH + ).name + } + + ScmCode.GITHUB -> { + githubOAuthService.getUser(accessToken).login + } + } + } catch (ignored: Exception) { + logger.warn("get [$scmCode] user info failed", ignored) + expired = true + null + } + return expired to username + } + + companion object { + val logger = LoggerFactory.getLogger(OauthRepositoryService::class.java) + } +} diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/RepositoryService.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/RepositoryService.kt index 2a9d9242ea20..a5515e2e3770 100644 --- a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/RepositoryService.kt +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/RepositoryService.kt @@ -67,6 +67,7 @@ import com.tencent.devops.repository.constant.RepositoryMessageCode.REPOSITORY_N import com.tencent.devops.repository.constant.RepositoryMessageCode.USER_CREATE_PEM_ERROR import com.tencent.devops.repository.dao.RepositoryCodeGitDao import com.tencent.devops.repository.dao.RepositoryDao +import com.tencent.devops.repository.dao.RepositoryGithubDao import com.tencent.devops.repository.pojo.AtomRefRepositoryInfo import com.tencent.devops.repository.pojo.AuthorizeResult import com.tencent.devops.repository.pojo.CodeGitRepository @@ -118,7 +119,8 @@ class RepositoryService @Autowired constructor( private val dslContext: DSLContext, private val repositoryPermissionService: RepositoryPermissionService, private val githubService: IGithubService, - private val client: Client + private val client: Client, + private val repositoryGithubDao: RepositoryGithubDao ) { @Value("\${repository.git.devopsPrivateToken}") @@ -1563,41 +1565,68 @@ class RepositoryService @Autowired constructor( fun listOauthRepo( userId: String, - projectId: String?, scmType: ScmType, limit: Int, offset: Int ): SQLPage { - val list = repositoryDao.listOauthRepo( - dslContext = dslContext, - userId = userId, - projectId = projectId, - scmType = scmType, - limit = limit, - offset = offset - ).map { - it.detailUrl = "/console/codelib/${it.projectId}/?id=${it.hashId}" - it - } - val count = countOauthRepo( - userId = userId, - projectId = projectId, - scmType = scmType - ) - return SQLPage(records = list, count = count) + val list = when (scmType) { + ScmType.CODE_GIT -> { + repositoryCodeGitDao.listOauthRepo( + dslContext = dslContext, + userId = userId, + limit = limit, + offset = offset + ) + } + + ScmType.GITHUB -> { + repositoryGithubDao.listOauthRepo( + dslContext = dslContext, + userId = userId, + limit = limit, + offset = offset + ) + } + + else -> { + listOf() + } + }.setDetailUrl() + val count = countOauthRepo(userId, scmType) + return SQLPage(count, list) } fun countOauthRepo( userId: String, - projectId: String?, scmType: ScmType ): Long { - return repositoryDao.countOauthRepo( - dslContext = dslContext, - userId = userId, - projectId = projectId, - scmType = scmType - ) + return when (scmType) { + ScmType.CODE_GIT -> { + repositoryCodeGitDao.countOauthRepo( + dslContext = dslContext, + userId = userId + ) + } + + ScmType.GITHUB -> { + repositoryGithubDao.countOauthRepo( + dslContext = dslContext, + userId = userId + ) + } + + else -> 0L + } + } + + /** + * 填充详情url + */ + private fun List.setDetailUrl(): List { + return this.map { + it.detailUrl = "/console/codelib/${it.projectId}/?id=${it.hashId}" + it + } } companion object { diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/github/GithubOAuthService.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/github/GithubOAuthService.kt index c527d02e701d..5f259c7f8bb2 100644 --- a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/github/GithubOAuthService.kt +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/github/GithubOAuthService.kt @@ -41,6 +41,7 @@ import com.tencent.devops.repository.pojo.github.GithubOauth import com.tencent.devops.repository.pojo.github.GithubOauthCallback import com.tencent.devops.repository.pojo.github.GithubToken import com.tencent.devops.repository.pojo.oauth.GithubTokenType +import com.tencent.devops.repository.sdk.github.response.GetUserResponse import com.tencent.devops.repository.sdk.github.service.GithubUserService import com.tencent.devops.repository.service.ScmUrlProxyService import com.tencent.devops.scm.config.GitConfig @@ -231,6 +232,10 @@ class GithubOAuthService @Autowired constructor( githubTokenService.deleteAccessToken(userId) } + fun getUser(accessToken: String): GetUserResponse { + return githubUserService.getUser(accessToken) + } + companion object { private val logger = LoggerFactory.getLogger(GithubOAuthService::class.java) private const val RANDOM_ALPHA_NUM = 8 diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/oauth2/CodeGitOauth2TokenStoreService.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/oauth2/CodeGitOauth2TokenStoreService.kt new file mode 100644 index 000000000000..2b2e54f832e4 --- /dev/null +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/oauth2/CodeGitOauth2TokenStoreService.kt @@ -0,0 +1,69 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. + * + * A copy of the MIT License is included in this file. + * + * + * Terms of the MIT License: + * --------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.tencent.devops.repository.service.oauth2 + +import com.tencent.devops.common.security.util.BkCryptoUtil +import com.tencent.devops.repository.dao.GitTokenDao +import com.tencent.devops.repository.pojo.CodeGitRepository +import com.tencent.devops.repository.pojo.oauth.Oauth2AccessToken +import org.jooq.DSLContext +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Value +import org.springframework.stereotype.Service + +/** + * 内部工蜂oauth存储管理 + */ +@Service +class CodeGitOauth2TokenStoreService @Autowired constructor( + private val dslContext: DSLContext, + private val gitTokenDao: GitTokenDao +) : IOauth2TokenStoreService { + + @Value("\${aes.git:#{null}}") + private val aesKey: String = "" + + override fun support(scmCode: String): Boolean { + return scmCode == CodeGitRepository.SCM_CODE + } + + override fun get(userId: String, scmCode: String): Oauth2AccessToken? { + return gitTokenDao.getAccessToken(dslContext, userId)?.let { + Oauth2AccessToken( + BkCryptoUtil.decryptSm4OrAes(aesKey, it.accessToken), + it.tokenType, + it.expiresIn, + BkCryptoUtil.decryptSm4OrAes(aesKey, it.refreshToken) + ) + } + } + + override fun delete(userId: String, scmCode: String) { + gitTokenDao.deleteToken(dslContext, userId) + } +} diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/oauth2/CodeGithubOauth2TokenStoreService.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/oauth2/CodeGithubOauth2TokenStoreService.kt new file mode 100644 index 000000000000..bbfbfe721996 --- /dev/null +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/oauth2/CodeGithubOauth2TokenStoreService.kt @@ -0,0 +1,74 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. + * + * A copy of the MIT License is included in this file. + * + * + * Terms of the MIT License: + * --------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.tencent.devops.repository.service.oauth2 + +import com.tencent.devops.common.security.util.BkCryptoUtil +import com.tencent.devops.repository.dao.GithubTokenDao +import com.tencent.devops.repository.pojo.GithubRepository +import com.tencent.devops.repository.pojo.oauth.GithubTokenType +import com.tencent.devops.repository.pojo.oauth.Oauth2AccessToken +import org.jooq.DSLContext +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Value +import org.springframework.stereotype.Service + +/** + * github oauth2 token存储管理 + */ +@Service +class CodeGithubOauth2TokenStoreService @Autowired constructor( + private val dslContext: DSLContext, + private val githubTokenDao: GithubTokenDao +) : IOauth2TokenStoreService { + + @Value("\${aes.github:#{null}}") + private val aesKey = "" + + override fun support(scmCode: String): Boolean { + return scmCode == GithubRepository.SCM_CODE + } + + override fun get(userId: String, scmCode: String): Oauth2AccessToken? { + return githubTokenDao.getOrNull( + dslContext = dslContext, + userId = userId, + githubTokenType = GithubTokenType.GITHUB_APP + )?.let { + Oauth2AccessToken( + BkCryptoUtil.decryptSm4OrAes(aesKey, it.accessToken), + it.tokenType, + null, + null + ) + } + } + + override fun delete(userId: String, scmCode: String) { + githubTokenDao.delete(dslContext, userId) + } +} diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/oauth2/IOauth2TokenStoreService.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/oauth2/IOauth2TokenStoreService.kt new file mode 100644 index 000000000000..5e10f3f3b244 --- /dev/null +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/oauth2/IOauth2TokenStoreService.kt @@ -0,0 +1,41 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. + * + * A copy of the MIT License is included in this file. + * + * + * Terms of the MIT License: + * --------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.tencent.devops.repository.service.oauth2 + +import com.tencent.devops.repository.pojo.oauth.Oauth2AccessToken + +/** + * oauth2 token存储服务 + */ +interface IOauth2TokenStoreService { + fun support(scmCode: String): Boolean + + fun get(userId: String, scmCode: String): Oauth2AccessToken? + + fun delete(userId: String, scmCode: String) +} diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/oauth2/Oauth2TokenStoreManager.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/oauth2/Oauth2TokenStoreManager.kt new file mode 100644 index 000000000000..aa47ec37c592 --- /dev/null +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/oauth2/Oauth2TokenStoreManager.kt @@ -0,0 +1,51 @@ +/* + * Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * BK-CI 蓝鲸持续集成平台 is licensed under the MIT license. + * + * A copy of the MIT License is included in this file. + * + * + * Terms of the MIT License: + * --------------------------------------------------- + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of + * the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.tencent.devops.repository.service.oauth2 + +import com.tencent.devops.common.api.exception.ErrorCodeException +import com.tencent.devops.repository.pojo.oauth.Oauth2AccessToken +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service + +@Service +class Oauth2TokenStoreManager @Autowired constructor( + private val oauth2TokenStoreServices: List +) { + + fun get(userId: String, scmCode: String): Oauth2AccessToken? { + return getTokenStoreService(scmCode).get(userId, scmCode) + } + + fun delete(userId: String, scmCode: String) { + getTokenStoreService(scmCode).delete(userId, scmCode) + } + + private fun getTokenStoreService(scmCode: String): IOauth2TokenStoreService { + return oauth2TokenStoreServices.find { it.support(scmCode) } ?: throw ErrorCodeException(errorCode = "") + } +} diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/scm/GitOauthService.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/scm/GitOauthService.kt index 60801d6ce313..e07694a8b168 100644 --- a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/scm/GitOauthService.kt +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/scm/GitOauthService.kt @@ -45,6 +45,8 @@ import com.tencent.devops.repository.constant.RepositoryMessageCode import com.tencent.devops.repository.dao.GitTokenDao import com.tencent.devops.repository.pojo.AuthorizeResult import com.tencent.devops.repository.pojo.enums.RedirectUrlTypeEnum +import com.tencent.devops.repository.pojo.enums.TokenTypeEnum +import com.tencent.devops.repository.pojo.git.GitUserInfo import com.tencent.devops.repository.pojo.oauth.GitOauthCallback import com.tencent.devops.repository.pojo.oauth.GitToken import com.tencent.devops.scm.code.git.api.GitBranch diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/scm/IGitOauthService.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/scm/IGitOauthService.kt index 67bd1ff905b5..a57afd4cd86e 100644 --- a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/scm/IGitOauthService.kt +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/scm/IGitOauthService.kt @@ -29,6 +29,7 @@ package com.tencent.devops.repository.service.scm import com.tencent.devops.repository.pojo.AuthorizeResult import com.tencent.devops.repository.pojo.enums.RedirectUrlTypeEnum +import com.tencent.devops.repository.pojo.git.GitUserInfo import com.tencent.devops.repository.pojo.oauth.GitOauthCallback import com.tencent.devops.repository.pojo.oauth.GitToken import com.tencent.devops.scm.code.git.api.GitBranch