Skip to content

Commit

Permalink
Merge pull request #10099 from hejieehe/bug_10096
Browse files Browse the repository at this point in the history
bug: 定时触发插件检查SVN代码库最新版本时, 无需调用会话接口 #10096
  • Loading branch information
mingshewhe authored Mar 14, 2024
2 parents 94c7d4a + da7b114 commit eb38d96
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@

package com.tencent.devops.process.utils

import com.tencent.devops.common.api.util.DHUtil
import com.tencent.devops.repository.pojo.CodeP4Repository
import com.tencent.devops.repository.pojo.CodeSvnRepository
import com.tencent.devops.repository.pojo.Repository
import com.tencent.devops.ticket.pojo.enums.CredentialType
import org.slf4j.LoggerFactory
import java.util.Base64

@Suppress("ALL")
object CredentialUtils {
Expand All @@ -40,19 +42,42 @@ object CredentialUtils {
when {
repository is CodeSvnRepository && repository.svnType == CodeSvnRepository.SVN_TYPE_HTTP -> {
// 兼容老的数据,老的数据是用的是password, 新的是username_password
return if (credentialType == CredentialType.USERNAME_PASSWORD) {
if (credentials.size <= 1) {
logger.warn("Fail to get the username($credentials) of the svn repo $repository")
return when (credentialType) {
CredentialType.USERNAME_PASSWORD -> {
if (credentials.size <= 1) {
logger.warn("Fail to get the username($credentials) of the svn repo $repository")
Credential(username = repository.userName, privateKey = credentials[0], passPhrase = null)
} else {
Credential(username = credentials[0], privateKey = credentials[1], passPhrase = null)
}
}

CredentialType.TOKEN_USERNAME_PASSWORD -> {
Credential(
svnToken = credentials[0],
username = credentials.getOrElse(1) { "" },
privateKey = credentials.getOrElse(2) { "" },
passPhrase = null
)
}

else -> {
Credential(username = repository.userName, privateKey = credentials[0], passPhrase = null)
} else {
Credential(username = credentials[0], privateKey = credentials[1], passPhrase = null)
}
} else {
Credential(username = repository.userName, privateKey = credentials[0], passPhrase = null)
}
}

repository is CodeSvnRepository && credentialType == CredentialType.TOKEN_SSH_PRIVATEKEY ->
return Credential(
svnToken = credentials[0],
privateKey = credentials.getOrElse(1) { "" },
username = repository.userName,
passPhrase = credentials.getOrElse(2) { "" }
)

repository is CodeP4Repository && credentialType == CredentialType.USERNAME_PASSWORD ->
return Credential(username = credentials[0], privateKey = "", passPhrase = credentials[1])

else -> {
val privateKey = credentials[0]
val passPhrase = if (credentials.size > 1) {
Expand All @@ -70,12 +95,25 @@ object CredentialUtils {
}
}

fun decode(encode: String?, publicKey: String, privateKey: ByteArray): String {
if (encode.isNullOrBlank()) return ""
val decoder = Base64.getDecoder()
return String(
DHUtil.decrypt(
decoder.decode(encode),
decoder.decode(publicKey),
privateKey
)
)
}

private val logger = LoggerFactory.getLogger(CredentialUtils::class.java)
}

data class Credential(
val username: String,
val privateKey: String, // password or private key
val passPhrase: String?, // passphrase for ssh private key
val svnToken: String? = "",
var credentialType: CredentialType? = null
)
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,11 @@ class ScmProxyService @Autowired constructor(private val client: Client) {
userName = repo.userName
)
} else {
val credInfo = getCredential(projectId, repo)
val credInfo = getCredential(
projectId = projectId,
repository = repo,
getSession = true
)
client.get(ServiceScmResource::class).getLatestRevision(
projectName = repo.projectName,
url = repo.url,
Expand Down Expand Up @@ -257,7 +261,11 @@ class ScmProxyService @Autowired constructor(private val client: Client) {
search = search
)
} else {
val credInfo = getCredential(projectId, repo)
val credInfo = getCredential(
projectId = projectId,
repository = repo,
getSession = true
)
client.get(ServiceScmResource::class).listBranches(
projectName = repo.projectName,
url = repo.url,
Expand Down Expand Up @@ -306,7 +314,11 @@ class ScmProxyService @Autowired constructor(private val client: Client) {
search = search
)
} else {
val credInfo = getCredential(projectId, repo)
val credInfo = getCredential(
projectId = projectId,
repository = repo,
getSession = true
)
client.get(ServiceScmResource::class).listBranches(
projectName = repo.projectName,
url = repo.url,
Expand Down Expand Up @@ -350,7 +362,11 @@ class ScmProxyService @Autowired constructor(private val client: Client) {
search = search
)
} else {
val credInfo = getCredential(projectId, repo)
val credInfo = getCredential(
projectId = projectId,
repository = repo,
getSession = true
)
client.get(ServiceScmResource::class).listTags(
projectName = repo.projectName,
url = repo.url,
Expand Down Expand Up @@ -390,7 +406,11 @@ class ScmProxyService @Autowired constructor(private val client: Client) {
search = search
)
} else {
val credInfo = getCredential(projectId, repo)
val credInfo = getCredential(
projectId = projectId,
repository = repo,
getSession = true
)
client.get(ServiceScmResource::class).listTags(
projectName = repo.projectName,
url = repo.url,
Expand Down Expand Up @@ -419,7 +439,11 @@ class ScmProxyService @Autowired constructor(private val client: Client) {
val token = if (isOauth) {
getAccessToken(repo.userName).first
} else {
getCredential(projectId, repo).privateKey
getCredential(
projectId = projectId,
repository = repo,
getSession = true
).privateKey
}
val event = convertEvent(codeEventType)

Expand Down Expand Up @@ -480,7 +504,11 @@ class ScmProxyService @Autowired constructor(private val client: Client) {
checkRepoID(repositoryConfig)
val repo = getRepo(projectId, repositoryConfig) as? CodeSvnRepository
?: throw ErrorCodeException(errorCode = ProcessMessageCode.SVN_INVALID)
val credential = getCredential(projectId, repo)
val credential = getCredential(
projectId = projectId,
repository = repo,
getSession = true
)
val (isOauth, token) = getSvnToken(credential, repo.svnType, repo.userName)
if (isOauth) {
client.get(ServiceScmOauthResource::class).addWebHook(
Expand Down Expand Up @@ -532,7 +560,11 @@ class ScmProxyService @Autowired constructor(private val client: Client) {
event = convertEvent(codeEventType)
)
} else {
val credInfo = getCredential(projectId, repo)
val credInfo = getCredential(
projectId = projectId,
repository = repo,
getSession = true
)
client.get(ServiceScmResource::class).addWebHook(
projectName = repo.projectName,
url = repo.url,
Expand Down Expand Up @@ -689,11 +721,14 @@ class ScmProxyService @Autowired constructor(private val client: Client) {
return repoResult.data!!
}

private fun getCredential(projectId: String, repository: Repository): Credential {
private fun getCredential(
projectId: String,
repository: Repository,
getSession: Boolean = false
): Credential {
val credentialId = repository.credentialId
val pair = DHUtil.initKey()
val encoder = Base64.getEncoder()
val decoder = Base64.getDecoder()
val credentialResult = client.get(ServiceCredentialResource::class).get(
projectId, credentialId,
encoder.encodeToString(pair.publicKey)
Expand All @@ -706,32 +741,31 @@ class ScmProxyService @Autowired constructor(private val client: Client) {
}

val credential = credentialResult.data!!

val privateKey = String(
DHUtil.decrypt(
decoder.decode(credential.v1),
decoder.decode(credential.publicKey),
pair.privateKey
)
// 凭证字段定义: com.tencent.devops.ticket.pojo.enums.CredentialType
val v1 = CredentialUtils.decode(
encode = credential.v1,
publicKey = credential.publicKey,
privateKey = pair.privateKey
)

val passPhrase = if (credential.v2.isNullOrBlank()) "" else String(
DHUtil.decrypt(
decoder.decode(credential.v2),
decoder.decode(credential.publicKey),
pair.privateKey
)
val v2 = CredentialUtils.decode(
encode = credential.v2,
publicKey = credential.publicKey,
privateKey = pair.privateKey
)

// username+password 关联的git代码库
if (tryGetSession(repository, credential.credentialType)) {
val v3 = CredentialUtils.decode(
encode = credential.v3,
publicKey = credential.publicKey,
privateKey = pair.privateKey
)
// 尝试获取token
if (getSession && tryGetSession(repository, credential.credentialType)) {
// USERNAME_PASSWORD v1 = username, v2 = password
val session = try {
client.get(ServiceScmResource::class).getLoginSession(
RepoSessionRequest(
type = repository.getScmType(),
username = privateKey,
password = passPhrase,
username = v1,
password = v2,
url = repository.url
)
).data
Expand All @@ -740,16 +774,17 @@ class ScmProxyService @Autowired constructor(private val client: Client) {
null
}
return Credential(
username = privateKey,
username = v1,
privateKey = session?.privateToken ?: "",
passPhrase = passPhrase
passPhrase = v2,
svnToken = session?.privateToken ?: ""
)
}

val list = if (passPhrase.isBlank()) {
listOf(privateKey)
} else {
listOf(privateKey, passPhrase)
// 按顺序封装凭证信息
val list = when {
v2.isBlank() -> listOf(v1)
v3.isBlank() -> listOf(v1, v2)
else -> listOf(v1, v2, v3)
}
return CredentialUtils.getCredential(repository, list, credential.credentialType).apply {
this.credentialType = credential.credentialType
Expand Down Expand Up @@ -778,7 +813,7 @@ class ScmProxyService @Autowired constructor(private val client: Client) {
CodeSvnRepository.SVN_TYPE_SSH -> {
// 凭证中存在token,则直接使用
if (credential.credentialType == CredentialType.TOKEN_SSH_PRIVATEKEY) {
Pair(false, credential.privateKey)
Pair(false, credential.svnToken ?: "")
} else {
// 兜底,以当前代码关联人的oauthToken去操作
try {
Expand All @@ -794,10 +829,10 @@ class ScmProxyService @Autowired constructor(private val client: Client) {
}
}
CodeSvnRepository.SVN_TYPE_HTTP -> {
// 凭证中存在token,则直接使用,反之用session接口返回值,此处privateKey是svn的token
// 凭证中存在token,则直接使用,反之用session接口返回值,此处svnToken是svn的token
// 参考:1. com.tencent.devops.process.utils.CredentialUtils.getCredential
// 2. com.tencent.devops.process.service.scm.ScmProxyService.getCredential
Pair(false, credential.privateKey)
Pair(false, credential.svnToken ?: "")
}
else -> {
Pair(false, "")
Expand Down

0 comments on commit eb38d96

Please sign in to comment.