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 460b454..b1a3eb5 100644 --- a/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizationUtils.java +++ b/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizationUtils.java @@ -199,6 +199,28 @@ public class AtlasAuthorizationUtils { return ret; } + public static void filterTypesDef(AtlasTypesDefFilterRequest request) { + MetricRecorder metric = RequestContext.get().startMetricRecord("filterTypesDef"); + String userName = getCurrentUserName(); + + if (StringUtils.isNotEmpty(userName) && !RequestContext.get().isImportInProgress()) { + try { + AtlasAuthorizer authorizer = AtlasAuthorizerFactory.getAtlasAuthorizer(); + + request.setUser(getCurrentUserName(), getCurrentUserGroups()); + request.setClientIPAddress(RequestContext.get().getClientIPAddress()); + request.setForwardedAddresses(RequestContext.get().getForwardedAddresses()); + request.setRemoteIPAddress(RequestContext.get().getClientIPAddress()); + + authorizer.filterTypesDef(request); + } catch (AtlasAuthorizationException e) { + LOG.error("Unable to obtain AtlasAuthorizer", e); + } + } + + RequestContext.get().endMetricRecord(metric); + } + public static List<String> getForwardedAddressesFromRequest(HttpServletRequest httpServletRequest){ String ipAddress = httpServletRequest.getHeader("X-FORWARDED-FOR"); String[] forwardedAddresses = null ; diff --git a/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizer.java b/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizer.java index 95d69e6..21b8cf9 100644 --- a/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizer.java +++ b/authorization/src/main/java/org/apache/atlas/authorize/AtlasAuthorizer.java @@ -101,4 +101,8 @@ public interface AtlasAuthorizer { entity.getMeaningNames().clear(); } } + + default + void filterTypesDef(AtlasTypesDefFilterRequest request) throws AtlasAuthorizationException { + } } diff --git a/authorization/src/main/java/org/apache/atlas/authorize/AtlasPrivilege.java b/authorization/src/main/java/org/apache/atlas/authorize/AtlasPrivilege.java index 7287b3d..9dbcd32 100644 --- a/authorization/src/main/java/org/apache/atlas/authorize/AtlasPrivilege.java +++ b/authorization/src/main/java/org/apache/atlas/authorize/AtlasPrivilege.java @@ -42,7 +42,9 @@ public enum AtlasPrivilege { ENTITY_ADD_LABEL("entity-add-label"), ENTITY_REMOVE_LABEL("entity-remove-label"), - ENTITY_UPDATE_BUSINESS_METADATA("entity-update-business-metadata"); + ENTITY_UPDATE_BUSINESS_METADATA("entity-update-business-metadata"), + + TYPE_READ("type-read"); private final String type; diff --git a/authorization/src/main/java/org/apache/atlas/authorize/AtlasTypesDefFilterRequest.java b/authorization/src/main/java/org/apache/atlas/authorize/AtlasTypesDefFilterRequest.java new file mode 100644 index 0000000..a2dc11f --- /dev/null +++ b/authorization/src/main/java/org/apache/atlas/authorize/AtlasTypesDefFilterRequest.java @@ -0,0 +1,50 @@ +/** + * 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.authorize; + +import org.apache.atlas.model.typedef.AtlasTypesDef; + +import java.util.Set; + +public class AtlasTypesDefFilterRequest extends AtlasAccessRequest { + private final AtlasTypesDef typesDef; + + + public AtlasTypesDefFilterRequest(AtlasTypesDef typesDef) { + super(AtlasPrivilege.TYPE_READ); + + this.typesDef = typesDef; + } + + public AtlasTypesDefFilterRequest(AtlasTypesDef typesDef, String userName, Set<String> usergroups) { + super(AtlasPrivilege.TYPE_READ, userName, usergroups); + + this.typesDef = typesDef; + } + + public AtlasTypesDef getTypesDef() { + return typesDef; + } + + @Override + public String toString() { + return "AtlasTypesDefFilterRequest[typesDef=" + typesDef + ", action=" + getAction() + ", accessTime=" + getAccessTime() + + ", user=" + getUser() + ", userGroups=" + getUserGroups() + ", clientIPAddress=" + getClientIPAddress() + + ", forwardedAddresses=" + getForwardedAddresses() + ", remoteIPAddress=" + getRemoteIPAddress() + "]"; + } +} diff --git a/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizer.java b/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizer.java index 7349916..5636438 100644 --- a/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizer.java +++ b/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasSimpleAuthorizer.java @@ -23,6 +23,7 @@ import java.io.InputStream; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.ListIterator; import java.util.Set; import org.apache.atlas.ApplicationProperties; @@ -32,6 +33,8 @@ import org.apache.atlas.authorize.simple.AtlasSimpleAuthzPolicy.*; import org.apache.atlas.model.discovery.AtlasSearchResult; import org.apache.atlas.model.discovery.AtlasSearchResult.AtlasFullTextResult; import org.apache.atlas.model.instance.AtlasEntityHeader; +import org.apache.atlas.model.typedef.AtlasBaseTypeDef; +import org.apache.atlas.model.typedef.AtlasTypesDef; import org.apache.atlas.utils.AtlasJson; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; @@ -39,6 +42,11 @@ import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static org.apache.atlas.authorize.AtlasPrivilege.TYPE_CREATE; +import static org.apache.atlas.authorize.AtlasPrivilege.TYPE_DELETE; +import static org.apache.atlas.authorize.AtlasPrivilege.TYPE_READ; +import static org.apache.atlas.authorize.AtlasPrivilege.TYPE_UPDATE; + public final class AtlasSimpleAuthorizer implements AtlasAuthorizer { private static final Logger LOG = LoggerFactory.getLogger(AtlasSimpleAuthorizer.class); @@ -61,6 +69,8 @@ public final class AtlasSimpleAuthorizer implements AtlasAuthorizer { inputStream = ApplicationProperties.getFileAsInputStream(ApplicationProperties.get(), "atlas.authorizer.simple.authz.policy.file", "atlas-simple-authz-policy.json"); authzPolicy = AtlasJson.fromJson(inputStream, AtlasSimpleAuthzPolicy.class); + + addImpliedTypeReadPrivilege(authzPolicy); } catch (IOException | AtlasException e) { LOG.error("SimpleAtlasAuthorizer.init(): initialization failed", e); @@ -313,6 +323,18 @@ public final class AtlasSimpleAuthorizer implements AtlasAuthorizer { } } + @Override + public void filterTypesDef(AtlasTypesDefFilterRequest request) throws AtlasAuthorizationException { + AtlasTypesDef typesDef = request.getTypesDef(); + + filterTypes(request, typesDef.getEnumDefs()); + filterTypes(request, typesDef.getStructDefs()); + filterTypes(request, typesDef.getEntityDefs()); + filterTypes(request, typesDef.getClassificationDefs()); + filterTypes(request, typesDef.getRelationshipDefs()); + filterTypes(request, typesDef.getBusinessMetadataDefs()); + } + private Set<String> getRoles(String userName, Set<String> userGroups) { Set<String> ret = new HashSet<>(); @@ -467,6 +489,46 @@ public final class AtlasSimpleAuthorizer implements AtlasAuthorizer { private boolean isBusinessMetadataMatch(AtlasEntityAccessRequest request, AtlasEntityPermission permission) { return AtlasPrivilege.ENTITY_UPDATE_BUSINESS_METADATA.equals(request.getAction()) ? isMatch(request.getBusinessMetadata(), permission.getBusinessMetadata()) : true; } + + private void filterTypes(AtlasAccessRequest request, List<? extends AtlasBaseTypeDef> typeDefs)throws AtlasAuthorizationException { + if (typeDefs != null) { + for (ListIterator<? extends AtlasBaseTypeDef> iter = typeDefs.listIterator(); iter.hasNext();) { + AtlasBaseTypeDef typeDef = iter.next(); + AtlasTypeAccessRequest typeRequest = new AtlasTypeAccessRequest(request.getAction(), typeDef, request.getUser(), request.getUserGroups()); + + typeRequest.setClientIPAddress(request.getClientIPAddress()); + typeRequest.setForwardedAddresses(request.getForwardedAddresses()); + typeRequest.setRemoteIPAddress(request.getRemoteIPAddress()); + + if (!isAccessAllowed(typeRequest)) { + iter.remove(); + } + } + } + } + + // add TYPE_READ privilege, if at least one of the following is granted: TYPE_CREATE, TYPE_UPDATE, TYPE_DELETE + private void addImpliedTypeReadPrivilege(AtlasSimpleAuthzPolicy policy) { + if (policy != null && policy.getRoles() != null) { + for (AtlasAuthzRole role : policy.getRoles().values()) { + if (role.getTypePermissions() == null) { + continue; + } + + for (AtlasTypePermission permission : role.getTypePermissions()) { + List<String> privileges = permission.getPrivileges(); + + if (CollectionUtils.isEmpty(privileges) || privileges.contains(TYPE_READ.name())) { + continue; + } + + if (privileges.contains(TYPE_CREATE.name()) || privileges.contains(TYPE_UPDATE.name()) || privileges.contains(TYPE_DELETE.name())) { + privileges.add(TYPE_READ.name()); + } + } + } + } + } } diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/AtlasTypeDefGraphStore.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/AtlasTypeDefGraphStore.java index 79f5270..0b1317a 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/AtlasTypeDefGraphStore.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/AtlasTypeDefGraphStore.java @@ -20,6 +20,10 @@ package org.apache.atlas.repository.store.graph; import org.apache.atlas.AtlasErrorCode; import org.apache.atlas.GraphTransactionInterceptor; import org.apache.atlas.annotation.GraphTransaction; +import org.apache.atlas.authorize.AtlasAuthorizationUtils; +import org.apache.atlas.authorize.AtlasPrivilege; +import org.apache.atlas.authorize.AtlasTypeAccessRequest; +import org.apache.atlas.authorize.AtlasTypesDefFilterRequest; import org.apache.atlas.exception.AtlasBaseException; import org.apache.atlas.listener.ChangedTypeDefs; import org.apache.atlas.listener.TypeDefChangeListener; @@ -120,6 +124,9 @@ public abstract class AtlasTypeDefGraphStore implements AtlasTypeDefStore { if (ret == null) { throw new AtlasBaseException(AtlasErrorCode.TYPE_NAME_NOT_FOUND, name); } + + AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_READ, ret), "read type ", name); + return ret; } @@ -129,6 +136,9 @@ public abstract class AtlasTypeDefGraphStore implements AtlasTypeDefStore { if (ret == null) { throw new AtlasBaseException(AtlasErrorCode.TYPE_GUID_NOT_FOUND, guid); } + + AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_READ, ret), "read type ", ret.getName()); + return ret; } @@ -160,6 +170,8 @@ public abstract class AtlasTypeDefGraphStore implements AtlasTypeDefStore { throw new AtlasBaseException(AtlasErrorCode.TYPE_NAME_NOT_FOUND, name); } + AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_READ, ret), "read type ", name); + return ret; } @@ -171,6 +183,8 @@ public abstract class AtlasTypeDefGraphStore implements AtlasTypeDefStore { throw new AtlasBaseException(AtlasErrorCode.TYPE_GUID_NOT_FOUND, guid); } + AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_READ, ret), "read type ", ret.getName()); + return ret; } @@ -182,6 +196,8 @@ public abstract class AtlasTypeDefGraphStore implements AtlasTypeDefStore { throw new AtlasBaseException(AtlasErrorCode.TYPE_NAME_NOT_FOUND, name); } + AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_READ, ret), "read type ", name); + return ret; } @@ -193,6 +209,8 @@ public abstract class AtlasTypeDefGraphStore implements AtlasTypeDefStore { throw new AtlasBaseException(AtlasErrorCode.TYPE_GUID_NOT_FOUND, guid); } + AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_READ, ret), "read type ", ret.getName()); + return ret; } @@ -204,6 +222,8 @@ public abstract class AtlasTypeDefGraphStore implements AtlasTypeDefStore { throw new AtlasBaseException(AtlasErrorCode.TYPE_NAME_NOT_FOUND, name); } + AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_READ, ret), "read type ", name); + return ret; } @@ -215,6 +235,8 @@ public abstract class AtlasTypeDefGraphStore implements AtlasTypeDefStore { throw new AtlasBaseException(AtlasErrorCode.TYPE_GUID_NOT_FOUND, guid); } + AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_READ, ret), "read type ", ret.getName()); + return ret; } @@ -250,6 +272,8 @@ public abstract class AtlasTypeDefGraphStore implements AtlasTypeDefStore { } } + AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_READ, ret), "read type ", name); + return ret; } @@ -261,6 +285,8 @@ public abstract class AtlasTypeDefGraphStore implements AtlasTypeDefStore { throw new AtlasBaseException(AtlasErrorCode.TYPE_GUID_NOT_FOUND, guid); } + AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_READ, ret), "read type ", ret.getName()); + return ret; } @@ -298,6 +324,8 @@ public abstract class AtlasTypeDefGraphStore implements AtlasTypeDefStore { } } + AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_READ, ret), "read type ", name); + return ret; } @@ -309,6 +337,8 @@ public abstract class AtlasTypeDefGraphStore implements AtlasTypeDefStore { throw new AtlasBaseException(AtlasErrorCode.TYPE_GUID_NOT_FOUND, guid); } + AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_READ, ret), "read type ", ret.getName()); + return ret; } @@ -722,6 +752,8 @@ public abstract class AtlasTypeDefGraphStore implements AtlasTypeDefStore { } } + AtlasAuthorizationUtils.filterTypesDef(new AtlasTypesDefFilterRequest(typesDef)); + return typesDef; } @@ -771,6 +803,11 @@ public abstract class AtlasTypeDefGraphStore implements AtlasTypeDefStore { default: throw new AtlasBaseException(AtlasErrorCode.SYSTEM_TYPE, type.getTypeCategory().name()); } + + if (ret != null) { + AtlasAuthorizationUtils.verifyAccess(new AtlasTypeAccessRequest(AtlasPrivilege.TYPE_READ, ret), "read type ", ret.getName()); + } + return ret; }