diff --git a/src/backend/ci/core/common/common-api/src/main/kotlin/com/tencent/devops/common/api/constant/CommonMessageCode.kt b/src/backend/ci/core/common/common-api/src/main/kotlin/com/tencent/devops/common/api/constant/CommonMessageCode.kt index 4146623669a..cfe16c93e6c 100644 --- a/src/backend/ci/core/common/common-api/src/main/kotlin/com/tencent/devops/common/api/constant/CommonMessageCode.kt +++ b/src/backend/ci/core/common/common-api/src/main/kotlin/com/tencent/devops/common/api/constant/CommonMessageCode.kt @@ -220,6 +220,7 @@ object CommonMessageCode { const val GET_PROJECT_INFO = "bkGetProjectInfo" // 获取项目详情 const val GET_COMMIT_REVIEW_INFO = "bkGetCommitReviewInfo" // 获取Commit Review详情 + const val GET_SESSION_INFO = "bkGetSessionInfo" // 获取会话详情 const val OPERATION_BRANCH = "bkOperationBranch" // 拉分支 const val OPERATION_TAG = "bkOperationTag" // 拉标签 diff --git a/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/IScm.kt b/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/IScm.kt index 9e9fa030454..77fd48b0ea2 100644 --- a/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/IScm.kt +++ b/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/IScm.kt @@ -34,6 +34,7 @@ import com.tencent.devops.scm.pojo.GitMrChangeInfo import com.tencent.devops.scm.pojo.GitMrInfo import com.tencent.devops.scm.pojo.GitMrReviewInfo import com.tencent.devops.scm.pojo.GitProjectInfo +import com.tencent.devops.scm.pojo.GitSession import com.tencent.devops.scm.pojo.RevisionInfo @Suppress("ALL") @@ -90,4 +91,6 @@ interface IScm { fun getProjectInfo(projectName: String): GitProjectInfo? = null fun getCommitReviewInfo(crId: Long): GitCommitReviewInfo? = null + + fun getGitSession(): GitSession? = null } diff --git a/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/code/CodeGitScmImpl.kt b/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/code/CodeGitScmImpl.kt index ceea3bad1b0..8d93250d83b 100644 --- a/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/code/CodeGitScmImpl.kt +++ b/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/code/CodeGitScmImpl.kt @@ -42,6 +42,7 @@ import com.tencent.devops.scm.pojo.GitMrChangeInfo import com.tencent.devops.scm.pojo.GitMrInfo import com.tencent.devops.scm.pojo.GitMrReviewInfo import com.tencent.devops.scm.pojo.GitProjectInfo +import com.tencent.devops.scm.pojo.GitSession import com.tencent.devops.scm.pojo.RevisionInfo import com.tencent.devops.scm.utils.code.git.GitUtils.urlEncode import org.eclipse.jgit.api.Git @@ -320,6 +321,16 @@ class CodeGitScmImpl constructor( ) } + override fun getGitSession(): GitSession? { + val url = "session" + return gitApi.getGitSession( + host = apiUrl, + url = url, + username = privateKey!!, + password = passPhrase!! + ) + } + companion object { private val logger = LoggerFactory.getLogger(CodeGitScmImpl::class.java) } diff --git a/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/code/CodeTGitScmImpl.kt b/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/code/CodeTGitScmImpl.kt index 1ad28e7d661..3a198273815 100644 --- a/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/code/CodeTGitScmImpl.kt +++ b/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/code/CodeTGitScmImpl.kt @@ -40,6 +40,7 @@ import com.tencent.devops.scm.pojo.GitMrChangeInfo import com.tencent.devops.scm.pojo.GitMrInfo import com.tencent.devops.scm.pojo.GitMrReviewInfo import com.tencent.devops.scm.pojo.GitProjectInfo +import com.tencent.devops.scm.pojo.GitSession import com.tencent.devops.scm.pojo.RevisionInfo import com.tencent.devops.scm.utils.code.git.GitUtils import com.tencent.devops.scm.utils.code.git.GitUtils.urlEncode @@ -301,6 +302,16 @@ class CodeTGitScmImpl constructor( ) } + override fun getGitSession(): GitSession? { + val url = "session" + return gitApi.getGitSession( + host = apiUrl, + url = url, + username = privateKey!!, + password = passPhrase!! + ) + } + companion object { private val logger = LoggerFactory.getLogger(CodeTGitScmImpl::class.java) } diff --git a/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/code/git/api/GitApi.kt b/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/code/git/api/GitApi.kt index 79675791043..14511892bbb 100644 --- a/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/code/git/api/GitApi.kt +++ b/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/code/git/api/GitApi.kt @@ -53,6 +53,7 @@ import com.tencent.devops.scm.pojo.GitMrChangeInfo import com.tencent.devops.scm.pojo.GitMrInfo import com.tencent.devops.scm.pojo.GitMrReviewInfo import com.tencent.devops.scm.pojo.GitProjectInfo +import com.tencent.devops.scm.pojo.GitSession import com.tencent.devops.scm.pojo.TapdWorkItem import io.micrometer.core.instrument.MeterRegistry import io.micrometer.core.instrument.Tag @@ -659,4 +660,28 @@ open class GitApi { ) ) } + + fun getGitSession( + host: String, + url: String, + username: String, + password: String + ): GitSession? { + val body = JsonUtil.toJson( + mapOf( + "login" to username, + "password" to password + ), + false + ) + val request = post(host, "", url, body) + val responseBody = getBody( + getMessageByLocale(CommonMessageCode.GET_SESSION_INFO), + request + ).ifBlank { + logger.warn("get session is blank, please check the username and password") + return null + } + return JsonUtil.getObjectMapper().readValue(responseBody) + } } diff --git a/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/pojo/GitSession.kt b/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/pojo/GitSession.kt new file mode 100644 index 00000000000..25a93c4ad9b --- /dev/null +++ b/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/pojo/GitSession.kt @@ -0,0 +1,42 @@ +/* + * 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.scm.pojo + +import com.fasterxml.jackson.annotation.JsonProperty +import io.swagger.annotations.ApiModel +import io.swagger.annotations.ApiModelProperty + +@ApiModel("工蜂会话信息") +data class GitSession( + val id: String, + @ApiModelProperty("邮箱地址") + val email: String, + @ApiModelProperty("用户名") + val username: String, + @JsonProperty("private_token") + val privateToken: String +) diff --git a/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/pojo/RepoSessionRequest.kt b/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/pojo/RepoSessionRequest.kt new file mode 100644 index 00000000000..0de342af9e2 --- /dev/null +++ b/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/pojo/RepoSessionRequest.kt @@ -0,0 +1,42 @@ +/* + * 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.scm.pojo + +import com.tencent.devops.common.api.enums.ScmType +import io.swagger.annotations.ApiParam + +data class RepoSessionRequest( + @ApiParam("仓库类型", required = true) + val type: ScmType, + @ApiParam("username", required = true) + val username: String, + @ApiParam("password", required = true) + val password: String, + @ApiParam("url", required = true) + val url: String +) diff --git a/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/utils/code/git/GitUtils.kt b/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/utils/code/git/GitUtils.kt index 9bc0c67049e..c598a2d2475 100644 --- a/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/utils/code/git/GitUtils.kt +++ b/src/backend/ci/core/common/common-scm/src/main/kotlin/com/tencent/devops/scm/utils/code/git/GitUtils.kt @@ -133,4 +133,17 @@ object GitUtils { commitId.substring(0, 8) } } + + /** + * 校验代码库url + */ + fun diffRepoUrl( + sourceRepoUrl: String, + targetRepoUrl: String + ): Boolean { + val sourceRepoInfo = GitUtils.getDomainAndRepoName(sourceRepoUrl) + val targetRepoInfo = GitUtils.getDomainAndRepoName(targetRepoUrl) + return sourceRepoInfo.first != targetRepoInfo.first || + sourceRepoInfo.second != targetRepoInfo.second + } } diff --git a/src/backend/ci/core/common/common-webhook/biz-common-webhook/src/main/kotlin/com/tencent/devops/common/webhook/service/code/GitScmService.kt b/src/backend/ci/core/common/common-webhook/biz-common-webhook/src/main/kotlin/com/tencent/devops/common/webhook/service/code/GitScmService.kt index 329cc31f311..679fd081be5 100644 --- a/src/backend/ci/core/common/common-webhook/biz-common-webhook/src/main/kotlin/com/tencent/devops/common/webhook/service/code/GitScmService.kt +++ b/src/backend/ci/core/common/common-webhook/biz-common-webhook/src/main/kotlin/com/tencent/devops/common/webhook/service/code/GitScmService.kt @@ -50,7 +50,10 @@ import com.tencent.devops.scm.pojo.GitCommitReviewInfo import com.tencent.devops.scm.pojo.GitMrChangeInfo import com.tencent.devops.scm.pojo.GitMrInfo import com.tencent.devops.scm.pojo.GitMrReviewInfo +import com.tencent.devops.scm.pojo.GitSession +import com.tencent.devops.scm.pojo.RepoSessionRequest import com.tencent.devops.ticket.api.ServiceCredentialResource +import com.tencent.devops.ticket.pojo.enums.CredentialType import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Service @@ -80,7 +83,9 @@ class GitScmService @Autowired constructor( projectId = projectId, credentialId = repo.credentialId, userName = repo.userName, - authType = tokenType + authType = tokenType, + scmType = repo.getScmType(), + repoUrl = repo.url ) if (type.first == RepoAuthType.OAUTH) { client.get(ServiceScmOauthResource::class).getMrReviewInfo( @@ -119,7 +124,9 @@ class GitScmService @Autowired constructor( projectId = projectId, credentialId = repo.credentialId, userName = repo.userName, - authType = tokenType + authType = tokenType, + scmType = repo.getScmType(), + repoUrl = repo.url ) if (type.first == RepoAuthType.OAUTH) { client.get(ServiceScmOauthResource::class).getMrInfo( @@ -158,7 +165,9 @@ class GitScmService @Autowired constructor( projectId = projectId, credentialId = repo.credentialId, userName = repo.userName, - authType = tokenType + authType = tokenType, + scmType = repo.getScmType(), + repoUrl = repo.url ) if (type.first == RepoAuthType.OAUTH) { client.get(ServiceScmOauthResource::class).getMergeRequestChangeInfo( @@ -197,7 +206,9 @@ class GitScmService @Autowired constructor( projectId = projectId, credentialId = repo.credentialId, userName = repo.userName, - authType = tokenType + authType = tokenType, + scmType = repo.getScmType(), + repoUrl = repo.url ) for (i in 1..10) { // 反向进行三点比较可以比较出rebase的真实提交 @@ -241,7 +252,9 @@ class GitScmService @Autowired constructor( projectId = projectId, credentialId = repo.credentialId, userName = repo.userName, - authType = tokenType + authType = tokenType, + scmType = repo.getScmType(), + repoUrl = repo.url ) val serviceGitResource = client.get(ServiceGitResource::class) val defaultBranch = serviceGitResource.getProjectInfo( @@ -276,7 +289,9 @@ class GitScmService @Autowired constructor( projectId = projectId, credentialId = repo.credentialId, userName = repo.userName, - authType = tokenType + authType = tokenType, + scmType = repo.getScmType(), + repoUrl = repo.url ) if (type.first == RepoAuthType.OAUTH) { return client.get(ServiceScmOauthResource::class).getMrCommitList( @@ -312,7 +327,9 @@ class GitScmService @Autowired constructor( projectId = projectId, credentialId = repo.credentialId, userName = repo.userName, - authType = tokenType + authType = tokenType, + scmType = repo.getScmType(), + repoUrl = repo.url ) client.get(ServiceGitResource::class).getUserInfoByToken( token = token, @@ -324,15 +341,27 @@ class GitScmService @Autowired constructor( } } - private fun getToken(projectId: String, credentialId: String, userName: String, authType: TokenTypeEnum): String { + private fun getToken( + projectId: String, + credentialId: String, + userName: String, + authType: TokenTypeEnum, + scmType: ScmType, + repoUrl: String = "" + ): String { return if (authType == TokenTypeEnum.OAUTH) { client.get(ServiceOauthResource::class).gitGet(userName).data?.accessToken ?: "" } else { - getCredential(projectId, credentialId) + getCredential(projectId, credentialId, scmType = scmType, repoUrl = repoUrl) } } - fun getCredential(projectId: String, credentialId: String): String { + fun getCredential( + projectId: String, + credentialId: String, + scmType: ScmType? = null, + repoUrl: String = "" + ): String { val pair = DHUtil.initKey() val encoder = Base64.getEncoder() val decoder = Base64.getDecoder() @@ -349,13 +378,31 @@ class GitScmService @Autowired constructor( val credential = credentialResult.data!! - return String( + val privateKey = String( DHUtil.decrypt( data = decoder.decode(credential.v1), partBPublicKey = decoder.decode(credential.publicKey), partAPrivateKey = pair.privateKey ) ) + if (credential.credentialType == CredentialType.USERNAME_PASSWORD && + (scmType == ScmType.CODE_GIT || scmType == ScmType.CODE_TGIT) + ) { + val password = String( + DHUtil.decrypt( + data = decoder.decode(credential.v2), + partBPublicKey = decoder.decode(credential.publicKey), + partAPrivateKey = pair.privateKey + ) + ) + return getSession( + scmType = scmType, + username = privateKey, + password = password, + url = repoUrl + )?.privateToken ?: "" + } + return privateKey } private fun getType(repo: Repository): Pair? { @@ -388,7 +435,9 @@ class GitScmService @Autowired constructor( projectId = projectId, credentialId = repo.credentialId, userName = repo.userName, - authType = tokenType + authType = tokenType, + scmType = repo.getScmType(), + repoUrl = repo.url ) if (type.first == RepoAuthType.OAUTH) { client.get(ServiceScmOauthResource::class).getCommitReviewInfo( @@ -436,4 +485,20 @@ class GitScmService @Autowired constructor( null } } + + fun getSession( + scmType: ScmType, + username: String, + password: String, + url: String + ): GitSession? { + return client.get(ServiceScmResource::class).getSession( + RepoSessionRequest( + type = scmType, + username = username, + password = password, + url = url + ) + ).data + } } diff --git a/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/service/scm/ScmProxyService.kt b/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/service/scm/ScmProxyService.kt index 18bdb971fe1..3dd05a7884d 100644 --- a/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/service/scm/ScmProxyService.kt +++ b/src/backend/ci/core/process/biz-base/src/main/kotlin/com/tencent/devops/process/service/scm/ScmProxyService.kt @@ -58,8 +58,10 @@ import com.tencent.devops.repository.pojo.GithubRepository import com.tencent.devops.repository.pojo.Repository import com.tencent.devops.repository.pojo.enums.RepoAuthType import com.tencent.devops.scm.code.git.CodeGitWebhookEvent +import com.tencent.devops.scm.pojo.RepoSessionRequest import com.tencent.devops.scm.pojo.RevisionInfo import com.tencent.devops.ticket.api.ServiceCredentialResource +import com.tencent.devops.ticket.pojo.enums.CredentialType import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Service @@ -693,12 +695,31 @@ class ScmProxyService @Autowired constructor(private val client: Client) { ) ) + // username+password 关联的git代码库 + if ((repository is CodeGitRepository || repository is CodeTGitRepository) && + (credential.credentialType == CredentialType.USERNAME_PASSWORD) + ) { + // USERNAME_PASSWORD v1 = username, v2 = password + val session = client.get(ServiceScmResource::class).getSession( + RepoSessionRequest( + type = repository.getScmType(), + username = privateKey, + password = passPhrase, + url = repository.url + ) + ).data + return Credential( + username = privateKey, + privateKey = session?.privateToken ?: "", + passPhrase = passPhrase + ) + } + val list = if (passPhrase.isBlank()) { listOf(privateKey) } else { listOf(privateKey, passPhrase) } - return CredentialUtils.getCredential(repository, list, credentialResult.data!!.credentialType) } diff --git a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/api/UserGithubResource.kt b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/api/UserGithubResource.kt index 2fad6b71be0..85219f3c1c8 100644 --- a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/api/UserGithubResource.kt +++ b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/api/UserGithubResource.kt @@ -78,4 +78,22 @@ interface UserGithubResource { @GET @Path("/githubAppUrl") fun getGithubAppUrl(): Result + + @ApiOperation("根据用户ID判断用户是否已经oauth认证") + @GET + @Path("/isOauth") + fun isOAuth( + @ApiParam(value = "用户ID", required = true, defaultValue = AUTH_HEADER_USER_ID_DEFAULT_VALUE) + @HeaderParam(AUTH_HEADER_USER_ID) + userId: String, + @ApiParam(value = "蓝盾项目", required = true) + @QueryParam("projectId") + projectId: String, + @ApiParam(value = "是否刷新token", required = false) + @QueryParam("refreshToken") + refreshToken: Boolean? = false, + @ApiParam(value = "重置授权类型,前端根据不同代码库类型,在重置授权时跳转不同的弹框", required = false) + @QueryParam("resetType") + resetType: String? + ): Result } diff --git a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/api/scm/ServiceScmResource.kt b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/api/scm/ServiceScmResource.kt index 542a30918fb..f85f5deca70 100644 --- a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/api/scm/ServiceScmResource.kt +++ b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/api/scm/ServiceScmResource.kt @@ -36,6 +36,8 @@ import com.tencent.devops.scm.pojo.GitCommitReviewInfo import com.tencent.devops.scm.pojo.GitMrChangeInfo import com.tencent.devops.scm.pojo.GitMrInfo import com.tencent.devops.scm.pojo.GitMrReviewInfo +import com.tencent.devops.scm.pojo.GitSession +import com.tencent.devops.scm.pojo.RepoSessionRequest import com.tencent.devops.scm.pojo.RevisionInfo import com.tencent.devops.scm.pojo.TokenCheckResult import io.swagger.annotations.Api @@ -410,4 +412,11 @@ interface ServiceScmResource { @QueryParam("crId") crId: Long ): Result + + @ApiOperation("获取会话信息") + @POST + @Path("getGitSession") + fun getSession( + reposSessionRequest: RepoSessionRequest + ): Result } diff --git a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/constant/RepositoryMessageCode.kt b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/constant/RepositoryMessageCode.kt index 4860971632e..1277990e6cb 100644 --- a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/constant/RepositoryMessageCode.kt +++ b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/constant/RepositoryMessageCode.kt @@ -73,6 +73,7 @@ object RepositoryMessageCode { const val REPOSITORY_ID_AND_NAME_ARE_EMPTY = "2115024" // 仓库ID和仓库名都为空 const val USER_NEED_PROJECT_X_PERMISSION = "2115025" // 用户({0})无({1})项目权限 const val NOT_AUTHORIZED_BY_OAUTH = "2115026" // 用户[{0}]尚未进行OAUTH授权,请先授权。 + const val CAN_NOT_SWITCH_REPO_URL = "2115027" // 不可切换代码库地址 const val BK_REQUEST_FILE_SIZE_LIMIT = "bkRequestFileSizeLimit" // 请求文件不能超过1M const val OPERATION_ADD_CHECK_RUNS = "OperationAddCheckRuns" // 添加检测任务 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 f09e754648c..afa69192cc3 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 @@ -27,6 +27,7 @@ package com.tencent.devops.repository.pojo +import com.tencent.devops.common.api.enums.ScmType import com.tencent.devops.repository.pojo.enums.RepoAuthType import com.tencent.devops.scm.utils.code.git.GitUtils import io.swagger.annotations.ApiModel @@ -75,4 +76,6 @@ data class CodeGitRepository( GitUtils.isLegalSshUrl(url) } } + + override fun getScmType() = ScmType.CODE_GIT } diff --git a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/CodeGitlabRepository.kt b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/CodeGitlabRepository.kt index 0a826adc82b..bb8d992a7ec 100644 --- a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/CodeGitlabRepository.kt +++ b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/CodeGitlabRepository.kt @@ -27,6 +27,7 @@ package com.tencent.devops.repository.pojo +import com.tencent.devops.common.api.enums.ScmType import com.tencent.devops.repository.pojo.enums.RepoAuthType import com.tencent.devops.scm.utils.code.git.GitUtils import io.swagger.annotations.ApiModel @@ -74,4 +75,6 @@ data class CodeGitlabRepository( GitUtils.isLegalSshUrl(url) } } + + override fun getScmType() = ScmType.CODE_GITLAB } diff --git a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/CodeP4Repository.kt b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/CodeP4Repository.kt index 01c85581aaa..65e6ca3f415 100644 --- a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/CodeP4Repository.kt +++ b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/CodeP4Repository.kt @@ -27,6 +27,7 @@ package com.tencent.devops.repository.pojo +import com.tencent.devops.common.api.enums.ScmType import io.swagger.annotations.ApiModel import io.swagger.annotations.ApiModelProperty @@ -59,4 +60,6 @@ data class CodeP4Repository( override fun isLegal(): Boolean { return true } + + override fun getScmType() = ScmType.CODE_P4 } diff --git a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/CodeSvnRepository.kt b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/CodeSvnRepository.kt index b61cc90d115..d5db961b91b 100644 --- a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/CodeSvnRepository.kt +++ b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/CodeSvnRepository.kt @@ -27,6 +27,7 @@ package com.tencent.devops.repository.pojo +import com.tencent.devops.common.api.enums.ScmType import com.tencent.devops.scm.enums.CodeSvnRegion import io.swagger.annotations.ApiModel import io.swagger.annotations.ApiModelProperty @@ -85,4 +86,6 @@ data class CodeSvnRepository( } override fun getStartPrefix() = "svn+ssh://" + + override fun getScmType() = ScmType.CODE_SVN } diff --git a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/CodeTGitRepository.kt b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/CodeTGitRepository.kt index 39b0188095e..e11a3d68bdc 100644 --- a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/CodeTGitRepository.kt +++ b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/CodeTGitRepository.kt @@ -27,6 +27,7 @@ package com.tencent.devops.repository.pojo +import com.tencent.devops.common.api.enums.ScmType import com.tencent.devops.repository.pojo.enums.RepoAuthType import com.tencent.devops.scm.utils.code.git.GitUtils import io.swagger.annotations.ApiModel @@ -75,4 +76,6 @@ data class CodeTGitRepository( GitUtils.isLegalSshUrl(url) } } + + override fun getScmType() = ScmType.CODE_TGIT } 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 61e6846db2f..5232ca255ff 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 @@ -27,6 +27,7 @@ package com.tencent.devops.repository.pojo +import com.tencent.devops.common.api.enums.ScmType import io.swagger.annotations.ApiModel import io.swagger.annotations.ApiModelProperty @@ -55,4 +56,6 @@ data class GithubRepository( } override fun getStartPrefix() = "https://github.com/" + + override fun getScmType() = ScmType.GITHUB } diff --git a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/Repository.kt b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/Repository.kt index e5d921f6255..7daafe70bf3 100644 --- a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/Repository.kt +++ b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/Repository.kt @@ -29,6 +29,7 @@ package com.tencent.devops.repository.pojo import com.fasterxml.jackson.annotation.JsonSubTypes import com.fasterxml.jackson.annotation.JsonTypeInfo +import com.tencent.devops.common.api.enums.ScmType import io.swagger.annotations.ApiModel @ApiModel("代码库模型-多态基类") @@ -55,4 +56,6 @@ interface Repository { fun getStartPrefix(): String fun getFormatURL() = url + + fun getScmType(): ScmType } diff --git a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/credential/RepoCredentialInfo.kt b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/credential/RepoCredentialInfo.kt index 3433e5b6e02..5a990621258 100644 --- a/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/credential/RepoCredentialInfo.kt +++ b/src/backend/ci/core/repository/api-repository/src/main/kotlin/com/tencent/devops/repository/pojo/credential/RepoCredentialInfo.kt @@ -32,7 +32,7 @@ import io.swagger.annotations.ApiModelProperty @ApiModel("仓库授权信息") data class RepoCredentialInfo( @ApiModelProperty("授权Token") - val token: String = "", + var token: String = "", @ApiModelProperty("授权私钥") val privateKey: String = "", @ApiModelProperty("私钥密码") diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/resources/UserGithubResourceImpl.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/resources/UserGithubResourceImpl.kt index 4a5fc9f00c6..982edbf54ec 100644 --- a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/resources/UserGithubResourceImpl.kt +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/resources/UserGithubResourceImpl.kt @@ -55,4 +55,20 @@ class UserGithubResourceImpl @Autowired constructor( override fun getGithubAppUrl(): Result { return Result(githubOAuthService.getGithubAppUrl()) } + + override fun isOAuth( + userId: String, + projectId: String, + refreshToken: Boolean?, + resetType: String? + ): Result { + return Result( + githubService.isOAuth( + userId = userId, + projectId = projectId, + refreshToken = refreshToken, + resetType = resetType + ) + ) + } } diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/resources/scm/ServiceScmResourceImpl.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/resources/scm/ServiceScmResourceImpl.kt index 34c6dbcf0a9..3e208a524b0 100644 --- a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/resources/scm/ServiceScmResourceImpl.kt +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/resources/scm/ServiceScmResourceImpl.kt @@ -40,6 +40,8 @@ import com.tencent.devops.scm.pojo.GitCommitReviewInfo import com.tencent.devops.scm.pojo.GitMrChangeInfo import com.tencent.devops.scm.pojo.GitMrInfo import com.tencent.devops.scm.pojo.GitMrReviewInfo +import com.tencent.devops.scm.pojo.GitSession +import com.tencent.devops.scm.pojo.RepoSessionRequest import com.tencent.devops.scm.pojo.RevisionInfo import com.tencent.devops.scm.pojo.TokenCheckResult import org.slf4j.LoggerFactory @@ -335,6 +337,19 @@ class ServiceScmResourceImpl @Autowired constructor(private val scmService: IScm ) } + override fun getSession(reposSessionRequest: RepoSessionRequest): Result { + return with(reposSessionRequest) { + Result( + scmService.getGitSession( + type = type, + username = username, + password = password, + url = url + ) + ) + } + } + companion object { private val logger = LoggerFactory.getLogger(ServiceScmResourceImpl::class.java) } diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/RepoFileService.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/RepoFileService.kt index beee8f79c1d..93f6c1f73c8 100644 --- a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/RepoFileService.kt +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/RepoFileService.kt @@ -38,6 +38,7 @@ import com.tencent.devops.common.api.util.DHUtil import com.tencent.devops.common.client.Client import com.tencent.devops.common.web.utils.I18nUtil import com.tencent.devops.repository.api.ServiceOauthResource +import com.tencent.devops.repository.api.scm.ServiceScmResource import com.tencent.devops.repository.constant.RepositoryMessageCode.NOT_AUTHORIZED_BY_OAUTH import com.tencent.devops.repository.dao.GitTokenDao import com.tencent.devops.repository.dao.TGitTokenDao @@ -60,11 +61,13 @@ import com.tencent.devops.repository.utils.CredentialUtils import com.tencent.devops.repository.utils.RepositoryUtils import com.tencent.devops.scm.code.svn.ISvnService import com.tencent.devops.scm.pojo.DownloadGitRepoFileRequest +import com.tencent.devops.scm.pojo.RepoSessionRequest import com.tencent.devops.scm.utils.code.svn.SvnUtils import com.tencent.devops.ticket.api.ServiceCredentialResource import java.util.Base64 import javax.servlet.http.HttpServletResponse import javax.ws.rs.NotFoundException +import com.tencent.devops.ticket.pojo.enums.CredentialType import org.jooq.DSLContext import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired @@ -504,6 +507,26 @@ class RepoFileService @Autowired constructor( ) ) + // username+password 关联的git代码库 + if ((repository is CodeGitRepository || repository is CodeTGitRepository) && + (credential.credentialType == CredentialType.USERNAME_PASSWORD) + ) { + // USERNAME_PASSWORD v1 = username, v2 = password + val session = client.get(ServiceScmResource::class).getSession( + RepoSessionRequest( + type = repository.getScmType(), + username = privateKey, + password = passPhrase, + url = repository.url + ) + ).data + return Credential( + username = privateKey, + privateKey = session?.privateToken ?: "", + passPhrase = passPhrase + ) + } + val list = if (passPhrase.isBlank()) { listOf(privateKey) } else { 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 1b335a4ff0f..206518b42cb 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 @@ -588,7 +588,6 @@ class RepositoryService @Autowired constructor( ) ) } - if (hasAliasName(projectId, repositoryHashId, repository.aliasName)) { throw OperationException( MessageUtil.getMessageByLocale( diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeGitRepositoryService.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeGitRepositoryService.kt index fe98ec632fe..6b33fdd4a0c 100644 --- a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeGitRepositoryService.kt +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeGitRepositoryService.kt @@ -31,8 +31,10 @@ import com.tencent.devops.common.api.enums.ScmType import com.tencent.devops.common.api.exception.ErrorCodeException import com.tencent.devops.common.api.exception.OperationException import com.tencent.devops.common.api.util.HashUtil +import com.tencent.devops.common.api.util.MessageUtil import com.tencent.devops.common.web.utils.I18nUtil import com.tencent.devops.model.repository.tables.records.TRepositoryRecord +import com.tencent.devops.repository.constant.RepositoryMessageCode import com.tencent.devops.repository.constant.RepositoryMessageCode.GIT_INVALID import com.tencent.devops.repository.constant.RepositoryMessageCode.REPO_TYPE_NO_NEED_CERTIFICATION import com.tencent.devops.repository.constant.RepositoryMessageCode.USER_SECRET_EMPTY @@ -48,6 +50,7 @@ import com.tencent.devops.repository.service.scm.IScmOauthService import com.tencent.devops.repository.service.scm.IScmService import com.tencent.devops.scm.pojo.TokenCheckResult import com.tencent.devops.scm.utils.code.git.GitUtils +import com.tencent.devops.ticket.pojo.enums.CredentialType import org.apache.commons.lang3.StringUtils import org.jooq.DSLContext import org.jooq.impl.DSL @@ -117,6 +120,16 @@ class CodeGitRepositoryService @Autowired constructor( ) ) } + // 不得切换代码库 + if (GitUtils.diffRepoUrl(record.url, repository.url)) { + logger.warn("can not switch repo url|sourceUrl[${record.url}]|targetUrl[${repository.url}]") + throw OperationException( + MessageUtil.getMessageByLocale( + RepositoryMessageCode.CAN_NOT_SWITCH_REPO_URL, + I18nUtil.getLanguage(userId) + ) + ) + } // 凭证信息 val credentialInfo = checkCredentialInfo(projectId = projectId, repository = repository) val repositoryId = HashUtil.decodeOtherIdToLong(repositoryHashId) @@ -126,11 +139,13 @@ class CodeGitRepositoryService @Autowired constructor( projectId = projectId, repositoryId = repositoryId ).url - var gitProjectId: Long? = 0L + var gitProjectId: Long? = null // 需要更新gitProjectId if (sourceUrl != repository.url) { - logger.info("repository url unMatch,need change gitProjectId,sourceUrl=[$sourceUrl] " + - "targetUrl=[${repository.url}]") + logger.info( + "repository url unMatch,need change gitProjectId,sourceUrl=[$sourceUrl] " + + "targetUrl=[${repository.url}]" + ) // Git项目ID gitProjectId = getGitProjectId( repo = repository, @@ -199,6 +214,7 @@ class CodeGitRepositoryService @Autowired constructor( userName = repository.userName ) } + RepoAuthType.HTTP -> { if (repoCredentialInfo.username.isEmpty()) { throw OperationException( @@ -221,6 +237,7 @@ class CodeGitRepositoryService @Autowired constructor( repoUsername = repository.userName ) } + else -> { throw ErrorCodeException( errorCode = REPO_TYPE_NO_NEED_CERTIFICATION, @@ -280,6 +297,16 @@ class CodeGitRepositoryService @Autowired constructor( val repoCredentialInfo = getCredentialInfo(projectId = projectId, repository = repository) // 若授权类型不为OAUTH则需要检查Token if (repository.authType != RepoAuthType.OAUTH) { + // 授权凭证信息 + if (repoCredentialInfo.credentialType == CredentialType.USERNAME_PASSWORD.name) { + logger.info("using credential of type [USERNAME_PASSWORD],loginUser[${repoCredentialInfo.username}]") + repoCredentialInfo.token = scmService.getGitSession( + type = ScmType.CODE_GIT, + username = repoCredentialInfo.username, + password = repoCredentialInfo.password, + url = repository.url + )?.privateToken ?: "" + } val checkResult = checkToken( repoCredentialInfo = repoCredentialInfo, repository = repository diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeGithubRepositoryService.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeGithubRepositoryService.kt index 28a16c19548..2553122a2e2 100644 --- a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeGithubRepositoryService.kt +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeGithubRepositoryService.kt @@ -29,9 +29,11 @@ package com.tencent.devops.repository.service.code import com.tencent.devops.common.api.enums.ScmType import com.tencent.devops.common.api.exception.OperationException import com.tencent.devops.common.api.util.HashUtil +import com.tencent.devops.common.api.util.MessageUtil import com.tencent.devops.common.sdk.github.request.GetRepositoryRequest import com.tencent.devops.common.web.utils.I18nUtil import com.tencent.devops.model.repository.tables.records.TRepositoryRecord +import com.tencent.devops.repository.constant.RepositoryMessageCode import com.tencent.devops.repository.constant.RepositoryMessageCode.GITHUB_INVALID import com.tencent.devops.repository.dao.RepositoryDao import com.tencent.devops.repository.dao.RepositoryGithubDao @@ -40,6 +42,7 @@ import com.tencent.devops.repository.pojo.GithubRepository import com.tencent.devops.repository.pojo.auth.RepoAuthInfo import com.tencent.devops.repository.pojo.enums.RepoAuthType import com.tencent.devops.repository.service.github.GithubTokenService +import com.tencent.devops.scm.utils.code.git.GitUtils import org.jooq.DSLContext import org.jooq.impl.DSL import org.slf4j.LoggerFactory @@ -98,6 +101,16 @@ class CodeGithubRepositoryService @Autowired constructor( ) ) } + // 不得切换代码库 + if (GitUtils.diffRepoUrl(record.url, repository.url)) { + logger.warn("can not switch repo url|sourceUrl[${record.url}]|targetUrl[${repository.url}]") + throw OperationException( + MessageUtil.getMessageByLocale( + RepositoryMessageCode.CAN_NOT_SWITCH_REPO_URL, + I18nUtil.getLanguage(userId) + ) + ) + } val repositoryId = HashUtil.decodeOtherIdToLong(repositoryHashId) val sourceUrl = repositoryDao.get( dslContext = dslContext, diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeGitlabRepositoryService.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeGitlabRepositoryService.kt index 966068e9f03..c80181641e5 100644 --- a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeGitlabRepositoryService.kt +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeGitlabRepositoryService.kt @@ -31,8 +31,10 @@ import com.tencent.devops.common.api.constant.CommonMessageCode.GITLAB_INVALID import com.tencent.devops.common.api.enums.ScmType import com.tencent.devops.common.api.exception.OperationException import com.tencent.devops.common.api.util.HashUtil +import com.tencent.devops.common.api.util.MessageUtil import com.tencent.devops.common.web.utils.I18nUtil import com.tencent.devops.model.repository.tables.records.TRepositoryRecord +import com.tencent.devops.repository.constant.RepositoryMessageCode import com.tencent.devops.repository.constant.RepositoryMessageCode.USER_SECRET_EMPTY import com.tencent.devops.repository.dao.RepositoryCodeGitLabDao import com.tencent.devops.repository.dao.RepositoryDao @@ -109,6 +111,16 @@ class CodeGitlabRepositoryService @Autowired constructor( ) ) } + // 不得切换代码库 + if (GitUtils.diffRepoUrl(record.url, repository.url)) { + logger.warn("can not switch repo url|sourceUrl[${record.url}]|targetUrl[${repository.url}]") + throw OperationException( + MessageUtil.getMessageByLocale( + RepositoryMessageCode.CAN_NOT_SWITCH_REPO_URL, + I18nUtil.getLanguage(userId) + ) + ) + } // 凭证信息 val credentialInfo = checkCredentialInfo(projectId = projectId, repository = repository) val repositoryId = HashUtil.decodeOtherIdToLong(repositoryHashId) diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeP4RepositoryService.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeP4RepositoryService.kt index 5b44c038f65..fa6101ecb5d 100644 --- a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeP4RepositoryService.kt +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeP4RepositoryService.kt @@ -30,8 +30,10 @@ import com.tencent.devops.common.api.constant.CommonMessageCode import com.tencent.devops.common.api.enums.ScmType import com.tencent.devops.common.api.exception.OperationException import com.tencent.devops.common.api.util.HashUtil +import com.tencent.devops.common.api.util.MessageUtil import com.tencent.devops.common.web.utils.I18nUtil import com.tencent.devops.model.repository.tables.records.TRepositoryRecord +import com.tencent.devops.repository.constant.RepositoryMessageCode import com.tencent.devops.repository.constant.RepositoryMessageCode.P4_INVALID import com.tencent.devops.repository.dao.RepositoryCodeP4Dao import com.tencent.devops.repository.dao.RepositoryDao @@ -97,6 +99,16 @@ class CodeP4RepositoryService @Autowired constructor( if (record.type != ScmType.CODE_P4.name) { throw OperationException(I18nUtil.getCodeLanMessage(P4_INVALID)) } + // 不得切换代码库 + if (diffRepoUrl(record, repository)) { + logger.warn("can not switch repo url|sourceUrl[${record.url}]|targetUrl[${repository.url}]") + throw OperationException( + MessageUtil.getMessageByLocale( + RepositoryMessageCode.CAN_NOT_SWITCH_REPO_URL, + I18nUtil.getLanguage(userId) + ) + ) + } // checkCredentialInfo(projectId = projectId, repository = repository) val repositoryId = HashUtil.decodeOtherIdToLong(repositoryHashId) dslContext.transaction { configuration -> @@ -195,6 +207,13 @@ class CodeP4RepositoryService @Autowired constructor( ) } + private fun diffRepoUrl( + sourceRepo: TRepositoryRecord, + targetRepo: CodeP4Repository + ): Boolean { + return sourceRepo.url != targetRepo.url + } + companion object { private val logger = LoggerFactory.getLogger(CodeP4RepositoryService::class.java) } diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeSvnRepositoryService.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeSvnRepositoryService.kt index ac4f31dcbab..d16b4427e4c 100644 --- a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeSvnRepositoryService.kt +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeSvnRepositoryService.kt @@ -31,8 +31,10 @@ import com.tencent.devops.common.api.enums.ScmType import com.tencent.devops.common.api.exception.ErrorCodeException import com.tencent.devops.common.api.exception.OperationException import com.tencent.devops.common.api.util.HashUtil +import com.tencent.devops.common.api.util.MessageUtil import com.tencent.devops.common.web.utils.I18nUtil import com.tencent.devops.model.repository.tables.records.TRepositoryRecord +import com.tencent.devops.repository.constant.RepositoryMessageCode import com.tencent.devops.repository.constant.RepositoryMessageCode.REPO_TYPE_NO_NEED_CERTIFICATION import com.tencent.devops.repository.constant.RepositoryMessageCode.SVN_INVALID import com.tencent.devops.repository.dao.RepositoryCodeSvnDao @@ -107,6 +109,16 @@ class CodeSvnRepositoryService @Autowired constructor( if (!StringUtils.equals(record.type, ScmType.CODE_SVN.name)) { throw OperationException(I18nUtil.getCodeLanMessage(SVN_INVALID)) } + // 不得切换代码库 + if (diffRepoUrl(record, repository)) { + logger.warn("can not switch repo url|sourceUrl[${record.url}]|targetUrl[${repository.url}]") + throw OperationException( + MessageUtil.getMessageByLocale( + RepositoryMessageCode.CAN_NOT_SWITCH_REPO_URL, + I18nUtil.getLanguage(userId) + ) + ) + } val repositoryId = HashUtil.decodeOtherIdToLong(repositoryHashId) checkCredentialInfo(projectId = projectId, repository = repository) dslContext.transaction { configuration -> @@ -246,6 +258,25 @@ class CodeSvnRepositoryService @Autowired constructor( ) } + fun diffRepoUrl( + sourceRepo: TRepositoryRecord, + targetRepo: CodeSvnRepository + ): Boolean { + val sourceRepoUrl = sourceRepo.url + val targetRepoUrl = targetRepo.url + val sourceProjectName = SvnUtils.getSvnProjectName(sourceRepoUrl) + val targetProjectName = SvnUtils.getSvnProjectName(targetRepoUrl) + val targetSubPath = targetRepoUrl.substring( + targetRepoUrl.indexOf(targetRepoUrl) + + targetRepoUrl.length + ) + val sourceSubPath = targetRepoUrl.substring( + targetRepoUrl.indexOf(targetRepoUrl) + + targetRepoUrl.length + ) + return sourceProjectName != targetProjectName || targetSubPath != sourceSubPath + } + companion object { private val logger = LoggerFactory.getLogger(CodeSvnRepositoryService::class.java) } diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeTGitRepositoryService.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeTGitRepositoryService.kt index 86a70df2dd5..f038f3c5e17 100644 --- a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeTGitRepositoryService.kt +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/code/CodeTGitRepositoryService.kt @@ -31,8 +31,10 @@ import com.tencent.devops.common.api.enums.ScmType import com.tencent.devops.common.api.exception.ErrorCodeException import com.tencent.devops.common.api.exception.OperationException import com.tencent.devops.common.api.util.HashUtil +import com.tencent.devops.common.api.util.MessageUtil import com.tencent.devops.common.web.utils.I18nUtil import com.tencent.devops.model.repository.tables.records.TRepositoryRecord +import com.tencent.devops.repository.constant.RepositoryMessageCode import com.tencent.devops.repository.constant.RepositoryMessageCode.REPO_TYPE_NO_NEED_CERTIFICATION import com.tencent.devops.repository.constant.RepositoryMessageCode.TGIT_INVALID import com.tencent.devops.repository.constant.RepositoryMessageCode.USER_SECRET_EMPTY @@ -109,6 +111,16 @@ class CodeTGitRepositoryService @Autowired constructor( if (!StringUtils.equals(record.type, ScmType.CODE_TGIT.name)) { throw OperationException(I18nUtil.getCodeLanMessage(TGIT_INVALID)) } + // 不得切换代码库 + if (GitUtils.diffRepoUrl(record.url, repository.url)) { + logger.warn("can not switch repo url|sourceUrl[${record.url}]|targetUrl[${repository.url}]") + throw OperationException( + MessageUtil.getMessageByLocale( + RepositoryMessageCode.CAN_NOT_SWITCH_REPO_URL, + I18nUtil.getLanguage(userId) + ) + ) + } // 凭证信息 val credentialInfo = checkCredentialInfo(projectId = projectId, repository = repository) val repositoryId = HashUtil.decodeOtherIdToLong(repositoryHashId) @@ -246,6 +258,16 @@ class CodeTGitRepositoryService @Autowired constructor( logger.warn("Fail to check the repo token & private key because of ${checkResult.message}") throw OperationException(checkResult.message) } + // 授权凭证信息 + if (repoCredentialInfo.credentialType == CredentialType.USERNAME_PASSWORD.name) { + logger.info("using credential of type [USERNAME_PASSWORD],loginUser[${repoCredentialInfo.username}]") + repoCredentialInfo.token = scmService.getGitSession( + type = ScmType.CODE_TGIT, + username = repoCredentialInfo.username, + password = repoCredentialInfo.password, + url = repository.url + )?.privateToken ?: "" + } } return repoCredentialInfo } 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 e895af11712..0879cbe5c24 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 @@ -61,11 +61,18 @@ class GithubOAuthService @Autowired constructor( private val githubUserService: GithubUserService ) { - fun getGithubOauth(projectId: String, userId: String, repoHashId: String?): GithubOauth { + fun getGithubOauth( + projectId: String, + userId: String, + repoHashId: String?, + popupTag: String? = "#popupGithub", + resetType: String? = "" + ): GithubOauth { val repoId = if (!repoHashId.isNullOrBlank()) HashUtil.decodeOtherIdToLong(repoHashId).toString() else "" - val state = "$userId,$projectId,$repoId,BK_DEVOPS__${RandomStringUtils.randomAlphanumeric(RANDOM_ALPHA_NUM)}" + val state = "$userId,$projectId,$repoId,BK_DEVOPS__${RandomStringUtils.randomAlphanumeric(RANDOM_ALPHA_NUM)}," + + "$popupTag,$resetType" val redirectUrl = "$GITHUB_URL/login/oauth/authorize" + - "?client_id=${gitConfig.githubClientId}&redirect_uri=${gitConfig.githubWebhookUrl}&state=$state" + "?client_id=${gitConfig.githubClientId}&redirect_uri=${gitConfig.githubCallbackUrl}&state=$state" return GithubOauth(redirectUrl) } @@ -114,13 +121,18 @@ class GithubOAuthService @Autowired constructor( if (state.isNullOrBlank() || !state.contains(",BK_DEVOPS__")) { throw OperationException("TGIT call back contain invalid parameter: $state") } - + // 回调状态信息 + // @see com.tencent.devops.repository.service.github.GithubOAuthService.getGithubOauth + // 格式:{{授权用户Id}},{{蓝盾项目Id}},{{蓝盾代码库Id}},{{回调标识}},{{弹框标识位}},{{重置类型}} val arrays = state.split(",") val userId = arrays[0] val projectId = arrays[1] val repoHashId = if (arrays[2].isNotBlank()) HashUtil.encodeOtherLongId(arrays[2].toLong()) else "" val githubToken = getAccessTokenImpl(code, githubTokenType) - + // 弹框标志位 + val popupTag = arrays.getOrNull(4) ?: "" + // 重置类型 + val resetType = arrays.getOrNull(5) ?: "" githubTokenService.createAccessToken( userId = userId, accessToken = githubToken.accessToken, @@ -130,7 +142,8 @@ class GithubOAuthService @Autowired constructor( ) return GithubOauthCallback( userId = userId, - redirectUrl = "${gitConfig.githubRedirectUrl}/$projectId#popupGithub$repoHashId" + redirectUrl = "${gitConfig.githubRedirectUrl}/$projectId$popupTag$repoHashId?" + + "resetType=$resetType&userId=$userId" ) } diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/github/GithubService.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/github/GithubService.kt index dc142ea2343..ad27c580582 100644 --- a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/github/GithubService.kt +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/github/GithubService.kt @@ -52,6 +52,7 @@ import com.tencent.devops.repository.constant.RepositoryMessageCode.OPERATION_LI import com.tencent.devops.repository.constant.RepositoryMessageCode.OPERATION_LIST_TAGS import com.tencent.devops.repository.constant.RepositoryMessageCode.OPERATION_UPDATE_CHECK_RUNS import com.tencent.devops.repository.github.service.GithubRepositoryService +import com.tencent.devops.repository.github.service.GithubUserService import com.tencent.devops.repository.pojo.AuthorizeResult import com.tencent.devops.repository.pojo.GithubCheckRuns import com.tencent.devops.repository.pojo.GithubCheckRunsResponse @@ -81,6 +82,7 @@ class GithubService @Autowired constructor( private val githubTokenService: GithubTokenService, private val githubOAuthService: GithubOAuthService, private val githubRepositoryService: GithubRepositoryService, + private val githubUserService: GithubUserService, private val objectMapper: ObjectMapper, private val gitConfig: GitConfig, private val client: Client @@ -388,6 +390,46 @@ class GithubService @Autowired constructor( ) } + override fun isOAuth( + userId: String, + projectId: String, + refreshToken: Boolean?, + resetType: String? + ): AuthorizeResult { + logger.info("isOAuth userId is: $userId,refreshToken is: $refreshToken") + val accessToken = if (refreshToken == true) { + null + } else { + githubTokenService.getAccessToken(userId) + } ?: return AuthorizeResult( + status = HTTP_403, + url = githubOAuthService.getGithubOauth( + projectId = projectId, + userId = userId, + repoHashId = null, + popupTag = "", + resetType = resetType + ).redirectUrl + ) + // 校验token是否有效 + try { + githubUserService.getUser(accessToken.accessToken) + } catch (e: Exception) { + return AuthorizeResult( + status = HTTP_403, + url = githubOAuthService.getGithubOauth( + projectId = projectId, + userId = userId, + repoHashId = null, + popupTag = "", + resetType = resetType + ).redirectUrl + ) + } + logger.info("github isOAuth accessToken is: $accessToken") + return AuthorizeResult(200, "") + } + companion object { private val logger = LoggerFactory.getLogger(GithubService::class.java) private const val PAGE_SIZE = 100 diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/github/IGithubService.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/github/IGithubService.kt index f7c7116651c..6fc85010310 100644 --- a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/github/IGithubService.kt +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/github/IGithubService.kt @@ -61,4 +61,11 @@ interface IGithubService { fun listBranches(token: String, projectName: String): List fun listTags(token: String, projectName: String): List + + fun isOAuth( + userId: String, + projectId: String, + refreshToken: Boolean?, + resetType: String? + ): AuthorizeResult } 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 bb562878962..fb5ce5bc107 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 @@ -153,7 +153,8 @@ class GitOauthService @Autowired constructor( redirectUrlType: RedirectUrlTypeEnum?, redirectUrl: String?, gitProjectId: Long?, - refreshToken: Boolean? + refreshToken: Boolean?, + resetType: String? ): AuthorizeResult { logger.info("isOAuth userId is: $userId,redirectUrlType is: $redirectUrlType") if (redirectUrlType == RedirectUrlTypeEnum.SPEC) { @@ -169,7 +170,8 @@ class GitOauthService @Autowired constructor( "userId" to userId, "redirectUrlType" to redirectUrlType?.type, "redirectUrl" to redirectUrl, - "randomStr" to "BK_DEVOPS__${RandomStringUtils.randomAlphanumeric(8)}" + "randomStr" to "BK_DEVOPS__${RandomStringUtils.randomAlphanumeric(8)}", + "resetType" to resetType ) val accessToken = if (refreshToken == true) { null @@ -177,6 +179,13 @@ class GitOauthService @Autowired constructor( getAccessToken(userId) } ?: return AuthorizeResult(403, getAuthUrl(authParams)) logger.info("isOAuth accessToken is: $accessToken") + // 检查accessToken 是否可用 + try { + gitService.getUserInfoByToken(accessToken.accessToken) + } catch (e: Exception) { + logger.info("get oauth project fail: ${e.message}") + return AuthorizeResult(403, getAuthUrl(authParams)) + } return AuthorizeResult(200, "") } diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/scm/GitService.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/scm/GitService.kt index 68728412804..f8687325968 100644 --- a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/scm/GitService.kt +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/scm/GitService.kt @@ -457,9 +457,15 @@ class GitService @Autowired constructor( val authParams = JsonUtil.toMap(authParamDecodeJsonStr) val type = authParams["redirectUrlType"] as? String val specRedirectUrl = authParams["redirectUrl"] as? String + val resetType = (authParams["resetType"] as? String) ?: "" + val queryParam = if (resetType.isNotBlank()) { + "resetType=$resetType" + } else { + "" + } return when (RedirectUrlTypeEnum.getRedirectUrlType(type ?: "")) { RedirectUrlTypeEnum.SPEC -> specRedirectUrl!! - RedirectUrlTypeEnum.DEFAULT -> redirectUrl + RedirectUrlTypeEnum.DEFAULT -> "$redirectUrl?$queryParam" else -> { val projectId = authParams["projectId"] as String val repoId = authParams["repoId"] as String 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 a5767459e2a..f6ce37f64b3 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 @@ -46,7 +46,8 @@ interface IGitOauthService { redirectUrlType: RedirectUrlTypeEnum?, redirectUrl: String? = null, gitProjectId: Long? = null, - refreshToken: Boolean? = false + refreshToken: Boolean? = false, + resetType: String? = "" ): AuthorizeResult fun gitCallback(code: String, state: String): GitOauthCallback fun checkAndGetAccessToken(projectId: String, buildId: String, userId: String): GitToken? diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/scm/IScmService.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/scm/IScmService.kt index fb0aa0ef4da..7cec24df53b 100644 --- a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/scm/IScmService.kt +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/scm/IScmService.kt @@ -37,6 +37,7 @@ import com.tencent.devops.scm.pojo.GitMrChangeInfo import com.tencent.devops.scm.pojo.GitMrInfo import com.tencent.devops.scm.pojo.GitMrReviewInfo import com.tencent.devops.scm.pojo.GitProjectInfo +import com.tencent.devops.scm.pojo.GitSession import com.tencent.devops.scm.pojo.RevisionInfo import com.tencent.devops.scm.pojo.TokenCheckResult @@ -238,4 +239,14 @@ interface IScmService { token: String?, crId: Long ): GitCommitReviewInfo? + + /** + * 读取会话信息 + */ + fun getGitSession( + type: ScmType, + username: String, + password: String, + url: String + ): GitSession? } diff --git a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/scm/ScmService.kt b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/scm/ScmService.kt index 6a019f3b82b..2ab45b13ed4 100644 --- a/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/scm/ScmService.kt +++ b/src/backend/ci/core/repository/biz-repository/src/main/kotlin/com/tencent/devops/repository/service/scm/ScmService.kt @@ -44,6 +44,7 @@ import com.tencent.devops.scm.pojo.GitMrChangeInfo import com.tencent.devops.scm.pojo.GitMrInfo import com.tencent.devops.scm.pojo.GitMrReviewInfo import com.tencent.devops.scm.pojo.GitProjectInfo +import com.tencent.devops.scm.pojo.GitSession import com.tencent.devops.scm.pojo.RevisionInfo import com.tencent.devops.scm.pojo.TokenCheckResult import com.tencent.devops.scm.utils.code.svn.SvnUtils @@ -604,6 +605,25 @@ class ScmService @Autowired constructor( ).getCommitReviewInfo(crId = crId) } + override fun getGitSession( + type: ScmType, + username: String, + password: String, + url: String + ): GitSession? { + return ScmFactory.getScm( + projectName = "", + url = url, + type = type, + branchName = null, + privateKey = username, + passPhrase = password, + token = "", + region = null, + userName = null + ).getGitSession() + } + companion object { private val logger = LoggerFactory.getLogger(ScmService::class.java) } diff --git a/support-files/i18n/repository/message_en_US.properties b/support-files/i18n/repository/message_en_US.properties index 8909c849d9c..047107f4dc3 100644 --- a/support-files/i18n/repository/message_en_US.properties +++ b/support-files/i18n/repository/message_en_US.properties @@ -24,6 +24,7 @@ 2115024=Warehouse ID and warehouse name are empty 2115025=User ({0}) does not have ({1}) project permissions 2115026=The user [{0}] has not been authorized by OAUTH, please authorize it first. +2115027=Cannot switch repository url bkRequestFileSizeLimit=The request file cannot exceed 1m OperationAddCheckRuns=Add a detection task OperationUpdateCheckRuns=Update the detection task diff --git a/support-files/i18n/repository/message_zh_CN.properties b/support-files/i18n/repository/message_zh_CN.properties index 99ef362b9f0..faf53cc90a8 100644 --- a/support-files/i18n/repository/message_zh_CN.properties +++ b/support-files/i18n/repository/message_zh_CN.properties @@ -24,6 +24,7 @@ 2115024=仓库ID和仓库名都为空 2115025=用户({0})无({1})项目权限 2115026=用户[{0}]尚未进行OAUTH授权,请先授权。 +2115027=不可切换代码库地址 bkRequestFileSizeLimit=请求文件不能超过1M OperationAddCheckRuns=添加检测任务 OperationUpdateCheckRuns=更新检测任务