From 93848cc609274648d9da8858b004d6b87ea2f8f5 Mon Sep 17 00:00:00 2001 From: zacYL <100330102+zacYL@users.noreply.github.com> Date: Fri, 22 Nov 2024 10:12:51 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BD=BF=E7=94=A8=E4=B8=B4=E6=97=B6tok?= =?UTF-8?q?en=E6=93=8D=E4=BD=9C=E6=97=B6=E8=AE=BE=E7=BD=AE=E5=AF=B9?= =?UTF-8?q?=E5=BA=94=E6=93=8D=E4=BD=9C=E7=94=A8=E6=88=B7,=E5=90=8C?= =?UTF-8?q?=E6=97=B6=E5=88=A0=E6=8E=89=E5=AE=A1=E8=AE=A1=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E4=B8=ADtoken=E4=BF=A1=E6=81=AF#2777?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 使用临时token操作时设置对应操作用户,同时删掉审计日志中token信息#2777 * feat: 代码调整#2777 * feat: 操作调整#2777 --- .../bkrepo/common/api/constant/Constants.kt | 6 +++++ .../artifact/audit/ActionAuditContent.kt | 6 ++--- .../artifact/audit/BkAuditPostFilter.kt | 13 ++++++++++- .../controller/TemporaryAccessController.kt | 22 ++++++------------- .../generic/service/TemporaryAccessService.kt | 16 +++++++++++++- .../controller/user/UserMetadataController.kt | 16 +++++++------- .../controller/user/UserShareController.kt | 5 ----- .../service/file/impl/ShareServiceImpl.kt | 13 +++++++++-- 8 files changed, 62 insertions(+), 35 deletions(-) diff --git a/src/backend/common/common-api/src/main/kotlin/com/tencent/bkrepo/common/api/constant/Constants.kt b/src/backend/common/common-api/src/main/kotlin/com/tencent/bkrepo/common/api/constant/Constants.kt index b38e19b921..6f4344a61c 100644 --- a/src/backend/common/common-api/src/main/kotlin/com/tencent/bkrepo/common/api/constant/Constants.kt +++ b/src/backend/common/common-api/src/main/kotlin/com/tencent/bkrepo/common/api/constant/Constants.kt @@ -167,3 +167,9 @@ const val BKREPO_TRACE = "X-BKREPO-RID" */ const val CODE_PROJECT_PREFIX = "CODE_" const val CLOSED_SOURCE_PREFIX = "CLOSED_SOURCE_" + + +const val AUDITED_UID = "audited_uid" +const val AUDIT_REQUEST_URI = "audit_request_uri" +const val AUDIT_REQUEST_KEY = "http_request" +const val AUDIT_SHARE_USER_ID = "audit_share_user_id" diff --git a/src/backend/common/common-artifact/artifact-service/src/main/kotlin/com/tencent/bkrepo/common/artifact/audit/ActionAuditContent.kt b/src/backend/common/common-artifact/artifact-service/src/main/kotlin/com/tencent/bkrepo/common/artifact/audit/ActionAuditContent.kt index 200de35498..add2656c6a 100644 --- a/src/backend/common/common-artifact/artifact-service/src/main/kotlin/com/tencent/bkrepo/common/artifact/audit/ActionAuditContent.kt +++ b/src/backend/common/common-artifact/artifact-service/src/main/kotlin/com/tencent/bkrepo/common/artifact/audit/ActionAuditContent.kt @@ -68,9 +68,9 @@ object ActionAuditContent { // 节点 const val NODE_SHARE_CREATE_CONTENT = "create share link for node info $CONTENT_TEMPLATE in repo $PROJECT_CODE_CONTENT_TEMPLATE|$REPO_NAME_CONTENT_TEMPLATE" - const val NODE_SHARE_DOWNLOAD_CONTENT = "download share node $CONTENT_TEMPLATE with token [{{@TOKEN}}] in repo $PROJECT_CODE_CONTENT_TEMPLATE|$REPO_NAME_CONTENT_TEMPLATE" - const val NODE_DOWNLOAD_WITH_TOKEN_CONTENT = "download node $CONTENT_TEMPLATE with token [{{@TOKEN}}] in repo $PROJECT_CODE_CONTENT_TEMPLATE|$REPO_NAME_CONTENT_TEMPLATE" - const val NODE_UPLOAD_WITH_TOKEN_CONTENT = "upload node $CONTENT_TEMPLATE with token [{{@TOKEN}}] in repo $PROJECT_CODE_CONTENT_TEMPLATE|$REPO_NAME_CONTENT_TEMPLATE" + const val NODE_SHARE_DOWNLOAD_CONTENT = "download share node $CONTENT_TEMPLATE with token in repo $PROJECT_CODE_CONTENT_TEMPLATE|$REPO_NAME_CONTENT_TEMPLATE" + const val NODE_DOWNLOAD_WITH_TOKEN_CONTENT = "download node $CONTENT_TEMPLATE with token in repo $PROJECT_CODE_CONTENT_TEMPLATE|$REPO_NAME_CONTENT_TEMPLATE" + const val NODE_UPLOAD_WITH_TOKEN_CONTENT = "upload node $CONTENT_TEMPLATE with token in repo $PROJECT_CODE_CONTENT_TEMPLATE|$REPO_NAME_CONTENT_TEMPLATE" const val NODE_VIEW_CONTENT = "get node info $CONTENT_TEMPLATE in repo $PROJECT_CODE_CONTENT_TEMPLATE|$REPO_NAME_CONTENT_TEMPLATE" const val NODE_CREATE_CONTENT = "create node $CONTENT_TEMPLATE in repo $PROJECT_CODE_CONTENT_TEMPLATE|$REPO_NAME_CONTENT_TEMPLATE" diff --git a/src/backend/common/common-artifact/artifact-service/src/main/kotlin/com/tencent/bkrepo/common/artifact/audit/BkAuditPostFilter.kt b/src/backend/common/common-artifact/artifact-service/src/main/kotlin/com/tencent/bkrepo/common/artifact/audit/BkAuditPostFilter.kt index ceced95a67..f4f8aad908 100644 --- a/src/backend/common/common-artifact/artifact-service/src/main/kotlin/com/tencent/bkrepo/common/artifact/audit/BkAuditPostFilter.kt +++ b/src/backend/common/common-artifact/artifact-service/src/main/kotlin/com/tencent/bkrepo/common/artifact/audit/BkAuditPostFilter.kt @@ -56,10 +56,21 @@ package com.tencent.bkrepo.common.artifact.audit import com.tencent.bk.audit.filter.AuditPostFilter import com.tencent.bk.audit.model.AuditEvent +import com.tencent.bkrepo.common.api.constant.AUDITED_UID +import com.tencent.bkrepo.common.api.constant.AUDIT_REQUEST_KEY +import com.tencent.bkrepo.common.api.constant.AUDIT_REQUEST_URI +import com.tencent.bkrepo.common.api.constant.AUDIT_SHARE_USER_ID class BkAuditPostFilter: AuditPostFilter { override fun map(auditEvent: AuditEvent): AuditEvent { - auditEvent.scopeType = "project" + auditEvent.scopeType = PROJECT_RESOURCE + // 特殊处理, 使用token下载时下载用户是根据token去判断后塞入httpAttribute中, 初始化时无法获取 + if (auditEvent.extendData.isNullOrEmpty()) return auditEvent + auditEvent.extendData[AUDIT_SHARE_USER_ID] ?: return auditEvent + val auditedUid = auditEvent.extendData[AUDITED_UID]?.toString() + val auditRequestUri = auditEvent.extendData[AUDIT_REQUEST_URI] + auditEvent.username = auditedUid ?: auditEvent.username + auditEvent.addExtendData(AUDIT_REQUEST_KEY, auditRequestUri) return auditEvent } } \ No newline at end of file diff --git a/src/backend/generic/biz-generic/src/main/kotlin/com/tencent/bkrepo/generic/controller/TemporaryAccessController.kt b/src/backend/generic/biz-generic/src/main/kotlin/com/tencent/bkrepo/generic/controller/TemporaryAccessController.kt index 661a010118..7e6f9fcbd6 100644 --- a/src/backend/generic/biz-generic/src/main/kotlin/com/tencent/bkrepo/generic/controller/TemporaryAccessController.kt +++ b/src/backend/generic/biz-generic/src/main/kotlin/com/tencent/bkrepo/generic/controller/TemporaryAccessController.kt @@ -31,7 +31,6 @@ import com.tencent.bk.audit.annotations.ActionAuditRecord import com.tencent.bk.audit.annotations.AuditAttribute import com.tencent.bk.audit.annotations.AuditEntry import com.tencent.bk.audit.annotations.AuditInstanceRecord -import com.tencent.bk.audit.context.ActionAuditContext import com.tencent.bkrepo.auth.pojo.enums.PermissionAction import com.tencent.bkrepo.auth.pojo.token.TemporaryTokenCreateRequest import com.tencent.bkrepo.auth.pojo.token.TokenType @@ -41,13 +40,13 @@ import com.tencent.bkrepo.common.api.message.CommonMessageCode import com.tencent.bkrepo.common.api.pojo.Response import com.tencent.bkrepo.common.artifact.api.ArtifactFile import com.tencent.bkrepo.common.artifact.api.ArtifactPathVariable -import com.tencent.bkrepo.common.artifact.metrics.ChunkArtifactTransferMetrics -import com.tencent.bkrepo.common.artifact.router.Router -import com.tencent.bkrepo.common.metadata.permission.PermissionManager import com.tencent.bkrepo.common.artifact.audit.ActionAuditContent +import com.tencent.bkrepo.common.artifact.audit.NODE_CREATE_ACTION import com.tencent.bkrepo.common.artifact.audit.NODE_DOWNLOAD_ACTION import com.tencent.bkrepo.common.artifact.audit.NODE_RESOURCE -import com.tencent.bkrepo.common.artifact.audit.NODE_CREATE_ACTION +import com.tencent.bkrepo.common.artifact.metrics.ChunkArtifactTransferMetrics +import com.tencent.bkrepo.common.artifact.router.Router +import com.tencent.bkrepo.common.metadata.permission.PermissionManager import com.tencent.bkrepo.common.security.permission.Principal import com.tencent.bkrepo.common.security.permission.PrincipalType import com.tencent.bkrepo.common.service.util.HttpContextHolder @@ -131,10 +130,6 @@ class TemporaryAccessController( AuditAttribute( name = ActionAuditContent.REPO_NAME_TEMPLATE, value = "#artifactInfo?.repoName" - ), - AuditAttribute( - name = ActionAuditContent.TOKEN_TEMPLATE, - value = "#token" ) ], scopeId = "#artifactInfo?.projectId", @@ -151,7 +146,6 @@ class TemporaryAccessController( artifactInfo: GenericArtifactInfo ) { val downloadUser = downloadUserId ?: userId - ActionAuditContext.current().addExtendData("downloadUser", downloadUser) val tokenInfo = temporaryAccessService.validateToken(token, artifactInfo, TokenType.DOWNLOAD) temporaryAccessService.downloadByShare(downloadUser, tokenInfo.createdBy, artifactInfo) temporaryAccessService.decrementPermits(tokenInfo) @@ -170,8 +164,7 @@ class TemporaryAccessController( ), attributes = [ AuditAttribute(name = ActionAuditContent.PROJECT_CODE_TEMPLATE, value = "#artifactInfo?.projectId"), - AuditAttribute(name = ActionAuditContent.REPO_NAME_TEMPLATE, value = "#artifactInfo?.repoName"), - AuditAttribute(name = ActionAuditContent.TOKEN_TEMPLATE, value = "#token") + AuditAttribute(name = ActionAuditContent.REPO_NAME_TEMPLATE, value = "#artifactInfo?.repoName") ], scopeId = "#artifactInfo?.projectId", content = ActionAuditContent.NODE_DOWNLOAD_WITH_TOKEN_CONTENT @@ -200,9 +193,8 @@ class TemporaryAccessController( ), attributes = [ AuditAttribute(name = ActionAuditContent.PROJECT_CODE_TEMPLATE, value = "#artifactInfo?.projectId"), - AuditAttribute(name = ActionAuditContent.REPO_NAME_TEMPLATE, value = "#artifactInfo?.repoName"), - AuditAttribute(name = ActionAuditContent.TOKEN_TEMPLATE, value = "#token") - ], + AuditAttribute(name = ActionAuditContent.REPO_NAME_TEMPLATE, value = "#artifactInfo?.repoName") + ], scopeId = "#artifactInfo?.projectId", content = ActionAuditContent.NODE_UPLOAD_WITH_TOKEN_CONTENT ) diff --git a/src/backend/generic/biz-generic/src/main/kotlin/com/tencent/bkrepo/generic/service/TemporaryAccessService.kt b/src/backend/generic/biz-generic/src/main/kotlin/com/tencent/bkrepo/generic/service/TemporaryAccessService.kt index f9fea00d69..0c0096e8a2 100644 --- a/src/backend/generic/biz-generic/src/main/kotlin/com/tencent/bkrepo/generic/service/TemporaryAccessService.kt +++ b/src/backend/generic/biz-generic/src/main/kotlin/com/tencent/bkrepo/generic/service/TemporaryAccessService.kt @@ -31,12 +31,16 @@ package com.tencent.bkrepo.generic.service +import com.tencent.bk.audit.context.ActionAuditContext import com.tencent.bkrepo.auth.api.ServiceTemporaryTokenClient import com.tencent.bkrepo.auth.pojo.enums.PermissionAction import com.tencent.bkrepo.auth.pojo.token.TemporaryTokenCreateRequest import com.tencent.bkrepo.auth.pojo.token.TemporaryTokenInfo import com.tencent.bkrepo.auth.pojo.token.TokenType import com.tencent.bkrepo.common.api.constant.ANONYMOUS_USER +import com.tencent.bkrepo.common.api.constant.AUDITED_UID +import com.tencent.bkrepo.common.api.constant.AUDIT_REQUEST_URI +import com.tencent.bkrepo.common.api.constant.AUDIT_SHARE_USER_ID import com.tencent.bkrepo.common.api.constant.AUTH_HEADER_UID import com.tencent.bkrepo.common.api.constant.HttpStatus import com.tencent.bkrepo.common.api.constant.StringPool @@ -60,8 +64,8 @@ import com.tencent.bkrepo.common.artifact.path.PathUtils import com.tencent.bkrepo.common.artifact.repository.context.ArtifactContextHolder import com.tencent.bkrepo.common.artifact.repository.context.ArtifactDownloadContext import com.tencent.bkrepo.common.artifact.repository.context.ArtifactUploadContext -import com.tencent.bkrepo.common.metadata.service.repo.RepositoryService import com.tencent.bkrepo.common.metadata.permission.PermissionManager +import com.tencent.bkrepo.common.metadata.service.repo.RepositoryService import com.tencent.bkrepo.common.security.util.SecurityUtils import com.tencent.bkrepo.common.service.util.HeaderUtils import com.tencent.bkrepo.common.service.util.HttpContextHolder @@ -137,6 +141,11 @@ class TemporaryAccessService( ?: throw ErrorCodeException(ArtifactMessageCode.REPOSITORY_NOT_FOUND, repoName) val context = ArtifactDownloadContext(repo = repo, userId = downloadUser) HttpContextHolder.getRequest().setAttribute(USER_KEY, downloadUser) + ActionAuditContext.current().addExtendData(AUDITED_UID, downloadUser) + ActionAuditContext.current().addExtendData( + AUDIT_REQUEST_URI, "{${HttpContextHolder.getRequestOrNull()?.requestURI}}" + ) + ActionAuditContext.current().addExtendData(AUDIT_SHARE_USER_ID, shareBy) context.shareUserId = shareBy val repository = ArtifactContextHolder.getRepository(context.repositoryDetail.category) repository.download(context) @@ -449,6 +458,11 @@ class TemporaryAccessService( } // 设置审计uid到session中 HttpContextHolder.getRequestOrNull()?.setAttribute(USER_KEY, auditedUid) + ActionAuditContext.current().addExtendData(AUDITED_UID, auditedUid) + ActionAuditContext.current().addExtendData( + AUDIT_REQUEST_URI, "{${HttpContextHolder.getRequestOrNull()?.requestURI}}" + ) + ActionAuditContext.current().addExtendData(AUDIT_SHARE_USER_ID, tokenInfo.createdBy) // 校验ip授权 val clientIp = HttpContextHolder.getClientAddress() if (tokenInfo.authorizedIpList.isNotEmpty() && clientIp !in tokenInfo.authorizedIpList) { diff --git a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/controller/user/UserMetadataController.kt b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/controller/user/UserMetadataController.kt index 7fccda0d93..2a792cd9f4 100644 --- a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/controller/user/UserMetadataController.kt +++ b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/controller/user/UserMetadataController.kt @@ -43,9 +43,10 @@ import com.tencent.bkrepo.common.artifact.api.ArtifactInfo import com.tencent.bkrepo.common.artifact.api.ArtifactPathVariable import com.tencent.bkrepo.common.artifact.api.DefaultArtifactInfo.Companion.DEFAULT_MAPPING_URI import com.tencent.bkrepo.common.artifact.audit.ActionAuditContent +import com.tencent.bkrepo.common.artifact.audit.NODE_EDIT_ACTION import com.tencent.bkrepo.common.artifact.audit.NODE_RESOURCE import com.tencent.bkrepo.common.artifact.audit.NODE_VIEW_ACTION -import com.tencent.bkrepo.common.artifact.audit.REPO_EDIT_ACTION +import com.tencent.bkrepo.common.metadata.service.metadata.MetadataService import com.tencent.bkrepo.common.security.permission.Permission import com.tencent.bkrepo.common.security.util.SecurityUtils import com.tencent.bkrepo.common.service.util.ResponseBuilder @@ -53,7 +54,6 @@ import com.tencent.bkrepo.repository.pojo.metadata.MetadataDeleteRequest import com.tencent.bkrepo.repository.pojo.metadata.MetadataSaveRequest import com.tencent.bkrepo.repository.pojo.metadata.UserMetadataDeleteRequest import com.tencent.bkrepo.repository.pojo.metadata.UserMetadataSaveRequest -import com.tencent.bkrepo.common.metadata.service.metadata.MetadataService import io.swagger.annotations.Api import io.swagger.annotations.ApiOperation import org.springframework.web.bind.annotation.DeleteMapping @@ -104,10 +104,10 @@ class UserMetadataController( } @AuditEntry( - actionId = REPO_EDIT_ACTION + actionId = NODE_EDIT_ACTION ) @ActionAuditRecord( - actionId = REPO_EDIT_ACTION, + actionId = NODE_EDIT_ACTION, instance = AuditInstanceRecord( resourceType = NODE_RESOURCE, instanceIds = "#artifactInfo?.getArtifactFullPath()", @@ -144,10 +144,10 @@ class UserMetadataController( } @AuditEntry( - actionId = REPO_EDIT_ACTION + actionId = NODE_EDIT_ACTION ) @ActionAuditRecord( - actionId = REPO_EDIT_ACTION, + actionId = NODE_EDIT_ACTION, instance = AuditInstanceRecord( resourceType = NODE_RESOURCE, instanceIds = "#artifactInfo?.getArtifactFullPath()", @@ -182,10 +182,10 @@ class UserMetadataController( } @AuditEntry( - actionId = REPO_EDIT_ACTION + actionId = NODE_EDIT_ACTION ) @ActionAuditRecord( - actionId = REPO_EDIT_ACTION, + actionId = NODE_EDIT_ACTION, instance = AuditInstanceRecord( resourceType = NODE_RESOURCE, instanceIds = "#artifactInfo?.getArtifactFullPath()", diff --git a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/controller/user/UserShareController.kt b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/controller/user/UserShareController.kt index 6c7a04552a..c0152d8bca 100644 --- a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/controller/user/UserShareController.kt +++ b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/controller/user/UserShareController.kt @@ -165,10 +165,6 @@ class UserShareController( AuditAttribute( name = ActionAuditContent.REPO_NAME_TEMPLATE, value = "#artifactInfo?.repoName" - ), - AuditAttribute( - name = ActionAuditContent.TOKEN_TEMPLATE, - value = "#token" ) ], scopeId = "#artifactInfo?.projectId", @@ -183,7 +179,6 @@ class UserShareController( @ArtifactPathVariable artifactInfo: ArtifactInfo ) { val downloadUser = downloadUserId ?: userId - ActionAuditContext.current().addExtendData("downloadUser", downloadUser) shareService.download(downloadUser, token, artifactInfo) } } diff --git a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/file/impl/ShareServiceImpl.kt b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/file/impl/ShareServiceImpl.kt index 55342317d6..acf1af7350 100644 --- a/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/file/impl/ShareServiceImpl.kt +++ b/src/backend/repository/biz-repository/src/main/kotlin/com/tencent/bkrepo/repository/service/file/impl/ShareServiceImpl.kt @@ -31,10 +31,14 @@ package com.tencent.bkrepo.repository.service.file.impl +import com.tencent.bk.audit.context.ActionAuditContext import com.tencent.bkrepo.auth.api.ServiceTemporaryTokenClient import com.tencent.bkrepo.auth.pojo.token.TemporaryTokenCreateRequest import com.tencent.bkrepo.auth.pojo.token.TokenType import com.tencent.bkrepo.common.api.constant.ANONYMOUS_USER +import com.tencent.bkrepo.common.api.constant.AUDITED_UID +import com.tencent.bkrepo.common.api.constant.AUDIT_REQUEST_URI +import com.tencent.bkrepo.common.api.constant.AUDIT_SHARE_USER_ID import com.tencent.bkrepo.common.api.constant.USER_KEY import com.tencent.bkrepo.common.api.exception.ErrorCodeException import com.tencent.bkrepo.common.artifact.api.ArtifactInfo @@ -42,6 +46,8 @@ import com.tencent.bkrepo.common.artifact.exception.NodeNotFoundException import com.tencent.bkrepo.common.artifact.message.ArtifactMessageCode import com.tencent.bkrepo.common.artifact.repository.context.ArtifactContextHolder import com.tencent.bkrepo.common.artifact.repository.context.ArtifactDownloadContext +import com.tencent.bkrepo.common.metadata.service.node.NodeService +import com.tencent.bkrepo.common.metadata.service.repo.RepositoryService import com.tencent.bkrepo.common.security.exception.PermissionException import com.tencent.bkrepo.common.service.cluster.condition.DefaultCondition import com.tencent.bkrepo.common.service.util.HttpContextHolder @@ -49,8 +55,6 @@ import com.tencent.bkrepo.repository.model.TShareRecord import com.tencent.bkrepo.repository.pojo.share.ShareRecordCreateRequest import com.tencent.bkrepo.repository.pojo.share.ShareRecordInfo import com.tencent.bkrepo.repository.service.file.ShareService -import com.tencent.bkrepo.common.metadata.service.node.NodeService -import com.tencent.bkrepo.common.metadata.service.repo.RepositoryService import org.slf4j.LoggerFactory import org.springframework.context.annotation.Conditional import org.springframework.data.mongodb.core.MongoTemplate @@ -144,6 +148,11 @@ class ShareServiceImpl( ?: throw ErrorCodeException(ArtifactMessageCode.REPOSITORY_NOT_FOUND, repoName) val context = ArtifactDownloadContext(repo = repo, userId = userId) HttpContextHolder.getRequest().setAttribute(USER_KEY, downloadUser) + ActionAuditContext.current().addExtendData(AUDITED_UID, downloadUser) + ActionAuditContext.current().addExtendData( + AUDIT_REQUEST_URI, "{${HttpContextHolder.getRequestOrNull()?.requestURI}}" + ) + ActionAuditContext.current().addExtendData(AUDIT_SHARE_USER_ID, shareRecord.createdBy) context.shareUserId = shareRecord.createdBy val repository = ArtifactContextHolder.getRepository(context.repositoryDetail.category) repository.download(context)