Skip to content

Commit

Permalink
Merge branch 'master' of github.com:linkedin/datahub into disable-ci-…
Browse files Browse the repository at this point in the history
…telemetry
  • Loading branch information
kevinhu committed Mar 29, 2022
2 parents fa7ecee + df69e76 commit 0fa6a97
Show file tree
Hide file tree
Showing 143 changed files with 24,522 additions and 1,018 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import com.linkedin.datahub.graphql.generated.MLPrimaryKeyProperties;
import com.linkedin.datahub.graphql.generated.Notebook;
import com.linkedin.datahub.graphql.generated.Owner;
import com.linkedin.datahub.graphql.generated.PolicyMatchCriterionValue;
import com.linkedin.datahub.graphql.generated.RecommendationContent;
import com.linkedin.datahub.graphql.generated.SearchAcrossLineageResult;
import com.linkedin.datahub.graphql.generated.SearchResult;
Expand Down Expand Up @@ -73,6 +74,7 @@
import com.linkedin.datahub.graphql.resolvers.group.ListGroupsResolver;
import com.linkedin.datahub.graphql.resolvers.group.RemoveGroupMembersResolver;
import com.linkedin.datahub.graphql.resolvers.group.RemoveGroupResolver;
import com.linkedin.datahub.graphql.resolvers.policy.GetGrantedPrivilegesResolver;
import com.linkedin.datahub.graphql.resolvers.ingest.execution.CancelIngestionExecutionRequestResolver;
import com.linkedin.datahub.graphql.resolvers.ingest.execution.CreateIngestionExecutionRequestResolver;
import com.linkedin.datahub.graphql.resolvers.ingest.execution.GetIngestionExecutionRequestResolver;
Expand Down Expand Up @@ -606,6 +608,7 @@ private void configureQueryResolvers(final RuntimeWiring.Builder builder) {
(env) -> env.getArgument(URN_FIELD_NAME))))
.dataFetcher("listPolicies",
new ListPoliciesResolver(this.entityClient))
.dataFetcher("getGrantedPrivileges", new GetGrantedPrivilegesResolver())
.dataFetcher("listUsers",
new ListUsersResolver(this.entityClient))
.dataFetcher("listGroups",
Expand Down Expand Up @@ -751,8 +754,14 @@ private void configureGenericEntityResolvers(final RuntimeWiring.Builder builder
new EntityTypeBatchResolver(
new ArrayList<>(entityTypes),
(env) -> ((AutoCompleteResultForEntity) env.getSource()).getEntities()))
)
.type("PolicyMatchCriterionValue", typeWiring -> typeWiring
.dataFetcher("entity", new AuthenticatedResolver<>(
new EntityTypeResolver(
new ArrayList<>(entityTypes),
(env) -> ((PolicyMatchCriterionValue) env.getSource()).getEntity()))
)
);
;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,25 @@
public class AuthorizationUtils {

public static boolean canManageUsersAndGroups(@Nonnull QueryContext context) {
final Authorizer authorizer = context.getAuthorizer();
final String actor = context.getActorUrn();
final ConjunctivePrivilegeGroup andGroup = new ConjunctivePrivilegeGroup(ImmutableList.of(PoliciesConfig.MANAGE_USERS_AND_GROUPS_PRIVILEGE.getType()));
return isAuthorized(authorizer, actor, new DisjunctivePrivilegeGroup(ImmutableList.of(andGroup)));
return isAuthorized(context, Optional.empty(), PoliciesConfig.MANAGE_USERS_AND_GROUPS_PRIVILEGE);
}

public static boolean canGeneratePersonalAccessToken(@Nonnull QueryContext context) {
final Authorizer authorizer = context.getAuthorizer();
final String actor = context.getActorUrn();
final ConjunctivePrivilegeGroup andGroup = new ConjunctivePrivilegeGroup(
ImmutableList.of(PoliciesConfig.GENERATE_PERSONAL_ACCESS_TOKENS_PRIVILEGE.getType()));
return isAuthorized(authorizer, actor, new DisjunctivePrivilegeGroup(ImmutableList.of(andGroup)));
return isAuthorized(context, Optional.empty(), PoliciesConfig.GENERATE_PERSONAL_ACCESS_TOKENS_PRIVILEGE);
}

public static boolean canManageDomains(@Nonnull QueryContext context) {
return isAuthorized(context, Optional.empty(), PoliciesConfig.MANAGE_DOMAINS_PRIVILEGE);
}

public static boolean isAuthorized(
@Nonnull QueryContext context,
@Nonnull Optional<ResourceSpec> resourceSpec,
@Nonnull PoliciesConfig.Privilege privilege) {
final Authorizer authorizer = context.getAuthorizer();
final String actor = context.getActorUrn();
final ConjunctivePrivilegeGroup andGroup = new ConjunctivePrivilegeGroup(ImmutableList.of(PoliciesConfig.MANAGE_DOMAINS_PRIVILEGE.getType()));
return isAuthorized(authorizer, actor, new DisjunctivePrivilegeGroup(ImmutableList.of(andGroup)));
final ConjunctivePrivilegeGroup andGroup = new ConjunctivePrivilegeGroup(ImmutableList.of(privilege.getType()));
return isAuthorized(authorizer, actor, resourceSpec, new DisjunctivePrivilegeGroup(ImmutableList.of(andGroup)));
}

public static boolean isAuthorized(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
package com.linkedin.datahub.graphql.resolvers.load;

import com.datahub.authorization.ResourceSpec;
import com.linkedin.datahub.graphql.QueryContext;
import com.linkedin.datahub.graphql.authorization.AuthorizationUtils;
import com.linkedin.datahub.graphql.generated.Entity;
import com.linkedin.datahub.graphql.generated.TimeSeriesAspect;
import com.linkedin.entity.client.EntityClient;
import com.linkedin.metadata.Constants;
import com.linkedin.metadata.aspect.EnvelopedAspect;
import com.linkedin.metadata.authorization.PoliciesConfig;
import com.linkedin.r2.RemoteInvocationException;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -42,6 +48,18 @@ public TimeSeriesAspectResolver(final EntityClient client, final String entityNa
_aspectMapper = aspectMapper;
}

/**
* Check whether the actor is authorized to fetch the timeseries aspect given the resource urn
*/
private boolean isAuthorized(QueryContext context, String urn) {
if (_entityName.equals(Constants.DATASET_ENTITY_NAME) && _aspectName.equals(
Constants.DATASET_PROFILE_ASPECT_NAME)) {
return AuthorizationUtils.isAuthorized(context, Optional.of(new ResourceSpec(_entityName, urn)),
PoliciesConfig.VIEW_DATASET_PROFILE_PRIVILEGE);
}
return true;
}

@Override
public CompletableFuture<List<TimeSeriesAspect>> get(DataFetchingEnvironment environment) {
return CompletableFuture.supplyAsync(() -> {
Expand All @@ -50,6 +68,11 @@ public CompletableFuture<List<TimeSeriesAspect>> get(DataFetchingEnvironment env
// Fetch the urn, assuming the parent has an urn field.
// todo: what if the parent urn isn't projected?
final String urn = ((Entity) environment.getSource()).getUrn();

if (!isAuthorized(context, urn)) {
return Collections.emptyList();
}

final Long maybeStartTimeMillis = environment.getArgumentOrDefault("startTimeMillis", null);
final Long maybeEndTimeMillis = environment.getArgumentOrDefault("endTimeMillis", null);
// Max number of aspects to return.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.linkedin.datahub.graphql.resolvers.policy;

import com.datahub.authorization.AuthorizationManager;
import com.datahub.authorization.ResourceSpec;
import com.linkedin.datahub.graphql.QueryContext;
import com.linkedin.datahub.graphql.exception.AuthorizationException;
import com.linkedin.datahub.graphql.generated.GetGrantedPrivilegesInput;
import com.linkedin.datahub.graphql.generated.Privileges;
import com.linkedin.datahub.graphql.resolvers.EntityTypeMapper;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;

import static com.linkedin.datahub.graphql.resolvers.ResolverUtils.bindArgument;


/**
* Resolver to support the getGrantedPrivileges end point
* Fetches all privileges that are granted for the given actor for the given resource (optional)
*/
public class GetGrantedPrivilegesResolver implements DataFetcher<CompletableFuture<Privileges>> {

@Override
public CompletableFuture<Privileges> get(final DataFetchingEnvironment environment) throws Exception {

final QueryContext context = environment.getContext();
final GetGrantedPrivilegesInput input =
bindArgument(environment.getArgument("input"), GetGrantedPrivilegesInput.class);
final String actor = input.getActorUrn();
if (!isAuthorized(context, actor)) {
throw new AuthorizationException("Unauthorized to get privileges for the given author.");
}
final Optional<ResourceSpec> resourceSpec = Optional.ofNullable(input.getResourceSpec())
.map(spec -> new ResourceSpec(EntityTypeMapper.getName(spec.getResourceType()), spec.getResourceUrn()));

if (context.getAuthorizer() instanceof AuthorizationManager) {
AuthorizationManager authorizationManager = (AuthorizationManager) context.getAuthorizer();
List<String> privileges = authorizationManager.getGrantedPrivileges(actor, resourceSpec);
return CompletableFuture.supplyAsync(() -> Privileges.builder()
.setPrivileges(privileges)
.build());
}
throw new UnsupportedOperationException(
String.format("GetGrantedPrivileges function is not supported on authorizer of type %s",
context.getAuthorizer().getClass().getSimpleName()));
}

private boolean isAuthorized(final QueryContext context, final String actor) {
return actor.equals(context.getActorUrn());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,27 @@
import com.linkedin.common.urn.Urn;
import com.linkedin.datahub.graphql.generated.ActorFilter;
import com.linkedin.datahub.graphql.generated.Policy;
import com.linkedin.datahub.graphql.generated.PolicyMatchCondition;
import com.linkedin.datahub.graphql.generated.PolicyMatchCriterion;
import com.linkedin.datahub.graphql.generated.PolicyMatchCriterionValue;
import com.linkedin.datahub.graphql.generated.PolicyMatchFilter;
import com.linkedin.datahub.graphql.generated.PolicyState;
import com.linkedin.datahub.graphql.generated.PolicyType;
import com.linkedin.datahub.graphql.generated.ResourceFilter;
import com.linkedin.datahub.graphql.types.common.mappers.UrnToEntityMapper;
import com.linkedin.datahub.graphql.types.mappers.ModelMapper;
import com.linkedin.policy.DataHubActorFilter;
import com.linkedin.policy.DataHubPolicyInfo;
import com.linkedin.policy.DataHubResourceFilter;
import java.net.URISyntaxException;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;


/**
* Maps {@link com.linkedin.policy.DataHubPolicyInfo} to GraphQL {@link com.linkedin.datahub.graphql.generated.Policy}.
*/
public class PolicyInfoPolicyMapper implements ModelMapper<DataHubPolicyInfo, Policy> {
public class PolicyInfoPolicyMapper implements ModelMapper<DataHubPolicyInfo, Policy> {

public static final PolicyInfoPolicyMapper INSTANCE = new PolicyInfoPolicyMapper();

Expand Down Expand Up @@ -48,16 +54,10 @@ private ActorFilter mapActors(final DataHubActorFilter actorFilter) {
result.setAllUsers(actorFilter.isAllUsers());
result.setResourceOwners(actorFilter.isResourceOwners());
if (actorFilter.hasGroups()) {
result.setGroups(actorFilter.getGroups()
.stream()
.map(Urn::toString)
.collect(Collectors.toList()));
result.setGroups(actorFilter.getGroups().stream().map(Urn::toString).collect(Collectors.toList()));
}
if (actorFilter.hasUsers()) {
result.setUsers(actorFilter.getUsers()
.stream()
.map(Urn::toString)
.collect(Collectors.toList()));
result.setUsers(actorFilter.getUsers().stream().map(Urn::toString).collect(Collectors.toList()));
}
return result;
}
Expand All @@ -71,7 +71,33 @@ private ResourceFilter mapResources(final DataHubResourceFilter resourceFilter)
if (resourceFilter.hasResources()) {
result.setResources(resourceFilter.getResources());
}
if (resourceFilter.hasFilter()) {
result.setFilter(mapFilter(resourceFilter.getFilter()));
}
return result;
}

private PolicyMatchFilter mapFilter(final com.linkedin.policy.PolicyMatchFilter filter) {
return PolicyMatchFilter.builder()
.setCriteria(filter.getCriteria()
.stream()
.map(criterion -> PolicyMatchCriterion.builder()
.setField(criterion.getField())
.setValues(criterion.getValues().stream().map(this::mapValue).collect(Collectors.toList()))
.setCondition(PolicyMatchCondition.valueOf(criterion.getCondition().name()))
.build())
.collect(Collectors.toList()))
.build();
}

private PolicyMatchCriterionValue mapValue(final String value) {
try {
// If value is urn, set entity field
Urn urn = Urn.createFromString(value);
return PolicyMatchCriterionValue.builder().setValue(value).setEntity(UrnToEntityMapper.map(urn)).build();
} catch (URISyntaxException e) {
// Value is not an urn. Just set value
return PolicyMatchCriterionValue.builder().setValue(value).build();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,22 @@
import com.linkedin.common.urn.Urn;
import com.linkedin.data.template.StringArray;
import com.linkedin.datahub.graphql.generated.ActorFilterInput;
import com.linkedin.datahub.graphql.generated.PolicyMatchFilterInput;
import com.linkedin.datahub.graphql.generated.PolicyUpdateInput;
import com.linkedin.datahub.graphql.generated.ResourceFilterInput;
import com.linkedin.datahub.graphql.types.mappers.ModelMapper;
import com.linkedin.policy.DataHubActorFilter;
import com.linkedin.policy.DataHubPolicyInfo;
import com.linkedin.policy.DataHubResourceFilter;
import com.linkedin.policy.PolicyMatchCondition;
import com.linkedin.policy.PolicyMatchCriterion;
import com.linkedin.policy.PolicyMatchCriterionArray;
import com.linkedin.policy.PolicyMatchFilter;
import java.net.URISyntaxException;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;


/**
* Maps GraphQL {@link PolicyUpdateInput} to DataHub backend {@link DataHubPolicyInfo}.
*/
Expand Down Expand Up @@ -46,32 +52,42 @@ private DataHubActorFilter mapActors(final ActorFilterInput actorInput) {
result.setAllUsers(actorInput.getAllUsers());
result.setResourceOwners(actorInput.getResourceOwners());
if (actorInput.getGroups() != null) {
result.setGroups(new UrnArray(actorInput.getGroups()
.stream()
.map(this::createUrn)
.collect(Collectors.toList())));
result.setGroups(new UrnArray(actorInput.getGroups().stream().map(this::createUrn).collect(Collectors.toList())));
}
if (actorInput.getUsers() != null) {
result.setUsers(new UrnArray(actorInput.getUsers()
.stream()
.map(this::createUrn)
.collect(Collectors.toList())));
result.setUsers(new UrnArray(actorInput.getUsers().stream().map(this::createUrn).collect(Collectors.toList())));
}
return result;
}

private DataHubResourceFilter mapResources(final ResourceFilterInput resourceInput) {
final DataHubResourceFilter result = new DataHubResourceFilter();
if (resourceInput.getAllResources() != null) {
result.setAllResources(resourceInput.getAllResources());
}
// This is an implicit mapping between GQL EntityType and Entity Name as known by GMS.
// Be careful about maintaining this contract.
result.setType(resourceInput.getType());
result.setAllResources(resourceInput.getAllResources());
if (resourceInput.getType() != null) {
result.setType(resourceInput.getType());
}
if (resourceInput.getResources() != null) {
result.setResources(new StringArray(resourceInput.getResources()));
}
if (resourceInput.getFilter() != null) {
result.setFilter(mapFilter(resourceInput.getFilter()));
}
return result;
}

private PolicyMatchFilter mapFilter(final PolicyMatchFilterInput filter) {
return new PolicyMatchFilter().setCriteria(new PolicyMatchCriterionArray(filter.getCriteria()
.stream()
.map(criterion -> new PolicyMatchCriterion().setField(criterion.getField())
.setValues(new StringArray(criterion.getValues()))
.setCondition(PolicyMatchCondition.valueOf(criterion.getCondition().name())))
.collect(Collectors.toList())));
}

private Urn createUrn(String urnStr) {
try {
return Urn.createFromString(urnStr);
Expand Down
Loading

0 comments on commit 0fa6a97

Please sign in to comment.