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 f5a6e27761..5b58c88e59 100644 --- a/common/src/main/java/org/apache/atlas/repository/Constants.java +++ b/common/src/main/java/org/apache/atlas/repository/Constants.java @@ -415,6 +415,7 @@ public enum SupportedFileExtensions { XLSX, XLS, CSV } public static final Set SKIP_DELETE_AUTH_CHECK_TYPES = new HashSet() {{ add(README_ENTITY_TYPE); add(LINK_ENTITY_TYPE); + add(POLICY_ENTITY_TYPE); }}; private Constants() { diff --git a/repository/src/main/java/org/apache/atlas/repository/store/bootstrap/AuthPoliciesBootstrapper.java b/repository/src/main/java/org/apache/atlas/repository/store/bootstrap/AuthPoliciesBootstrapper.java index ddb94056b8..9b1327ba1f 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/bootstrap/AuthPoliciesBootstrapper.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/bootstrap/AuthPoliciesBootstrapper.java @@ -81,13 +81,17 @@ private void startInternal() { private void loadBootstrapAuthPolicies() { LOG.info("==> AuthPoliciesBootstrapper.loadBootstrapAuthPolicies()"); - RequestContext.get().setPoliciesBootstrappingInProgress(true); + RequestContext.get().setSkipAuthorizationCheck(true); - String atlasHomeDir = System.getProperty("atlas.home"); - String policiesDirName = (StringUtils.isEmpty(atlasHomeDir) ? "." : atlasHomeDir) + File.separator + "policies"; + try { + String atlasHomeDir = System.getProperty("atlas.home"); + String policiesDirName = (StringUtils.isEmpty(atlasHomeDir) ? "." : atlasHomeDir) + File.separator + "policies"; - File topPoliciesDir = new File(policiesDirName); - loadPoliciesInFolder(topPoliciesDir); + File topPoliciesDir = new File(policiesDirName); + loadPoliciesInFolder(topPoliciesDir); + } finally { + RequestContext.get().setSkipAuthorizationCheck(false); + } LOG.info("<== AuthPoliciesBootstrapper.loadBootstrapAuthPolicies()"); } 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 7ddff9920f..7f705575e7 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 @@ -1437,7 +1437,7 @@ private EntityMutationResponse createOrUpdate(EntityStream entityStream, boolean final EntityMutationContext context = preCreateOrUpdate(entityStream, entityGraphMapper, isPartialUpdate); // Check if authorized to create entities - if (!RequestContext.get().isImportInProgress() && !RequestContext.get().isPoliciesBootstrappingInProgress()) { + if (!RequestContext.get().isImportInProgress() && !RequestContext.get().isSkipAuthorizationCheck()) { for (AtlasEntity entity : context.getCreatedEntities()) { if (!PreProcessor.skipInitialAuthCheckTypes.contains(entity.getTypeName())) { AtlasAuthorizationUtils.verifyAccess(new AtlasEntityAccessRequest(typeRegistry, AtlasPrivilege.ENTITY_CREATE, new AtlasEntityHeader(entity)), diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/AuthPolicyPreProcessor.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/AuthPolicyPreProcessor.java index 679cc9081c..5149568f1a 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/AuthPolicyPreProcessor.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/AuthPolicyPreProcessor.java @@ -21,10 +21,13 @@ import org.apache.atlas.AtlasErrorCode; 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.featureflag.FeatureFlagStore; import org.apache.atlas.model.instance.AtlasEntity; import org.apache.atlas.model.instance.AtlasEntity.AtlasEntityWithExtInfo; +import org.apache.atlas.model.instance.AtlasEntityHeader; import org.apache.atlas.model.instance.AtlasObjectId; import org.apache.atlas.model.instance.AtlasStruct; import org.apache.atlas.model.instance.EntityMutations.EntityOperation; @@ -52,6 +55,7 @@ import static org.apache.atlas.AtlasErrorCode.RESOURCE_NOT_FOUND; import static org.apache.atlas.AtlasErrorCode.UNAUTHORIZED_CONNECTION_ADMIN; import static org.apache.atlas.authorize.AtlasAuthorizationUtils.getCurrentUserName; +import static org.apache.atlas.authorize.AtlasAuthorizationUtils.verifyAccess; 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.ATTR_ADMIN_ROLES; @@ -223,6 +227,8 @@ public void processDelete(AtlasVertex vertex) throws AtlasBaseException { try { AtlasEntity policy = entityRetriever.toAtlasEntity(vertex); + authorizeDeleteAuthPolicy(policy); + if(!policy.getStatus().equals(AtlasEntity.Status.ACTIVE)) { LOG.info("Policy with guid {} is already deleted/purged", policy.getGuid()); return; @@ -238,6 +244,16 @@ public void processDelete(AtlasVertex vertex) throws AtlasBaseException { } } + private void authorizeDeleteAuthPolicy(AtlasEntity policy) throws AtlasBaseException { + if (!RequestContext.get().isSkipAuthorizationCheck()) { + AtlasEntityAccessRequest request = new AtlasEntityAccessRequest(typeRegistry, AtlasPrivilege.ENTITY_DELETE, new AtlasEntityHeader(policy)); + verifyAccess(request, "delete entity: guid=" + policy.getGuid()); + } + /* else, + * skip auth check + * */ + } + private void validateConnectionAdmin(AtlasEntity policy) throws AtlasBaseException { String subCategory = getPolicySubCategory(policy); if (POLICY_SUB_CATEGORY_METADATA.equals(subCategory) || POLICY_SUB_CATEGORY_DATA.equals(subCategory)) { diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/AuthPolicyValidator.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/AuthPolicyValidator.java index 451e7326ec..8a91b4af5f 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/AuthPolicyValidator.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/AuthPolicyValidator.java @@ -265,7 +265,7 @@ public void validate(AtlasEntity policy, AtlasEntity existingPolicy, } else { //only allow argo & backend - if (!RequestContext.get().isPoliciesBootstrappingInProgress()) { + if (!RequestContext.get().isSkipAuthorizationCheck()) { String userName = RequestContext.getCurrentUser(); validateOperation (!ARGO_SERVICE_USER_NAME.equals(userName) && !BACKEND_SERVICE_USER_NAME.equals(userName), "Create/Update AuthPolicy with policyCategory other than persona & purpose"); diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/ConnectionPreProcessor.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/ConnectionPreProcessor.java index f143ae9fc5..b994398c23 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/ConnectionPreProcessor.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/ConnectionPreProcessor.java @@ -142,12 +142,12 @@ private void processCreateConnection(AtlasStruct struct) throws AtlasBaseExcepti AtlasEntitiesWithExtInfo policies = transformer.transform(connection); try { - RequestContext.get().setPoliciesBootstrappingInProgress(true); + RequestContext.get().setSkipAuthorizationCheck(true); EntityStream entityStream = new AtlasEntityStream(policies); entityStore.createOrUpdate(entityStream, false); LOG.info("Created bootstrap policies for connection {}", connection.getAttribute(QUALIFIED_NAME)); } finally { - RequestContext.get().setPoliciesBootstrappingInProgress(false); + RequestContext.get().setSkipAuthorizationCheck(false); } RequestContext.get().endMetricRecord(metricRecorder); @@ -254,6 +254,7 @@ private List getConnectionPolicies(String guid, String roleNa dsl.put("query", mapOf("bool", mapOf("must", mustClauseList))); indexSearchParams.setDsl(dsl); + indexSearchParams.setSuppressLogs(true); AtlasSearchResult result = discovery.directIndexSearch(indexSearchParams); if (result != null) { diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/sql/QueryCollectionPreProcessor.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/sql/QueryCollectionPreProcessor.java index 8a4f1fe696..63e8ba4250 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/sql/QueryCollectionPreProcessor.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/preprocessor/sql/QueryCollectionPreProcessor.java @@ -28,8 +28,8 @@ import org.apache.atlas.model.instance.AtlasEntity; import org.apache.atlas.model.instance.AtlasEntityHeader; import org.apache.atlas.model.instance.AtlasStruct; -import org.apache.atlas.model.instance.EntityMutationResponse; import org.apache.atlas.model.instance.EntityMutations; +import org.apache.atlas.repository.graph.GraphHelper; import org.apache.atlas.repository.graphdb.AtlasVertex; import org.apache.atlas.repository.store.graph.AtlasEntityStore; import org.apache.atlas.repository.store.graph.v2.AtlasEntityStream; @@ -137,12 +137,12 @@ private void processCreate(AtlasStruct entity) throws AtlasBaseException { AtlasEntity.AtlasEntitiesWithExtInfo policies = transformer.transform(collection); try { - RequestContext.get().setPoliciesBootstrappingInProgress(true); + RequestContext.get().setSkipAuthorizationCheck(true); EntityStream entityStream = new AtlasEntityStream(policies); entityStore.createOrUpdate(entityStream, false); LOG.info("Created bootstrap policies for collection {}", entity.getAttribute(QUALIFIED_NAME)); } finally { - RequestContext.get().setPoliciesBootstrappingInProgress(false); + RequestContext.get().setSkipAuthorizationCheck(false); } } } finally { @@ -170,26 +170,30 @@ public void processDelete(AtlasVertex vertex) throws AtlasBaseException { AtlasPerfMetrics.MetricRecorder metricRecorder = RequestContext.get().startMetricRecord("processDeleteCollection"); try { - AtlasEntityHeader collection = entityRetriever.toAtlasEntityHeader(vertex); + AtlasEntity.Status collectionStatus = GraphHelper.getStatus(vertex); - if (!AtlasEntity.Status.ACTIVE.equals(collection.getStatus())) { + if (!AtlasEntity.Status.ACTIVE.equals(collectionStatus)) { throw new AtlasBaseException("Collection is already deleted/purged"); } if (ATLAS_AUTHORIZER_IMPL.equalsIgnoreCase(CURRENT_AUTHORIZER_IMPL)) { + String collectionGuid = GraphHelper.getGuid(vertex); + //delete collection policies - List policies = getCollectionPolicies(collection.getGuid()); - EntityMutationResponse response = entityStore.deleteByIds(policies.stream().map(x -> x.getGuid()).collect(Collectors.toList())); + List policies = getCollectionPolicies(collectionGuid); + RequestContext.get().setSkipAuthorizationCheck(true); + entityStore.deleteByIds(policies.stream().map(x -> x.getGuid()).collect(Collectors.toList())); //delete collection roles - String adminRoleName = String.format(COLL_ADMIN_ROLE_PATTERN, collection.getGuid()); - String viewerRoleName = String.format(COLL_VIEWER_ROLE_PATTERN, collection.getGuid()); + String adminRoleName = String.format(COLL_ADMIN_ROLE_PATTERN, collectionGuid); + String viewerRoleName = String.format(COLL_VIEWER_ROLE_PATTERN, collectionGuid); keycloakStore.removeRoleByName(adminRoleName); keycloakStore.removeRoleByName(viewerRoleName); } } finally { RequestContext.get().endMetricRecord(metricRecorder); + RequestContext.get().setSkipAuthorizationCheck(false); } } @@ -303,6 +307,7 @@ private List getCollectionPolicies(String guid) throws AtlasB dsl.put("query", mapOf("bool", mapOf("must", mustClauseList))); indexSearchParams.setDsl(dsl); + indexSearchParams.setSuppressLogs(true); AtlasSearchResult result = discovery.directIndexSearch(indexSearchParams); if (result != null) { diff --git a/repository/src/main/java/org/apache/atlas/repository/util/AccessControlUtils.java b/repository/src/main/java/org/apache/atlas/repository/util/AccessControlUtils.java index 0d78f511ae..0cf78c8f39 100644 --- a/repository/src/main/java/org/apache/atlas/repository/util/AccessControlUtils.java +++ b/repository/src/main/java/org/apache/atlas/repository/util/AccessControlUtils.java @@ -100,6 +100,8 @@ public final class AccessControlUtils { public static final String POLICY_CATEGORY_PURPOSE = "purpose"; public static final String POLICY_CATEGORY_BOOTSTRAP = "bootstrap"; + public static final String POLICY_SUB_CATEGORY_COLLECTION = "collection"; + public static final String POLICY_RESOURCE_CATEGORY_PERSONA_CUSTOM = "CUSTOM"; public static final String POLICY_RESOURCE_CATEGORY_PERSONA_ENTITY = "ENTITY"; public static final String POLICY_RESOURCE_CATEGORY_PURPOSE = "TAG"; diff --git a/server-api/src/main/java/org/apache/atlas/RequestContext.java b/server-api/src/main/java/org/apache/atlas/RequestContext.java index ef6df62b28..e3cbeb5d94 100644 --- a/server-api/src/main/java/org/apache/atlas/RequestContext.java +++ b/server-api/src/main/java/org/apache/atlas/RequestContext.java @@ -80,7 +80,6 @@ public class RequestContext { private int maxAttempts = 1; private int attemptCount = 1; private boolean isImportInProgress = false; - private boolean isPoliciesBootstrappingInProgress = false; private boolean isInNotificationProcessing = false; private boolean isInTypePatching = false; private boolean createShellEntityForNonExistingReference = false; @@ -94,6 +93,7 @@ public class RequestContext { private final Map relationshipEndToVertexIdMap = new HashMap<>(); private boolean allowDuplicateDisplayName; private MetricsRegistry metricsRegistry; + private boolean skipAuthorizationCheck = false; private RequestContext() { } @@ -151,8 +151,7 @@ public void clearCache() { this.relationshipEndToVertexIdMap.clear(); this.relationshipMutationMap.clear(); this.currentTask = null; - - this.isPoliciesBootstrappingInProgress = false; + this.skipAuthorizationCheck = false; if (metrics != null && !metrics.isEmpty()) { METRICS.debug(metrics.toString()); @@ -411,12 +410,12 @@ public static int getActiveRequestsCount() { return ACTIVE_REQUESTS.size(); } - public boolean isPoliciesBootstrappingInProgress() { - return isPoliciesBootstrappingInProgress; + public boolean isSkipAuthorizationCheck() { + return skipAuthorizationCheck; } - public void setPoliciesBootstrappingInProgress(boolean policiesBootstrappingInProgress) { - isPoliciesBootstrappingInProgress = policiesBootstrappingInProgress; + public void setSkipAuthorizationCheck(boolean skipAuthorizationCheck) { + this.skipAuthorizationCheck = skipAuthorizationCheck; } public static long earliestActiveRequestTime() { diff --git a/webapp/src/main/java/org/apache/atlas/web/rest/MigrationREST.java b/webapp/src/main/java/org/apache/atlas/web/rest/MigrationREST.java index 2c59fbcea5..11a56758ed 100644 --- a/webapp/src/main/java/org/apache/atlas/web/rest/MigrationREST.java +++ b/webapp/src/main/java/org/apache/atlas/web/rest/MigrationREST.java @@ -109,13 +109,13 @@ public EntityMutationResponse bootstrapConnections(AtlasEntity.AtlasEntitiesWith } AtlasEntity.AtlasEntitiesWithExtInfo policiesExtInfo = transformer.transform(entity); try { - RequestContext.get().setPoliciesBootstrappingInProgress(true); + RequestContext.get().setSkipAuthorizationCheck(true); EntityStream entityStream = new AtlasEntityStream(policiesExtInfo); EntityMutationResponse policyResponse = entityStore.createOrUpdate(entityStream, false); response.setMutatedEntities(policyResponse.getMutatedEntities()); LOG.info("Created bootstrap policies for connection"); } finally { - RequestContext.get().setPoliciesBootstrappingInProgress(false); + RequestContext.get().setSkipAuthorizationCheck(false); } } } @@ -142,14 +142,14 @@ public EntityMutationResponse bootstrapCollections(AtlasEntity.AtlasEntitiesWith //create bootstrap policies AtlasEntity.AtlasEntitiesWithExtInfo policies = transformer.transform(entity); try { - RequestContext.get().setPoliciesBootstrappingInProgress(true); + RequestContext.get().setSkipAuthorizationCheck(true); EntityStream entityStream = new AtlasEntityStream(policies); EntityMutationResponse policyResponse = entityStore.createOrUpdate(entityStream, false); response.setMutatedEntities(policyResponse.getMutatedEntities()); LOG.info("Created bootstrap policies for connection"); } finally { - RequestContext.get().setPoliciesBootstrappingInProgress(false); + RequestContext.get().setSkipAuthorizationCheck(false); } } }