Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
package com.tencent.devops.environment.pojo

import com.tencent.devops.environment.pojo.thirdpartyagent.AgentBuildDetail
import com.tencent.devops.environment.pojo.thirdpartyagent.create.AgentPropsSource
import io.swagger.v3.oas.annotations.media.Schema

@Schema(title = "NodeWithPermission-节点信息(权限)")
Expand Down Expand Up @@ -104,6 +105,8 @@ data class NodeWithPermission(
val envEnableNode: Boolean?,
@get:Schema(title = "创作环境,工作空间id", required = false)
val createWorkspaceId: String?,
@get:Schema(title = "创作环境,工作空间来源", required = false)
val createWorkspaceSource: AgentPropsSource?,
@get:Schema(
title = "操作人状态:NORMAL 表示操作人正常 / OPERATOR_CHANGED 表示负责人已变更(禁止使用);可为NULL,为NULL表示未计算。" +
"只有nodeType为CMDB的时候,此字段不为空。判断CMDB节点是否责任人变更,条件为 " +
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.tencent.devops.environment.pojo.thirdpartyagent.create

enum class AgentPropsSource {
REMOTEDEV, // 普通的云桌面
DEVCLOUD, // TEG iMate Linux
IEG_IMATE // IEG iMate 的 linux/windows 云桌面
;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.tencent.devops.environment.model

import com.tencent.devops.common.api.pojo.agent.DockerInitFileInfo
import com.tencent.devops.common.api.pojo.OS
import com.tencent.devops.common.api.pojo.agent.AgentErrorExitData
import com.tencent.devops.common.api.pojo.agent.DockerInitFileInfo
import com.tencent.devops.common.api.util.JsonUtil
import com.tencent.devops.environment.pojo.thirdpartyagent.create.AgentPropsSource

/**
* Agent 系统属性
Expand Down Expand Up @@ -31,11 +34,24 @@ data class AgentProps(
osVersion = null,
source = source
)
}
}

enum class AgentPropsSource {
REMOTEDEV, // 云桌面
DEVCLOUD, // 团队imate龙虾
;
fun getSourceFromRecord(props: String?, os: OS?): AgentPropsSource {
val source = if (props == null) {
null
} else {
try {
JsonUtil.to<AgentProps>(props).source
} catch (_: Exception) {
null
}
}
if (source == AgentPropsSource.DEVCLOUD || (source == null && os == OS.LINUX)) {
return AgentPropsSource.DEVCLOUD
}
if (source == AgentPropsSource.REMOTEDEV || (source == null && os == OS.WINDOWS)) {
return AgentPropsSource.REMOTEDEV
}
return AgentPropsSource.IEG_IMATE
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ abstract class AbstractEnvironmentPermissionService constructor(
)
}

override fun listNodeByRbacPermission(
override fun listNodePermission(
userId: String,
projectId: String,
nodeRecordList: List<TNodeRecord>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ interface EnvironmentPermissionService {
resourceType: AuthResourceType = AuthResourceType.ENVIRONMENT_ENV_NODE
): Map<AuthPermission, List<String>>

fun listNodeByRbacPermission(
fun listNodePermission(
userId: String,
projectId: String,
nodeRecordList: List<TNodeRecord>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,16 @@ import com.tencent.devops.common.auth.rbac.utils.RbacAuthUtils
import com.tencent.devops.common.auth.utils.AuthCacheKeyUtil
import com.tencent.devops.common.client.Client
import com.tencent.devops.common.client.ClientTokenService
import com.tencent.devops.common.pipeline.enums.ChannelCode
import com.tencent.devops.environment.permission.creativestream.CreativeStreamNodePermissionHandler
import com.tencent.devops.model.environment.tables.records.TEnvRecord
import com.tencent.devops.model.environment.tables.records.TNodeRecord
import org.slf4j.LoggerFactory

class RbacEnvironmentPermissionService(
private val client: Client,
private val tokenCheckService: ClientTokenService
private val tokenCheckService: ClientTokenService,
private val creativeStreamNodePermissionHandler: CreativeStreamNodePermissionHandler
) : EnvironmentPermissionService {
val envResourceType = AuthResourceType.ENVIRONMENT_ENVIRONMENT.value
val nodeResourceType = AuthResourceType.ENVIRONMENT_ENV_NODE.value
Expand Down Expand Up @@ -174,13 +177,22 @@ class RbacEnvironmentPermissionService(
permission: AuthPermission,
resourceType: AuthResourceType
): Set<Long> {
return client.get(ServicePermissionAuthResource::class).getUserResourceByPermission(
token = tokenCheckService.getSystemToken()!!,
userId = userId,
action = buildNodeAction(permission, resourceType),
projectCode = projectId,
resourceType = resourceType.value
).data?.map { HashUtil.decodeIdToLong(it) }?.toSet() ?: emptySet()
val channel = ChannelCode.getRequestChannelCode()
return if (channel == ChannelCode.CREATIVE_STREAM || resourceType == AuthResourceType.CREATIVE_STREAM) {
creativeStreamNodePermissionHandler.listNodePermissions(
userId = userId,
projectId = projectId,
permissions = setOf(permission)
)[permission] ?: emptySet()
} else {
client.get(ServicePermissionAuthResource::class).getUserResourceByPermission(
token = tokenCheckService.getSystemToken()!!,
userId = userId,
action = buildNodeAction(permission, resourceType),
projectCode = projectId,
resourceType = resourceType.value
).data?.map { HashUtil.decodeIdToLong(it) }?.toSet() ?: emptySet()
}
}

override fun listNodeByPermissions(
Expand All @@ -189,6 +201,15 @@ class RbacEnvironmentPermissionService(
permissions: Set<AuthPermission>,
resourceType: AuthResourceType
): Map<AuthPermission, List<String>> {
if (ChannelCode.getRequestChannelCode() == ChannelCode.CREATIVE_STREAM ||
resourceType == AuthResourceType.CREATIVE_STREAM
) {
return creativeStreamNodePermissionHandler.listNodePermissions(
userId = userId,
projectId = projectId,
permissions = permissions
).mapValues { (_, ids) -> ids.map(HashUtil::encodeLongId) }
}
return client.get(ServicePermissionAuthResource::class).getUserResourcesByPermissions(
token = tokenCheckService.getSystemToken()!!,
userId = userId,
Expand All @@ -198,13 +219,24 @@ class RbacEnvironmentPermissionService(
).data ?: emptyMap()
}

override fun listNodeByRbacPermission(
override fun listNodePermission(
userId: String,
projectId: String,
nodeRecordList: List<TNodeRecord>,
authPermission: AuthPermission,
resourceType: AuthResourceType
): List<TNodeRecord> {
if (ChannelCode.getRequestChannelCode() == ChannelCode.CREATIVE_STREAM ||
resourceType == AuthResourceType.CREATIVE_STREAM
) {
val permissionNodeIds = creativeStreamNodePermissionHandler.listNodePermissions(
userId = userId,
projectId = projectId,
nodeIds = nodeRecordList.map { it.nodeId },
permissions = setOf(authPermission)
)[authPermission] ?: emptySet()
return nodeRecordList.filter { it.nodeId in permissionNodeIds }
}
val hasRbacPermissionNodeIds = listNodeByPermission(
userId, projectId, authPermission, resourceType
)
Expand All @@ -221,6 +253,16 @@ class RbacEnvironmentPermissionService(
permission: AuthPermission,
resourceType: AuthResourceType
): Boolean {
if (ChannelCode.getRequestChannelCode() == ChannelCode.CREATIVE_STREAM ||
resourceType == AuthResourceType.CREATIVE_STREAM
) {
return creativeStreamNodePermissionHandler.checkPermission(
userId = userId,
projectId = projectId,
nodeId = nodeId,
permission = permission
)
}
val cacheKey = AuthCacheKeyUtil.getCacheKey(
userId = userId,
resourceType = resourceType.value,
Expand Down Expand Up @@ -248,6 +290,12 @@ class RbacEnvironmentPermissionService(
permission: AuthPermission,
resourceType: AuthResourceType
): Boolean {
if ((ChannelCode.getRequestChannelCode() == ChannelCode.CREATIVE_STREAM ||
resourceType == AuthResourceType.CREATIVE_STREAM) &&
permission == AuthPermission.CREATE
) {
return true
}
val cacheKey = AuthCacheKeyUtil.getCacheKey(
userId = userId,
resourceType = AuthResourceType.PROJECT.value,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ class StreamEnvironmentPermissionServiceImp @Autowired constructor(
return resultMap
}

override fun listNodeByRbacPermission(
override fun listNodePermission(
userId: String,
projectId: String,
nodeRecordList: List<TNodeRecord>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import com.tencent.devops.environment.permission.EnvironmentPermissionService
import com.tencent.devops.environment.permission.MockEnvironmentPermissionService
import com.tencent.devops.environment.permission.RbacEnvironmentPermissionService
import com.tencent.devops.environment.permission.StreamEnvironmentPermissionServiceImp
import com.tencent.devops.environment.permission.creativestream.CreativeStreamNodePermissionHandler
import org.jooq.DSLContext
import org.springframework.boot.autoconfigure.AutoConfigureOrder
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
Expand Down Expand Up @@ -106,9 +107,11 @@ class EnvironmentPermConfiguration {
@ConditionalOnProperty(prefix = "auth", name = ["idProvider"], havingValue = "rbac")
fun rbacEnvironmentPermissionService(
client: Client,
tokenCheckService: ClientTokenService
tokenCheckService: ClientTokenService,
creativeStreamNodePermissionHandler: CreativeStreamNodePermissionHandler
): EnvironmentPermissionService = RbacEnvironmentPermissionService(
client = client,
tokenCheckService = tokenCheckService
tokenCheckService = tokenCheckService,
creativeStreamNodePermissionHandler = creativeStreamNodePermissionHandler
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available.
*
* Copyright (C) 2019 Tencent. 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.environment.permission.creativestream

import com.tencent.devops.common.auth.api.AuthPermission
import com.tencent.devops.environment.dao.NodeDao
import com.tencent.devops.environment.pojo.enums.NodeType
import org.jooq.DSLContext
import org.springframework.stereotype.Component

@Component
class CreativeStreamNodePermissionHandler(
private val dslContext: DSLContext,
private val nodeDao: NodeDao,
strategies: List<CreativeStreamNodePermissionStrategy>
) {
private val strategies = strategies.sortedBy { it.order }

fun listNodePermissions(
userId: String,
projectId: String,
nodeIds: Collection<Long>? = null,
permissions: Set<AuthPermission>
): Map<AuthPermission, Set<Long>> {
val permissionNodeIds = permissions.associateWith { mutableSetOf<Long>() }
val candidateNodeIds = nodeIds ?: nodeDao.listNodes(
dslContext = dslContext,
projectId = projectId,
nodeType = NodeType.CREATE
).map { it.nodeId }
if (candidateNodeIds.isEmpty()) {
return permissionNodeIds
}
// 先批量预取一次节点数据,避免后续逐节点重复查询。
strategies.forEach { it.prefetch(projectId, candidateNodeIds) }
candidateNodeIds.forEach { nodeId ->
// supports 与权限无关,每个节点只解析一次策略,再对多个权限复用。
val strategy = strategies.firstOrNull { it.supports(projectId, nodeId) } ?: return@forEach
permissions.forEach { permission ->
if (strategy.checkPermission(userId, projectId, nodeId, permission)) {
permissionNodeIds.getValue(permission).add(nodeId)
}
}
}
return permissionNodeIds
}

fun checkPermission(
userId: String,
projectId: String,
nodeId: Long,
permission: AuthPermission
): Boolean {
val strategy = strategies.firstOrNull { it.supports(projectId, nodeId) } ?: return false
return strategy.checkPermission(
userId = userId,
projectId = projectId,
nodeId = nodeId,
permission = permission
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Tencent is pleased to support the open source community by making BK-CI 蓝鲸持续集成平台 available.
*
* Copyright (C) 2019 Tencent. 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.environment.permission.creativestream

import com.tencent.devops.common.auth.api.AuthPermission

interface CreativeStreamNodePermissionStrategy {
val order: Int

fun supports(projectId: String, nodeId: Long): Boolean

fun checkPermission(
userId: String,
projectId: String,
nodeId: Long,
permission: AuthPermission
): Boolean

/**
* 批量场景下预热策略所需的节点数据,避免逐节点重复查询。默认不做任何事。
*/
fun prefetch(projectId: String, nodeIds: Collection<Long>) = Unit
}
Loading
Loading