Skip to content

Commit

Permalink
feat: 支持NodeList接口过滤无权限路径 TencentBlueKing#1585
Browse files Browse the repository at this point in the history
  • Loading branch information
cnlkl committed Jan 3, 2024
1 parent 3fbcac1 commit 0f47f4a
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ package com.tencent.bkrepo.repository.pojo.node

import com.tencent.bkrepo.common.api.constant.DEFAULT_PAGE_NUMBER
import com.tencent.bkrepo.common.api.constant.DEFAULT_PAGE_SIZE
import com.tencent.bkrepo.repository.constant.SYSTEM_USER
import io.swagger.annotations.ApiModel
import io.swagger.annotations.ApiModelProperty

Expand All @@ -53,5 +54,9 @@ data class NodeListOption(
@ApiModelProperty("排序字段")
val sortProperty: List<String> = emptyList(),
@ApiModelProperty("排序方向")
val direction: List<String> = emptyList()
val direction: List<String> = emptyList(),
@ApiModelProperty("无权限路径")
var noPermissionPath: List<String> = emptyList(),
@ApiModelProperty("操作用户")
var operator: String = SYSTEM_USER,
)
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

package com.tencent.bkrepo.repository.service.node.impl

import com.tencent.bkrepo.auth.api.ServicePermissionClient
import com.tencent.bkrepo.auth.pojo.enums.PermissionAction
import com.tencent.bkrepo.common.api.exception.BadRequestException
import com.tencent.bkrepo.common.api.exception.ErrorCodeException
Expand All @@ -41,15 +42,18 @@ import com.tencent.bkrepo.common.artifact.path.PathUtils
import com.tencent.bkrepo.common.artifact.pojo.RepositoryType
import com.tencent.bkrepo.common.mongo.dao.AbstractMongoDao.Companion.ID
import com.tencent.bkrepo.common.mongo.dao.util.Pages
import com.tencent.bkrepo.common.query.enums.OperationType
import com.tencent.bkrepo.common.query.model.Sort
import com.tencent.bkrepo.common.security.manager.PermissionManager
import com.tencent.bkrepo.common.security.util.SecurityUtils
import com.tencent.bkrepo.common.service.util.SpringContextUtils.Companion.publishEvent
import com.tencent.bkrepo.common.storage.core.StorageService
import com.tencent.bkrepo.common.stream.constant.BinderType
import com.tencent.bkrepo.common.stream.event.supplier.MessageSupplier
import com.tencent.bkrepo.fs.server.constant.FAKE_MD5
import com.tencent.bkrepo.fs.server.constant.FAKE_SHA256
import com.tencent.bkrepo.repository.config.RepositoryProperties
import com.tencent.bkrepo.repository.constant.SYSTEM_USER
import com.tencent.bkrepo.repository.dao.NodeDao
import com.tencent.bkrepo.repository.dao.RepositoryDao
import com.tencent.bkrepo.repository.model.TNode
Expand Down Expand Up @@ -96,6 +100,7 @@ abstract class NodeBaseService(
open val quotaService: QuotaService,
open val repositoryProperties: RepositoryProperties,
open val messageSupplier: MessageSupplier,
open val servicePermissionClient: ServicePermissionClient,
) : NodeService {

@Autowired
Expand All @@ -112,6 +117,7 @@ abstract class NodeBaseService(
override fun listNode(artifact: ArtifactInfo, option: NodeListOption): List<NodeInfo> {
checkNodeListOption(option)
with(artifact) {
getNoPermissionPaths(SecurityUtils.getUserId(), projectId, repoName)?.let { option.noPermissionPath = it }
val query = NodeQueryHelper.nodeListQuery(projectId, repoName, getArtifactFullPath(), option)
if (nodeDao.count(query) > repositoryProperties.listCountLimit) {
throw ErrorCodeException(ArtifactMessageCode.NODE_LIST_TOO_LARGE)
Expand All @@ -123,6 +129,7 @@ abstract class NodeBaseService(
override fun listNodePage(artifact: ArtifactInfo, option: NodeListOption): Page<NodeInfo> {
checkNodeListOption(option)
with(artifact) {
getNoPermissionPaths(SecurityUtils.getUserId(), projectId, repoName)?.let { option.noPermissionPath = it }
val pageNumber = option.pageNumber
val pageSize = option.pageSize
Preconditions.checkArgument(pageNumber >= 0, "pageNumber")
Expand Down Expand Up @@ -467,6 +474,27 @@ abstract class NodeBaseService(
)
}

/**
* 获取用户无权限路径列表
*/
private fun getNoPermissionPaths(userId: String, projectId: String, repoName: String): List<String>? {
if (userId == SYSTEM_USER) {
return null
}
val result = servicePermissionClient.listPermissionPath(userId, projectId, repoName).data!!
if (result.status) {
val paths = result.path.flatMap {
require(it.key == OperationType.NIN)
it.value
}.ifEmpty { null }
logger.info(
"user[$userId] does not have permission of paths[$paths] in [$projectId/$repoName], will be filterd"
)
return paths
}
return null
}

companion object {
private val logger = LoggerFactory.getLogger(NodeBaseService::class.java)
private const val TOPIC = "bkbase_bkrepo_artifact_node_created"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

package com.tencent.bkrepo.repository.service.node.impl

import com.tencent.bkrepo.auth.api.ServicePermissionClient
import com.tencent.bkrepo.common.artifact.api.ArtifactInfo
import com.tencent.bkrepo.common.service.cluster.DefaultCondition
import com.tencent.bkrepo.common.storage.core.StorageService
Expand Down Expand Up @@ -67,6 +68,7 @@ class NodeServiceImpl(
override val quotaService: QuotaService,
override val repositoryProperties: RepositoryProperties,
override val messageSupplier: MessageSupplier,
override val servicePermissionClient: ServicePermissionClient,
) : NodeBaseService(
nodeDao,
repositoryDao,
Expand All @@ -76,6 +78,7 @@ class NodeServiceImpl(
quotaService,
repositoryProperties,
messageSupplier,
servicePermissionClient,
) {

override fun computeSize(artifact: ArtifactInfo, estimated: Boolean): NodeSizeInfo {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

package com.tencent.bkrepo.repository.service.node.impl.center

import com.tencent.bkrepo.auth.api.ServicePermissionClient
import com.tencent.bkrepo.common.api.exception.ErrorCodeException
import com.tencent.bkrepo.common.api.message.CommonMessageCode
import com.tencent.bkrepo.common.artifact.message.ArtifactMessageCode
Expand Down Expand Up @@ -76,6 +77,7 @@ class CommitEdgeCenterNodeServiceImpl(
override val quotaService: QuotaService,
override val repositoryProperties: RepositoryProperties,
override val messageSupplier: MessageSupplier,
override val servicePermissionClient: ServicePermissionClient,
val clusterProperties: ClusterProperties
) : NodeServiceImpl(
nodeDao,
Expand All @@ -85,7 +87,8 @@ class CommitEdgeCenterNodeServiceImpl(
storageService,
quotaService,
repositoryProperties,
messageSupplier
messageSupplier,
servicePermissionClient,
) {

override fun checkRepo(projectId: String, repoName: String): TRepository {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

package com.tencent.bkrepo.repository.service.node.impl.edge

import com.tencent.bkrepo.auth.api.ServicePermissionClient
import com.tencent.bkrepo.common.service.cluster.ClusterProperties
import com.tencent.bkrepo.common.service.feign.FeignClientFactory
import com.tencent.bkrepo.common.storage.core.StorageService
Expand Down Expand Up @@ -54,6 +55,7 @@ abstract class EdgeNodeBaseService(
override val quotaService: QuotaService,
override val repositoryProperties: RepositoryProperties,
override val messageSupplier: MessageSupplier,
override val servicePermissionClient: ServicePermissionClient,
open val clusterProperties: ClusterProperties
) : NodeBaseService(
nodeDao,
Expand All @@ -63,7 +65,8 @@ abstract class EdgeNodeBaseService(
storageService,
quotaService,
repositoryProperties,
messageSupplier
messageSupplier,
servicePermissionClient,
) {

val centerNodeClient: ClusterNodeClient by lazy {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

package com.tencent.bkrepo.repository.service.node.impl.edge

import com.tencent.bkrepo.auth.api.ServicePermissionClient
import com.tencent.bkrepo.common.artifact.api.ArtifactInfo
import com.tencent.bkrepo.common.service.cluster.ClusterProperties
import com.tencent.bkrepo.common.service.cluster.CommitEdgeEdgeCondition
Expand Down Expand Up @@ -76,7 +77,8 @@ class EdgeNodeServiceImpl(
override val quotaService: QuotaService,
override val repositoryProperties: RepositoryProperties,
override val messageSupplier: MessageSupplier,
override val clusterProperties: ClusterProperties
override val servicePermissionClient: ServicePermissionClient,
override val clusterProperties: ClusterProperties,
) : EdgeNodeBaseService(
nodeDao,
repositoryDao,
Expand All @@ -86,7 +88,8 @@ class EdgeNodeServiceImpl(
quotaService,
repositoryProperties,
messageSupplier,
clusterProperties
servicePermissionClient,
clusterProperties,
) {
override fun computeSize(artifact: ArtifactInfo, estimated: Boolean): NodeSizeInfo {
return NodeStatsSupport(this).computeSize(artifact, estimated)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import org.springframework.data.mongodb.core.query.Update
import org.springframework.data.mongodb.core.query.and
import org.springframework.data.mongodb.core.query.inValues
import org.springframework.data.mongodb.core.query.isEqualTo
import org.springframework.data.mongodb.core.query.regex
import org.springframework.data.mongodb.core.query.where
import java.time.LocalDateTime

Expand Down Expand Up @@ -85,7 +86,17 @@ object NodeQueryHelper {
if (!option.includeFolder) {
criteria.and(TNode::folder).isEqualTo(false)
}
return criteria
return if (option.noPermissionPath.isNotEmpty()) {
val noPermissionPathCriteria = option.noPermissionPath.flatMap {
listOf(
TNode::fullPath.isEqualTo(it),
TNode::fullPath.regex("^${escapeRegex(it)}")
)
}
Criteria().andOperator(criteria, Criteria().norOperator(noPermissionPathCriteria))
} else {
criteria
}
}

fun nodeListQuery(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,13 @@

package com.tencent.bkrepo.repository.service

import com.tencent.bkrepo.auth.pojo.permission.ListPathResult
import com.tencent.bkrepo.common.api.exception.ErrorCodeException
import com.tencent.bkrepo.common.artifact.api.ArtifactInfo
import com.tencent.bkrepo.common.artifact.api.DefaultArtifactInfo
import com.tencent.bkrepo.common.artifact.path.PathUtils.ROOT
import com.tencent.bkrepo.common.query.enums.OperationType
import com.tencent.bkrepo.common.service.util.ResponseBuilder
import com.tencent.bkrepo.repository.UT_PROJECT_ID
import com.tencent.bkrepo.repository.UT_REPO_NAME
import com.tencent.bkrepo.repository.UT_USER
Expand All @@ -61,6 +64,8 @@ import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.api.assertThrows
import org.mockito.ArgumentMatchers.anyString
import org.mockito.kotlin.whenever
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest
import org.springframework.context.annotation.Import
Expand All @@ -86,12 +91,12 @@ class NodeServiceTest @Autowired constructor(

@BeforeAll
fun beforeAll() {
initMock()
initRepoForUnitTest(projectService, repositoryService)
}

@BeforeEach
fun beforeEach() {
initMock()
repositoryProperties.nodeCreateTimeout = 5000
nodeService.deleteByPath(UT_PROJECT_ID, UT_REPO_NAME, ROOT, UT_USER)
}
Expand Down Expand Up @@ -257,6 +262,41 @@ class NodeServiceTest @Autowired constructor(
assertEquals(7, page.pageNumber)
}

@Test
@DisplayName("测试查询无路径权限的目录")
fun testListNoPathPermissionNode() {
val size = 5L
repeat(size.toInt()) { i -> nodeService.createNode(createRequest("/a/$i/$i.txt", false)) }
whenever(servicePermissionClient.listPermissionPath(anyString(), anyString(), anyString())).thenReturn(
ResponseBuilder.success(
ListPathResult(
status = true,
path = mapOf(OperationType.NIN to listOf("/a/1", "/a/2"))
)
)
)

val option = NodeListOption(
pageNumber = 0,
pageSize = 10,
includeFolder = true,
includeMetadata = false,
deep = false,
sort = false
)
val page = nodeService.listNodePage(node("/a"), option)
assertEquals(3, page.totalRecords)
assertEquals("/a/0", page.records[0].fullPath)
assertEquals("/a/3", page.records[1].fullPath)
assertEquals("/a/4", page.records[2].fullPath)

val result = nodeService.listNode(node("/a"), option)
assertEquals(3, result.size)
assertEquals("/a/0", result[0].fullPath)
assertEquals("/a/3", result[1].fullPath)
assertEquals("/a/4", result[2].fullPath)
}

@Test
@DisplayName("测试删除文件")
fun testDeleteFile() {
Expand Down

0 comments on commit 0f47f4a

Please sign in to comment.