diff --git a/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizationUtils.java b/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizationUtils.java index f901ea827a9..0a0659acb4b 100644 --- a/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizationUtils.java +++ b/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizationUtils.java @@ -22,6 +22,8 @@ import org.apache.atlas.AtlasErrorCode; import org.apache.atlas.RequestContext; import org.apache.atlas.exception.AtlasBaseException; +import org.apache.atlas.model.instance.AtlasEntityHeader; +import org.apache.atlas.type.AtlasTypeRegistry; import org.apache.atlas.utils.AtlasPerfMetrics.MetricRecorder; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; @@ -35,6 +37,9 @@ import java.net.UnknownHostException; import java.util.*; +import static org.apache.atlas.repository.Constants.SKIP_DELETE_AUTH_CHECK_TYPES; +import static org.apache.atlas.repository.Constants.SKIP_UPDATE_AUTH_CHECK_TYPES; + public class AtlasAuthorizationUtils { private static final Logger LOG = LoggerFactory.getLogger(AtlasAuthorizationUtils.class); @@ -54,6 +59,20 @@ public static void verifyAccess(AtlasTypeAccessRequest request, Object... errorM } } + public static void verifyUpdateEntityAccess(AtlasTypeRegistry typeRegistry, AtlasEntityHeader entityHeader, String message) throws AtlasBaseException { + if (!SKIP_UPDATE_AUTH_CHECK_TYPES.contains(entityHeader.getTypeName())) { + AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(typeRegistry, AtlasPrivilege.ENTITY_UPDATE, entityHeader); + verifyAccess(request, message); + } + } + + public static void verifyDeleteEntityAccess(AtlasTypeRegistry typeRegistry, AtlasEntityHeader entityHeader, String message) throws AtlasBaseException { + if (!SKIP_DELETE_AUTH_CHECK_TYPES.contains(entityHeader.getTypeName())) { + AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(typeRegistry, AtlasPrivilege.ENTITY_DELETE, entityHeader); + verifyAccess(request, message); + } + } + public static void verifyAccess(AtlasEntityAccessRequest request, Object... errorMsgParams) throws AtlasBaseException { if (! isAccessAllowed(request)) { String message = (errorMsgParams != null && errorMsgParams.length > 0) ? StringUtils.join(errorMsgParams) : ""; diff --git a/common/src/main/java/org/apache/atlas/repository/Constants.java b/common/src/main/java/org/apache/atlas/repository/Constants.java index a3cef0608a9..3404797b7c4 100644 --- a/common/src/main/java/org/apache/atlas/repository/Constants.java +++ b/common/src/main/java/org/apache/atlas/repository/Constants.java @@ -34,6 +34,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; import static org.apache.atlas.type.AtlasStructType.AtlasAttribute.encodePropertyKey; @@ -154,6 +156,12 @@ public final class Constants { * Resource */ public static final String LINK_ENTITY_TYPE = "Link"; + public static final String README_ENTITY_TYPE = "Readme"; + + public static final String ASSET_RELATION_ATTR = "asset"; + + public static final String ASSET_README_EDGE_LABEL = "__Asset.readme"; + public static final String ASSET_LINK_EDGE_LABEL = "__Asset.links"; /** * Lineage relations. @@ -398,6 +406,16 @@ public enum SupportedFileExtensions { XLSX, XLS, CSV } public static final String REQUEST_HEADER_USER_AGENT = "User-Agent"; public static final String REQUEST_HEADER_HOST = "Host"; + public static final Set SKIP_UPDATE_AUTH_CHECK_TYPES = new HashSet() {{ + add(README_ENTITY_TYPE); + add(LINK_ENTITY_TYPE); + }}; + + public static final Set SKIP_DELETE_AUTH_CHECK_TYPES = new HashSet() {{ + add(README_ENTITY_TYPE); + add(LINK_ENTITY_TYPE); + }}; + private Constants() { } diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java index 75682efc09f..db8d91c2b58 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java @@ -58,13 +58,14 @@ import org.apache.atlas.repository.store.graph.v1.RestoreHandlerV1; import org.apache.atlas.repository.store.graph.v2.preprocessor.AuthPolicyPreProcessor; import org.apache.atlas.repository.store.graph.v2.preprocessor.ConnectionPreProcessor; -import org.apache.atlas.repository.store.graph.v2.preprocessor.LinkPreProcessor; +import org.apache.atlas.repository.store.graph.v2.preprocessor.resource.LinkPreProcessor; import org.apache.atlas.repository.store.graph.v2.preprocessor.PreProcessor; import org.apache.atlas.repository.store.graph.v2.preprocessor.accesscontrol.PersonaPreProcessor; import org.apache.atlas.repository.store.graph.v2.preprocessor.accesscontrol.PurposePreProcessor; import org.apache.atlas.repository.store.graph.v2.preprocessor.glossary.CategoryPreProcessor; import org.apache.atlas.repository.store.graph.v2.preprocessor.glossary.GlossaryPreProcessor; import org.apache.atlas.repository.store.graph.v2.preprocessor.glossary.TermPreProcessor; +import org.apache.atlas.repository.store.graph.v2.preprocessor.resource.ReadmePreProcessor; import org.apache.atlas.repository.store.graph.v2.preprocessor.sql.QueryCollectionPreProcessor; import org.apache.atlas.repository.store.graph.v2.preprocessor.sql.QueryFolderPreProcessor; import org.apache.atlas.repository.store.graph.v2.preprocessor.sql.QueryPreProcessor; @@ -509,7 +510,7 @@ public EntityMutationResponse updateByUniqueAttributes(AtlasEntityType entityTyp entity.setGuid(guid); - AtlasAuthorizationUtils.verifyAccess(new AtlasEntityAccessRequest(typeRegistry, AtlasPrivilege.ENTITY_UPDATE, new AtlasEntityHeader(entity)), "update entity ByUniqueAttributes"); + AtlasAuthorizationUtils.verifyUpdateEntityAccess(typeRegistry, new AtlasEntityHeader(entity), "update entity ByUniqueAttributes"); return createOrUpdate(new AtlasEntityStream(updatedEntityInfo), true, false, false, false); } @@ -526,7 +527,7 @@ public EntityMutationResponse updateEntityAttributeByGuid(String guid, String at AtlasEntityType entityType = (AtlasEntityType) typeRegistry.getType(entity.getTypeName()); AtlasAttribute attr = entityType.getAttribute(attrName); - AtlasAuthorizationUtils.verifyAccess(new AtlasEntityAccessRequest(typeRegistry, AtlasPrivilege.ENTITY_UPDATE, entity), "update entity ByUniqueAttributes : guid=", guid ); + AtlasAuthorizationUtils.verifyUpdateEntityAccess(typeRegistry, entity, "update entity ByUniqueAttributes : guid=" + guid); if (attr == null) { attr = entityType.getRelationshipAttribute(attrName, AtlasEntityUtil.getRelationshipType(attrValue)); @@ -581,7 +582,7 @@ public EntityMutationResponse deleteById(final String guid) throws AtlasBaseExce if (vertex != null) { AtlasEntityHeader entityHeader = entityRetriever.toAtlasEntityHeaderWithClassifications(vertex); - AtlasAuthorizationUtils.verifyAccess(new AtlasEntityAccessRequest(typeRegistry, AtlasPrivilege.ENTITY_DELETE, entityHeader), "delete entity: guid=", guid); + AtlasAuthorizationUtils.verifyDeleteEntityAccess(typeRegistry, entityHeader, "delete entity: guid=" + guid); deletionCandidates.add(vertex); } else { @@ -627,7 +628,7 @@ public EntityMutationResponse deleteByIds(final List guids) throws Atlas AtlasEntityHeader entityHeader = entityRetriever.toAtlasEntityHeaderWithClassifications(vertex); - AtlasAuthorizationUtils.verifyAccess(new AtlasEntityAccessRequest(typeRegistry, AtlasPrivilege.ENTITY_DELETE, entityHeader), "delete entity: guid=", guid); + AtlasAuthorizationUtils.verifyDeleteEntityAccess(typeRegistry, entityHeader, "delete entity: guid=" + guid); deletionCandidates.add(vertex); } @@ -670,7 +671,7 @@ public EntityMutationResponse restoreByIds(final List guids) throws Atla AtlasEntityHeader entityHeader = entityRetriever.toAtlasEntityHeaderWithClassifications(vertex); - AtlasAuthorizationUtils.verifyAccess(new AtlasEntityAccessRequest(typeRegistry, AtlasPrivilege.ENTITY_DELETE, entityHeader), "delete entity: guid=", guid); + AtlasAuthorizationUtils.verifyDeleteEntityAccess(typeRegistry, entityHeader, "delete entity: guid=" + guid); restoreCandidates.add(vertex); } @@ -736,7 +737,8 @@ public EntityMutationResponse deleteByUniqueAttributes(AtlasEntityType entityTyp if (vertex != null) { AtlasEntityHeader entityHeader = entityRetriever.toAtlasEntityHeaderWithClassifications(vertex); - AtlasAuthorizationUtils.verifyAccess(new AtlasEntityAccessRequest(typeRegistry, AtlasPrivilege.ENTITY_DELETE, entityHeader), "delete entity: typeName=", entityType.getTypeName(), ", uniqueAttributes=", uniqAttributes); + AtlasAuthorizationUtils.verifyDeleteEntityAccess(typeRegistry, entityHeader, + "delete entity: typeName=" + entityType.getTypeName() + ", uniqueAttributes=" + uniqAttributes); deletionCandidates.add(vertex); } else { @@ -788,7 +790,8 @@ public EntityMutationResponse deleteByUniqueAttributes(List objec if (vertex != null) { AtlasEntityHeader entityHeader = entityRetriever.toAtlasEntityHeaderWithClassifications(vertex); - AtlasAuthorizationUtils.verifyAccess(new AtlasEntityAccessRequest(typeRegistry, AtlasPrivilege.ENTITY_DELETE, entityHeader), "delete entity: typeName=", entityType.getTypeName(), ", uniqueAttributes=", objectId.getUniqueAttributes()); + AtlasAuthorizationUtils.verifyDeleteEntityAccess(typeRegistry, entityHeader, + "delete entity: typeName=" + entityType.getTypeName() + ", uniqueAttributes=" + objectId.getUniqueAttributes()); deletionCandidates.add(vertex); } else { @@ -1502,11 +1505,9 @@ private EntityMutationResponse createOrUpdate(EntityStream entityStream, boolean boolean skipAuthMeaningsUpdate = diffEntity != null && MapUtils.isNotEmpty(diffEntity.getRelationshipAttributes()) && diffEntity.getRelationshipAttributes().containsKey("meanings") && diffEntity.getRelationshipAttributes().size() == 1 && MapUtils.isEmpty(diffEntity.getAttributes()); boolean skipAuthStarredDetailsUpdate = diffEntity != null && MapUtils.isEmpty(diffEntity.getRelationshipAttributes()) && MapUtils.isNotEmpty(diffEntity.getAttributes()) && diffEntity.getAttributes().size() == 3 && diffEntity.getAttributes().containsKey(ATTR_STARRED_BY) && diffEntity.getAttributes().containsKey(ATTR_STARRED_COUNT) && diffEntity.getAttributes().containsKey(ATTR_STARRED_DETAILS_LIST); if (skipAuthBaseConditions && (skipAuthMeaningsUpdate || skipAuthStarredDetailsUpdate)) { - //do nothing, only diff is relationshipAttributes.meanings, allow update - } - else { - AtlasEntityAccessRequest accessRequest = new AtlasEntityAccessRequest(typeRegistry, AtlasPrivilege.ENTITY_UPDATE, entityHeader); - AtlasAuthorizationUtils.verifyAccess(accessRequest, "update entity: type=", entity.getTypeName()); + //do nothing, only diff is relationshipAttributes.meanings or starred, allow update + } else { + AtlasAuthorizationUtils.verifyUpdateEntityAccess(typeRegistry, entityHeader,"update entity: type=" + entity.getTypeName()); } } } @@ -1828,7 +1829,11 @@ public PreProcessor getPreProcessor(String typeName) { break; case LINK_ENTITY_TYPE: - preProcessor = new LinkPreProcessor(); + preProcessor = new LinkPreProcessor(typeRegistry, entityRetriever); + break; + + case README_ENTITY_TYPE: + preProcessor = new ReadmePreProcessor(typeRegistry, entityRetriever); break; } diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/resource/AbstractResourcePreProcessor.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/resource/AbstractResourcePreProcessor.java new file mode 100644 index 00000000000..8abb66a1503 --- /dev/null +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/resource/AbstractResourcePreProcessor.java @@ -0,0 +1,140 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.atlas.repository.store.graph.v2.preprocessor.resource; + +import org.apache.atlas.RequestContext; +import org.apache.atlas.authorize.AtlasAuthorizationUtils; +import org.apache.atlas.authorize.AtlasEntityAccessRequest; +import org.apache.atlas.authorize.AtlasPrivilege; +import org.apache.atlas.exception.AtlasBaseException; +import org.apache.atlas.model.instance.AtlasEntity; +import org.apache.atlas.model.instance.AtlasEntityHeader; +import org.apache.atlas.model.instance.AtlasObjectId; +import org.apache.atlas.repository.graphdb.AtlasEdgeDirection; +import org.apache.atlas.repository.graphdb.AtlasVertex; +import org.apache.atlas.repository.store.graph.v2.EntityGraphRetriever; +import org.apache.atlas.repository.store.graph.v2.preprocessor.PreProcessor; +import org.apache.atlas.type.AtlasTypeRegistry; +import org.apache.atlas.utils.AtlasPerfMetrics; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Iterator; + +import static org.apache.atlas.repository.Constants.ACTIVE_STATE_VALUE; +import static org.apache.atlas.repository.Constants.ASSET_RELATION_ATTR; +import static org.apache.atlas.repository.Constants.STATE_PROPERTY_KEY; + +public abstract class AbstractResourcePreProcessor implements PreProcessor { + private static final Logger LOG = LoggerFactory.getLogger(AbstractResourcePreProcessor.class); + + private final AtlasTypeRegistry typeRegistry; + private final EntityGraphRetriever entityRetriever; + + AbstractResourcePreProcessor(AtlasTypeRegistry typeRegistry, + EntityGraphRetriever entityRetriever) { + this.typeRegistry = typeRegistry; + this.entityRetriever = entityRetriever; + } + + void authorizeResourceUpdate(AtlasEntity resourceEntity, AtlasVertex ResourceVertex, String edgeLabel) throws AtlasBaseException { + AtlasPerfMetrics.MetricRecorder metricRecorder = RequestContext.get().startMetricRecord("authorizeResourceUpdate"); + + try { + AtlasEntityHeader assetEntity = null; + + AtlasObjectId asset = getAssetRelationAttr(resourceEntity); + if (asset != null) { + //Found linked asset in payload + AtlasVertex assetVertex = entityRetriever.getEntityVertex(asset); + assetEntity = entityRetriever.toAtlasEntityHeader(assetVertex); + + } else { + //Check for linked asset in store + Iterator atlasVertexIterator = ResourceVertex.query() + .direction(AtlasEdgeDirection.IN) + .label(edgeLabel) + .has(STATE_PROPERTY_KEY, ACTIVE_STATE_VALUE) + .vertices() + .iterator(); + + if (atlasVertexIterator.hasNext()) { + //Found linked asset in store + AtlasVertex assetVertex = (AtlasVertex) atlasVertexIterator.next(); + assetEntity = entityRetriever.toAtlasEntityHeader(assetVertex); + } + } + + if (assetEntity != null) { + //First authorize entity update access + verifyAssetAccess(assetEntity, AtlasPrivilege.ENTITY_UPDATE, resourceEntity, AtlasPrivilege.ENTITY_UPDATE); + } else { + //No linked asset to the Resource, check for resource update permission + verifyAccess(resourceEntity, AtlasPrivilege.ENTITY_UPDATE); + } + + } finally { + RequestContext.get().endMetricRecord(metricRecorder); + } + } + + void authorizeResourceDelete(AtlasVertex resourceVertex) throws AtlasBaseException { + AtlasPerfMetrics.MetricRecorder recorder = RequestContext.get().startMetricRecord("authorizeResourceDelete"); + + try { + AtlasEntity resourceEntity = entityRetriever.toAtlasEntity(resourceVertex); + + AtlasObjectId asset = getAssetRelationAttr(resourceEntity); + if (asset != null) { + AtlasEntityHeader assetEntity = entityRetriever.toAtlasEntityHeader(asset.getGuid()); + verifyAssetAccess(assetEntity, AtlasPrivilege.ENTITY_UPDATE, resourceEntity, AtlasPrivilege.ENTITY_DELETE); + } else { + //No linked asset to the Resource, check for resource delete permission + verifyAccess(resourceEntity, AtlasPrivilege.ENTITY_DELETE); + } + } finally { + RequestContext.get().endMetricRecord(recorder); + } + } + + private AtlasObjectId getAssetRelationAttr(AtlasEntity entity) { + AtlasObjectId ret = null; + + if (entity.hasRelationshipAttribute(ASSET_RELATION_ATTR) && + entity.getRelationshipAttribute(ASSET_RELATION_ATTR) != null) { + ret = (AtlasObjectId) entity.getRelationshipAttribute(ASSET_RELATION_ATTR); + } + + return ret; + } + + private void verifyAssetAccess(AtlasEntityHeader asset, AtlasPrivilege assetPrivilege, + AtlasEntity resource, AtlasPrivilege resourcePrivilege) throws AtlasBaseException { + verifyAccess(asset, assetPrivilege); + verifyAccess(resource, resourcePrivilege); + } + + private void verifyAccess(AtlasEntity entity, AtlasPrivilege privilege) throws AtlasBaseException { + verifyAccess(new AtlasEntityHeader(entity), privilege); + } + + private void verifyAccess(AtlasEntityHeader entityHeader, AtlasPrivilege privilege) throws AtlasBaseException { + String errorMessage = privilege.name() + " entity: " + entityHeader.getTypeName(); + AtlasAuthorizationUtils.verifyAccess(new AtlasEntityAccessRequest(typeRegistry, privilege, entityHeader), errorMessage); + } +} diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/LinkPreProcessor.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/resource/LinkPreProcessor.java similarity index 56% rename from repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/LinkPreProcessor.java rename to repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/resource/LinkPreProcessor.java index fa1a50f06e1..273359869c3 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/LinkPreProcessor.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/resource/LinkPreProcessor.java @@ -1,4 +1,4 @@ -package org.apache.atlas.repository.store.graph.v2.preprocessor; +package org.apache.atlas.repository.store.graph.v2.preprocessor.resource; import com.google.common.base.Predicate; import org.apache.atlas.RequestContext; @@ -6,22 +6,35 @@ import org.apache.atlas.model.instance.AtlasEntity; import org.apache.atlas.model.instance.AtlasStruct; import org.apache.atlas.model.instance.EntityMutations; +import org.apache.atlas.repository.graphdb.AtlasVertex; +import org.apache.atlas.repository.store.graph.v2.EntityGraphRetriever; import org.apache.atlas.repository.store.graph.v2.EntityMutationContext; +import org.apache.atlas.type.AtlasTypeRegistry; import org.apache.atlas.utils.AtlasPerfMetrics; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.regex.Pattern; +import static org.apache.atlas.model.instance.EntityMutations.EntityOperation.CREATE; +import static org.apache.atlas.model.instance.EntityMutations.EntityOperation.UPDATE; +import static org.apache.atlas.repository.Constants.ASSET_LINK_EDGE_LABEL; import static org.apache.atlas.repository.Constants.ATTRIBUTE_LINK; import static org.apache.atlas.repository.Constants.QUALIFIED_NAME; -public class LinkPreProcessor implements PreProcessor { + +public class LinkPreProcessor extends AbstractResourcePreProcessor { private static final Logger LOG = LoggerFactory.getLogger(LinkPreProcessor.class); + private static final Pattern REGEX_ONSITE_URL = Pattern.compile("(?:[\\p{L}\\p{N}\\\\\\.\\#@\\$%\\+&;\\-_~,\\?=/!]+|\\#(\\w)+)"); private static final Pattern REGEX_OFFSITE_URL = Pattern.compile("\\s*(?:(?:ht|f)tps?://|mailto:)[\\p{L}\\p{N}]" + "[\\p{L}\\p{N}\\p{Zs}\\.\\#@\\$%\\+&;:\\-_~,\\?=/!\\(\\)]*+\\s*"); private static final Predicate REGEX_ON_OFFSITE_URL = matchesEither(REGEX_ONSITE_URL, REGEX_OFFSITE_URL); + public LinkPreProcessor(AtlasTypeRegistry typeRegistry, + EntityGraphRetriever entityRetriever) { + super(typeRegistry, entityRetriever); + } + @Override public void processAttributes(AtlasStruct entityStruct, EntityMutationContext context, EntityMutations.EntityOperation operation) throws AtlasBaseException { if (LOG.isDebugEnabled()) { @@ -29,27 +42,46 @@ public void processAttributes(AtlasStruct entityStruct, EntityMutationContext co } AtlasEntity entity = (AtlasEntity) entityStruct; - String link = (String) entity.getAttribute(ATTRIBUTE_LINK); switch (operation) { case CREATE: + processLinkCreate(entity); + break; case UPDATE: - processLink(link, operation.name()); + processLinkUpdate(entity, context.getVertex(entity.getGuid())); break; } } + private void processLinkCreate(AtlasEntity linkEntity) throws AtlasBaseException { + validateLinkAttribute(linkEntity, CREATE.name()); + } + + private void processLinkUpdate(AtlasEntity linkEntity, AtlasVertex vertex) throws AtlasBaseException { + AtlasPerfMetrics.MetricRecorder metricRecorder = RequestContext.get().startMetricRecord("processLinkUpdate"); + + try { + validateLinkAttribute(linkEntity, UPDATE.name()); + + authorizeResourceUpdate(linkEntity, vertex, ASSET_LINK_EDGE_LABEL); + } finally { + RequestContext.get().endMetricRecord(metricRecorder); + } + } + /** - * Processes the link based on the provided operation. + * Validate the link based on the provided operation. * - * @param link The link to be processed. + * @param linkEntity The linkEntity to be processed. * @param operation The operation to be performed. * @throws AtlasBaseException If the link is not valid or empty. */ - private void processLink(String link, String operation) throws AtlasBaseException { + private void validateLinkAttribute(AtlasEntity linkEntity, String operation) throws AtlasBaseException { AtlasPerfMetrics.MetricRecorder metricRecorder = RequestContext.get().startMetricRecord(operation); + String link = (String) linkEntity.getAttribute(ATTRIBUTE_LINK); + if (link == null || link.isEmpty()) { throw new AtlasBaseException("Link is empty for operation: " + operation); } @@ -63,4 +95,9 @@ private void processLink(String link, String operation) throws AtlasBaseExceptio private static Predicate matchesEither(final Pattern a, final Pattern b) { return input -> a.matcher(input).matches() || b.matcher(input).matches(); } + + @Override + public void processDelete(AtlasVertex vertex) throws AtlasBaseException { + authorizeResourceDelete(vertex); + } } diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/resource/ReadmePreProcessor.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/resource/ReadmePreProcessor.java new file mode 100644 index 00000000000..b2ca8ca11e7 --- /dev/null +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/resource/ReadmePreProcessor.java @@ -0,0 +1,75 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.atlas.repository.store.graph.v2.preprocessor.resource; + +import org.apache.atlas.RequestContext; +import org.apache.atlas.exception.AtlasBaseException; +import org.apache.atlas.model.instance.AtlasEntity; +import org.apache.atlas.model.instance.AtlasStruct; +import org.apache.atlas.model.instance.EntityMutations; +import org.apache.atlas.repository.graphdb.AtlasVertex; +import org.apache.atlas.repository.store.graph.v2.EntityGraphRetriever; +import org.apache.atlas.repository.store.graph.v2.EntityMutationContext; +import org.apache.atlas.type.AtlasTypeRegistry; +import org.apache.atlas.utils.AtlasPerfMetrics; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.apache.atlas.repository.Constants.ASSET_README_EDGE_LABEL; +import static org.apache.atlas.repository.Constants.QUALIFIED_NAME; + +public class ReadmePreProcessor extends AbstractResourcePreProcessor { + private static final Logger LOG = LoggerFactory.getLogger(ReadmePreProcessor.class); + + public ReadmePreProcessor(AtlasTypeRegistry typeRegistry, + EntityGraphRetriever entityRetriever) { + super(typeRegistry, entityRetriever); + } + + @Override + public void processAttributes(AtlasStruct entityStruct, EntityMutationContext context, EntityMutations.EntityOperation operation) throws AtlasBaseException { + if (LOG.isDebugEnabled()) { + LOG.debug("ReadmePreProcessor.processAttributes: pre processing {}, {}", entityStruct.getAttribute(QUALIFIED_NAME), operation); + } + + AtlasEntity entity = (AtlasEntity) entityStruct; + + switch (operation) { + case UPDATE: + processUpdateReadme(entity, context.getVertex(entity.getGuid())); + break; + } + } + + private void processUpdateReadme(AtlasStruct struct, AtlasVertex vertex) throws AtlasBaseException { + AtlasPerfMetrics.MetricRecorder metricRecorder = RequestContext.get().startMetricRecord("processUpdateReadme"); + + AtlasEntity readmeEntity = (AtlasEntity) struct; + + try { + authorizeResourceUpdate(readmeEntity, vertex, ASSET_README_EDGE_LABEL); + } finally { + RequestContext.get().endMetricRecord(metricRecorder); + } + } + + @Override + public void processDelete(AtlasVertex vertex) throws AtlasBaseException { + authorizeResourceDelete(vertex); + } +}