Integrate DefaultAuthorizer with PolicyEvaluator (#2017)

This commit is contained in:
Matt 2022-01-09 21:04:10 -08:00 committed by GitHub
parent ed797dc335
commit 321a0e811b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 183 additions and 52 deletions

View File

@ -27,7 +27,9 @@ import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment; import io.dropwizard.setup.Environment;
import io.federecio.dropwizard.swagger.SwaggerBundle; import io.federecio.dropwizard.swagger.SwaggerBundle;
import io.federecio.dropwizard.swagger.SwaggerBundleConfiguration; import io.federecio.dropwizard.swagger.SwaggerBundleConfiguration;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.time.temporal.ChronoUnit;
import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseFilter; import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
@ -37,6 +39,8 @@ import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
import org.glassfish.jersey.media.multipart.MultiPartFeature; import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ServerProperties; import org.glassfish.jersey.server.ServerProperties;
import org.jdbi.v3.core.Jdbi; import org.jdbi.v3.core.Jdbi;
import org.jdbi.v3.core.statement.SqlLogger;
import org.jdbi.v3.core.statement.StatementContext;
import org.openmetadata.catalog.events.EventFilter; import org.openmetadata.catalog.events.EventFilter;
import org.openmetadata.catalog.events.EventPubSub; import org.openmetadata.catalog.events.EventPubSub;
import org.openmetadata.catalog.exception.CatalogGenericExceptionMapper; import org.openmetadata.catalog.exception.CatalogGenericExceptionMapper;
@ -62,19 +66,25 @@ public class CatalogApplication extends Application<CatalogApplicationConfig> {
@Override @Override
public void run(CatalogApplicationConfig catalogConfig, Environment environment) public void run(CatalogApplicationConfig catalogConfig, Environment environment)
throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException,
InvocationTargetException { InvocationTargetException, IOException {
final JdbiFactory factory = new JdbiFactory(); final JdbiFactory factory = new JdbiFactory();
final Jdbi jdbi = factory.build(environment, catalogConfig.getDataSourceFactory(), "mysql3"); final Jdbi jdbi = factory.build(environment, catalogConfig.getDataSourceFactory(), "mysql3");
// SqlLogger sqlLogger = new SqlLogger() { SqlLogger sqlLogger =
// @Override new SqlLogger() {
// public void logAfterExecution(StatementContext context) { @Override
// LOG.info("sql {}, parameters {}, timeTaken {} ms", context.getRenderedSql(), public void logAfterExecution(StatementContext context) {
// context.getBinding().toString(), context.getElapsedTime(ChronoUnit.MILLIS)); LOG.debug(
// } "sql {}, parameters {}, timeTaken {} ms",
// }; context.getRenderedSql(),
// jdbi.setSqlLogger(sqlLogger); context.getBinding(),
context.getElapsedTime(ChronoUnit.MILLIS));
}
};
if (LOG.isDebugEnabled()) {
jdbi.setSqlLogger(sqlLogger);
}
// Register Authorizer // Register Authorizer
registerAuthorizer(catalogConfig, environment, jdbi); registerAuthorizer(catalogConfig, environment, jdbi);
@ -128,7 +138,7 @@ public class CatalogApplication extends Application<CatalogApplicationConfig> {
private void registerAuthorizer(CatalogApplicationConfig catalogConfig, Environment environment, Jdbi jdbi) private void registerAuthorizer(CatalogApplicationConfig catalogConfig, Environment environment, Jdbi jdbi)
throws NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InvocationTargetException, throws NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InvocationTargetException,
InstantiationException { InstantiationException, IOException {
AuthorizerConfiguration authorizerConf = catalogConfig.getAuthorizerConfiguration(); AuthorizerConfiguration authorizerConf = catalogConfig.getAuthorizerConfiguration();
AuthenticationConfiguration authenticationConfiguration = catalogConfig.getAuthenticationConfiguration(); AuthenticationConfiguration authenticationConfiguration = catalogConfig.getAuthenticationConfiguration();
if (authorizerConf != null) { if (authorizerConf != null) {

View File

@ -15,6 +15,7 @@ package org.openmetadata.catalog;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.text.ParseException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@ -24,13 +25,17 @@ import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.openmetadata.catalog.exception.CatalogExceptionMessage; import org.openmetadata.catalog.exception.CatalogExceptionMessage;
import org.openmetadata.catalog.exception.EntityNotFoundException; import org.openmetadata.catalog.exception.EntityNotFoundException;
import org.openmetadata.catalog.jdbi3.EntityDAO; import org.openmetadata.catalog.jdbi3.EntityDAO;
import org.openmetadata.catalog.jdbi3.EntityRepository; import org.openmetadata.catalog.jdbi3.EntityRepository;
import org.openmetadata.catalog.type.EntityReference; import org.openmetadata.catalog.type.EntityReference;
import org.openmetadata.catalog.util.EntityInterface; import org.openmetadata.catalog.util.EntityInterface;
import org.openmetadata.catalog.util.EntityUtil;
@Slf4j
public final class Entity { public final class Entity {
private static final Map<String, EntityDAO<?>> DAO_MAP = new HashMap<>(); private static final Map<String, EntityDAO<?>> DAO_MAP = new HashMap<>();
private static final Map<String, EntityRepository<?>> ENTITY_REPOSITORY_MAP = new HashMap<>(); private static final Map<String, EntityRepository<?>> ENTITY_REPOSITORY_MAP = new HashMap<>();
@ -86,7 +91,7 @@ public final class Entity {
DAO_MAP.put(entity, dao); DAO_MAP.put(entity, dao);
ENTITY_REPOSITORY_MAP.put(entity, entityRepository); ENTITY_REPOSITORY_MAP.put(entity, entityRepository);
CANONICAL_ENTITY_NAME_MAP.put(entity.toLowerCase(Locale.ROOT), entity); CANONICAL_ENTITY_NAME_MAP.put(entity.toLowerCase(Locale.ROOT), entity);
System.out.println("Registering entity " + entity); log.info("Registering entity {}", entity);
} }
public static EntityReference getEntityReference(String entity, UUID id) throws IOException { public static EntityReference getEntityReference(String entity, UUID id) throws IOException {
@ -138,12 +143,45 @@ public final class Entity {
return null; return null;
} }
String entityName = getEntityNameFromObject(entity); String entityName = getEntityNameFromObject(entity);
EntityRepository<T> entityRepository = getEntityRepository(entityName);
return entityRepository.getEntityInterface(entity);
}
/**
* Retrieve the entity using id from given entity reference and fields
*
* @return entity object eg: {@link org.openmetadata.catalog.entity.data.Table}, {@link
* org.openmetadata.catalog.entity.data.Topic}, etc
*/
public static <T> T getEntity(EntityReference entityReference, EntityUtil.Fields fields)
throws IOException, ParseException {
if (entityReference == null) {
return null;
}
EntityRepository<?> entityRepository = Entity.getEntityRepository(entityReference.getType());
@SuppressWarnings("unchecked")
T entity = (T) entityRepository.get(null, entityReference.getId().toString(), fields);
if (entity == null) {
throw EntityNotFoundException.byMessage(
CatalogExceptionMessage.entityNotFound(entityReference.getType(), entityReference.getId()));
}
return entity;
}
/**
* Retrieve the corresponding entity repository for a given entity name.
*
* @param entityName type of entity, eg: {@link Entity#TABLE}, {@link Entity#TOPIC}, etc
* @return entity repository corresponding to the entity name
*/
public static <T> EntityRepository<T> getEntityRepository(@NonNull String entityName) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
EntityRepository<T> entityRepository = (EntityRepository<T>) ENTITY_REPOSITORY_MAP.get(entityName); EntityRepository<T> entityRepository = (EntityRepository<T>) ENTITY_REPOSITORY_MAP.get(entityName);
if (entityRepository == null) { if (entityRepository == null) {
throw EntityNotFoundException.byMessage(CatalogExceptionMessage.entityTypeNotFound(entityName)); throw EntityNotFoundException.byMessage(CatalogExceptionMessage.entityTypeNotFound(entityName));
} }
return entityRepository.getEntityInterface(entity); return entityRepository;
} }
public static void deleteEntity(String entity, UUID entityId, boolean recursive) throws IOException { public static void deleteEntity(String entity, UUID entityId, boolean recursive) throws IOException {

View File

@ -15,6 +15,7 @@ package org.openmetadata.catalog.jdbi3;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -24,6 +25,7 @@ import org.openmetadata.catalog.Entity;
import org.openmetadata.catalog.entity.data.Location; import org.openmetadata.catalog.entity.data.Location;
import org.openmetadata.catalog.entity.policies.Policy; import org.openmetadata.catalog.entity.policies.Policy;
import org.openmetadata.catalog.entity.policies.accessControl.Rule; import org.openmetadata.catalog.entity.policies.accessControl.Rule;
import org.openmetadata.catalog.exception.CatalogExceptionMessage;
import org.openmetadata.catalog.resources.policies.PolicyResource; import org.openmetadata.catalog.resources.policies.PolicyResource;
import org.openmetadata.catalog.type.ChangeDescription; import org.openmetadata.catalog.type.ChangeDescription;
import org.openmetadata.catalog.type.EntityReference; import org.openmetadata.catalog.type.EntityReference;
@ -184,6 +186,33 @@ public class PolicyRepository extends EntityRepository<Policy> {
// No validation errors, if execution reaches here. // No validation errors, if execution reaches here.
} }
private List<Policy> getAccessControlPolicies() throws IOException {
EntityUtil.Fields fields = new EntityUtil.Fields(List.of("policyType", "rules"));
List<String> jsons = daoCollection.policyDAO().listAfter(null, Integer.MAX_VALUE, "");
List<Policy> policies = new ArrayList<>(jsons.size());
for (String json : jsons) {
Policy policy = setFields(JsonUtils.readValue(json, Policy.class), fields);
if (policy.getPolicyType() != PolicyType.AccessControl) {
continue;
}
policies.add(policy);
}
return policies;
}
public List<Rule> getAccessControlPolicyRules() throws IOException {
List<Policy> policies = getAccessControlPolicies();
List<Rule> rules = new ArrayList<>();
for (Policy policy : policies) {
List<Object> ruleObjects = policy.getRules();
for (Object ruleObject : ruleObjects) {
Rule rule = JsonUtils.readValue(JsonUtils.getJsonStructure(ruleObject).toString(), Rule.class);
rules.add(rule);
}
}
return rules;
}
private void setLocation(Policy policy, EntityReference location) { private void setLocation(Policy policy, EntityReference location) {
if (location == null || location.getId() == null) { if (location == null || location.getId() == null) {
return; return;
@ -334,6 +363,10 @@ public class PolicyRepository extends EntityRepository<Policy> {
@Override @Override
public void entitySpecificUpdate() throws IOException { public void entitySpecificUpdate() throws IOException {
// Disallow changing policyType.
if (original.getEntity().getPolicyType() != updated.getEntity().getPolicyType()) {
throw new IllegalArgumentException(CatalogExceptionMessage.readOnlyAttribute(Entity.POLICY, "policyType"));
}
recordChange("policyUrl", original.getEntity().getPolicyUrl(), updated.getEntity().getPolicyUrl()); recordChange("policyUrl", original.getEntity().getPolicyUrl(), updated.getEntity().getPolicyUrl());
recordChange("enabled", original.getEntity().getEnabled(), updated.getEntity().getEnabled()); recordChange("enabled", original.getEntity().getEnabled(), updated.getEntity().getEnabled());
recordChange("rules", original.getEntity().getRules(), updated.getEntity().getRules()); recordChange("rules", original.getEntity().getRules(), updated.getEntity().getRules());

View File

@ -13,13 +13,15 @@
package org.openmetadata.catalog.security; package org.openmetadata.catalog.security;
import java.io.IOException;
import org.jdbi.v3.core.Jdbi; import org.jdbi.v3.core.Jdbi;
import org.openmetadata.catalog.type.EntityReference; import org.openmetadata.catalog.type.EntityReference;
import org.openmetadata.catalog.type.MetadataOperation;
public interface Authorizer { public interface Authorizer {
/** Initialize the authorizer */ /** Initialize the authorizer */
void init(AuthorizerConfiguration config, Jdbi jdbi); void init(AuthorizerConfiguration config, Jdbi jdbi) throws IOException;
/** /**
* Check if the authenticated user has given permission on the target entity identified by the given resourceType and * Check if the authenticated user has given permission on the target entity identified by the given resourceType and
@ -27,6 +29,12 @@ public interface Authorizer {
*/ */
boolean hasPermissions(AuthenticationContext ctx, EntityReference entityReference); boolean hasPermissions(AuthenticationContext ctx, EntityReference entityReference);
/**
* Check if the authenticated user (subject) has permission to perform the {@link MetadataOperation} on the target
* entity (object).
*/
boolean hasPermissions(AuthenticationContext ctx, EntityReference entityReference, MetadataOperation operation);
boolean isAdmin(AuthenticationContext ctx); boolean isAdmin(AuthenticationContext ctx);
boolean isBot(AuthenticationContext ctx); boolean isBot(AuthenticationContext ctx);

View File

@ -19,6 +19,7 @@ import java.io.IOException;
import java.text.ParseException; import java.text.ParseException;
import java.util.Date; import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.commons.lang3.exception.ExceptionUtils;
@ -28,8 +29,11 @@ import org.openmetadata.catalog.entity.teams.User;
import org.openmetadata.catalog.exception.DuplicateEntityException; import org.openmetadata.catalog.exception.DuplicateEntityException;
import org.openmetadata.catalog.exception.EntityNotFoundException; import org.openmetadata.catalog.exception.EntityNotFoundException;
import org.openmetadata.catalog.jdbi3.CollectionDAO; import org.openmetadata.catalog.jdbi3.CollectionDAO;
import org.openmetadata.catalog.jdbi3.PolicyRepository;
import org.openmetadata.catalog.jdbi3.UserRepository; import org.openmetadata.catalog.jdbi3.UserRepository;
import org.openmetadata.catalog.security.policyevaluator.PolicyEvaluator;
import org.openmetadata.catalog.type.EntityReference; import org.openmetadata.catalog.type.EntityReference;
import org.openmetadata.catalog.type.MetadataOperation;
import org.openmetadata.catalog.util.EntityUtil; import org.openmetadata.catalog.util.EntityUtil;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -42,19 +46,22 @@ public class DefaultAuthorizer implements Authorizer {
private String principalDomain; private String principalDomain;
private UserRepository userRepository; private UserRepository userRepository;
private static final String fieldsParam = "teams"; private PolicyEvaluator policyEvaluator;
private static final String fieldsParam = "roles,teams";
@Override @Override
public void init(AuthorizerConfiguration config, Jdbi dbi) { public void init(AuthorizerConfiguration config, Jdbi dbi) throws IOException {
LOG.debug("Initializing DefaultAuthorizer with config {}", config); LOG.debug("Initializing DefaultAuthorizer with config {}", config);
this.adminUsers = new HashSet<>(config.getAdminPrincipals()); this.adminUsers = new HashSet<>(config.getAdminPrincipals());
this.botUsers = new HashSet<>(config.getBotPrincipals()); this.botUsers = new HashSet<>(config.getBotPrincipals());
this.principalDomain = config.getPrincipalDomain(); this.principalDomain = config.getPrincipalDomain();
LOG.debug("Admin users: {}", adminUsers); LOG.debug("Admin users: {}", adminUsers);
CollectionDAO repo = dbi.onDemand(CollectionDAO.class); CollectionDAO collectionDAO = dbi.onDemand(CollectionDAO.class);
this.userRepository = new UserRepository(repo); this.userRepository = new UserRepository(collectionDAO);
mayBeAddAdminUsers(); mayBeAddAdminUsers();
mayBeAddBotUsers(); mayBeAddBotUsers();
// Load all rules from access control policies at once during init.
this.policyEvaluator = new PolicyEvaluator(new PolicyRepository(collectionDAO).getAccessControlPolicyRules());
} }
private void mayBeAddAdminUsers() { private void mayBeAddAdminUsers() {
@ -104,10 +111,8 @@ public class DefaultAuthorizer implements Authorizer {
if (owner == null) { if (owner == null) {
return true; return true;
} }
String userName = SecurityUtil.getUserName(ctx);
EntityUtil.Fields fields = new EntityUtil.Fields(FIELD_LIST, fieldsParam);
try { try {
User user = userRepository.getByName(null, userName, fields); User user = getUserFromAuthenticationContext(ctx);
if (owner.getType().equals(Entity.TEAM)) { if (owner.getType().equals(Entity.TEAM)) {
for (EntityReference team : user.getTeams()) { for (EntityReference team : user.getTeams()) {
if (team.getName().equals(owner.getName())) { if (team.getName().equals(owner.getName())) {
@ -123,6 +128,20 @@ public class DefaultAuthorizer implements Authorizer {
} }
} }
@Override
public boolean hasPermissions(
AuthenticationContext ctx, EntityReference entityReference, MetadataOperation operation) {
validateAuthenticationContext(ctx);
try {
return policyEvaluator.hasPermission(
getUserFromAuthenticationContext(ctx),
Entity.getEntity(entityReference, new EntityUtil.Fields(List.of("tags"))),
operation);
} catch (IOException | EntityNotFoundException | ParseException ex) {
return false;
}
}
@Override @Override
public boolean isAdmin(AuthenticationContext ctx) { public boolean isAdmin(AuthenticationContext ctx) {
validateAuthenticationContext(ctx); validateAuthenticationContext(ctx);
@ -161,6 +180,12 @@ public class DefaultAuthorizer implements Authorizer {
} }
} }
private User getUserFromAuthenticationContext(AuthenticationContext ctx) throws IOException, ParseException {
String userName = SecurityUtil.getUserName(ctx);
EntityUtil.Fields fields = new EntityUtil.Fields(FIELD_LIST, fieldsParam);
return userRepository.getByName(null, userName, fields);
}
private void addAdmin(String name) { private void addAdmin(String name) {
User user = User user =
new User() new User()

View File

@ -15,6 +15,7 @@ package org.openmetadata.catalog.security;
import org.jdbi.v3.core.Jdbi; import org.jdbi.v3.core.Jdbi;
import org.openmetadata.catalog.type.EntityReference; import org.openmetadata.catalog.type.EntityReference;
import org.openmetadata.catalog.type.MetadataOperation;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -31,6 +32,12 @@ public class NoopAuthorizer implements Authorizer {
return true; return true;
} }
@Override
public boolean hasPermissions(
AuthenticationContext ctx, EntityReference entityReference, MetadataOperation operation) {
return true;
}
@Override @Override
public boolean isAdmin(AuthenticationContext ctx) { public boolean isAdmin(AuthenticationContext ctx) {
return true; return true;

View File

@ -20,6 +20,7 @@ import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget; import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.SecurityContext; import javax.ws.rs.core.SecurityContext;
import org.openmetadata.catalog.type.EntityReference; import org.openmetadata.catalog.type.EntityReference;
import org.openmetadata.catalog.type.MetadataOperation;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -55,6 +56,20 @@ public final class SecurityUtil {
} }
} }
public static void checkAdminRoleOrPermissions(
Authorizer authorizer,
SecurityContext securityContext,
EntityReference entityReference,
MetadataOperation metadataOperation) {
Principal principal = securityContext.getUserPrincipal();
AuthenticationContext authenticationCtx = SecurityUtil.getAuthenticationContext(principal);
if (!authorizer.isAdmin(authenticationCtx)
&& !authorizer.isBot(authenticationCtx)
&& !authorizer.hasPermissions(authenticationCtx, entityReference, metadataOperation)) {
throw new AuthorizationException("Principal: " + principal + " does not have permissions");
}
}
public static String getUserName(String principalName) { public static String getUserName(String principalName) {
return principalName == null ? null : principalName.split("[/@]")[0]; return principalName == null ? null : principalName.split("[/@]")[0];
} }

View File

@ -1,25 +1,27 @@
package org.openmetadata.catalog.security.policyevaluator; package org.openmetadata.catalog.security.policyevaluator;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import lombok.Builder; import lombok.Builder;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jeasy.rules.api.Facts; import org.jeasy.rules.api.Facts;
import org.openmetadata.catalog.Entity;
import org.openmetadata.catalog.entity.teams.User; import org.openmetadata.catalog.entity.teams.User;
import org.openmetadata.catalog.exception.EntityNotFoundException;
import org.openmetadata.catalog.type.EntityReference; import org.openmetadata.catalog.type.EntityReference;
import org.openmetadata.catalog.type.MetadataOperation; import org.openmetadata.catalog.type.MetadataOperation;
import org.openmetadata.catalog.type.TagLabel; import org.openmetadata.catalog.type.TagLabel;
import org.openmetadata.catalog.util.EntityInterface;
@Slf4j @Slf4j
@Builder(setterPrefix = "with") @Builder(setterPrefix = "with")
class AttributeBasedFacts { class AttributeBasedFacts {
private User user; @NonNull private User user;
private Object entity; @NonNull private Object entity;
private MetadataOperation operation; @NonNull private MetadataOperation operation;
// Do not allow anything external or the builder itself change the value of facts. // Do not allow anything external or the builder itself change the value of facts.
// Individual Fact(s) within facts may be changed by the RulesEngine. // Individual Fact(s) within facts may be changed by the RulesEngine.
@ -29,10 +31,7 @@ class AttributeBasedFacts {
* Creates {@link Facts} with the operation, user (subject) and entity (object) attributes so that it is recognizable * Creates {@link Facts} with the operation, user (subject) and entity (object) attributes so that it is recognizable
* by {@link org.jeasy.rules.api.RulesEngine} * by {@link org.jeasy.rules.api.RulesEngine}
*/ */
public Facts getFacts() throws RuntimeException { public Facts getFacts() {
if (!validate()) {
throw new RuntimeException("Validation failed while building facts");
}
facts.put(CommonFields.USER_ROLES, getUserRoles(user)); facts.put(CommonFields.USER_ROLES, getUserRoles(user));
facts.put(CommonFields.ENTITY_TAGS, getEntityTags(entity)); facts.put(CommonFields.ENTITY_TAGS, getEntityTags(entity));
facts.put(CommonFields.ENTITY_TYPE, getEntityType(entity)); facts.put(CommonFields.ENTITY_TYPE, getEntityType(entity));
@ -46,35 +45,29 @@ class AttributeBasedFacts {
return facts.get(CommonFields.ALLOW); return facts.get(CommonFields.ALLOW);
} }
private List<String> getUserRoles(User user) { private List<String> getUserRoles(@NonNull User user) {
// TODO: Fix this to fetch user's roles when roles is added as entity reference list from user schema. return user.getRoles().stream().map(EntityReference::getName).collect(Collectors.toList());
return user.getTeams().stream().map(EntityReference::getName).collect(Collectors.toList());
} }
private List<String> getEntityTags(Object entity) { private List<String> getEntityTags(@NonNull Object entity) {
// TODO: Fix the entityType fetch such that it is fetched from Repository or using a Util. List<TagLabel> entityTags = null;
// This is done here now to facilitate prototyping and unit testing.
List<TagLabel> entityTags = Collections.emptyList();
try { try {
entityTags = (List<TagLabel>) entity.getClass().getMethod("getTags").invoke(entity); EntityInterface<?> entityInterface = Entity.getEntityInterface(entity);
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) { entityTags = entityInterface.getTags();
log.warn("Could not obtain tags for entity with class {}", entity.getClass()); } catch (EntityNotFoundException e) {
log.warn("could not obtain tags for the given entity {} - exception: {}", entity, e.toString());
}
if (entityTags == null) {
return Collections.emptyList();
} }
return entityTags.stream().map(TagLabel::getTagFQN).collect(Collectors.toList()); return entityTags.stream().map(TagLabel::getTagFQN).collect(Collectors.toList());
} }
private static String getEntityType(Object object) { private static String getEntityType(@NonNull Object entity) {
// TODO: Fix the entityType fetch such that it is fetched from Repository or using a Util. String entityType = Entity.getEntityNameFromObject(entity);
// This is done here now to facilitate prototyping and unit testing. if (entityType == null) {
return object.getClass().getSimpleName().toLowerCase(Locale.ROOT); log.warn("could not find entity type for the given entity {}", entity);
} }
return entityType;
private boolean validate() {
log.debug(
"Validating attribute based facts - user: {}, entity: {}, operation: {}",
this.user,
this.entity,
this.operation);
return this.user != null && this.entity != null && this.operation != null;
} }
} }

View File

@ -27,6 +27,7 @@ import java.util.function.BiPredicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.ws.rs.WebApplicationException; import javax.ws.rs.WebApplicationException;
import lombok.RequiredArgsConstructor;
import org.joda.time.Period; import org.joda.time.Period;
import org.joda.time.format.ISOPeriodFormat; import org.joda.time.format.ISOPeriodFormat;
import org.openmetadata.catalog.Entity; import org.openmetadata.catalog.Entity;
@ -391,6 +392,7 @@ public final class EntityUtil {
return followers; return followers;
} }
@RequiredArgsConstructor
public static class Fields { public static class Fields {
public static final Fields EMPTY_FIELDS = new Fields(null, null); public static final Fields EMPTY_FIELDS = new Fields(null, null);
private final List<String> fieldList; private final List<String> fieldList;