diff --git a/metadata-service/auth-api/src/main/java/com/datahub/authorization/Authorizer.java b/metadata-service/auth-api/src/main/java/com/datahub/authorization/Authorizer.java index c92aad8b2b..2f662cff7b 100644 --- a/metadata-service/auth-api/src/main/java/com/datahub/authorization/Authorizer.java +++ b/metadata-service/auth-api/src/main/java/com/datahub/authorization/Authorizer.java @@ -15,12 +15,12 @@ public interface Authorizer { * @param authorizerConfig config provided to the authenticator derived from the Metadata Service YAML config. This * config comes from the "authorization.authorizers.config" configuration. */ - void init(@Nonnull final Map authorizerConfig); + void init(@Nonnull final Map authorizerConfig, @Nonnull final AuthorizerContext ctx); /** * Authorizes an action based on the actor, the resource, & required privileges. */ - AuthorizationResult authorize(AuthorizationRequest request); + AuthorizationResult authorize(@Nonnull final AuthorizationRequest request); /** * Retrieves the current list of actors authorized to for a particular privilege against diff --git a/metadata-service/auth-api/src/main/java/com/datahub/authorization/AuthorizerContext.java b/metadata-service/auth-api/src/main/java/com/datahub/authorization/AuthorizerContext.java new file mode 100644 index 0000000000..65c0c08a21 --- /dev/null +++ b/metadata-service/auth-api/src/main/java/com/datahub/authorization/AuthorizerContext.java @@ -0,0 +1,17 @@ +package com.datahub.authorization; + +import lombok.AllArgsConstructor; +import lombok.Data; + + +/** + * Context provided to an Authorizer on initialization. + */ +@Data +@AllArgsConstructor +public class AuthorizerContext { + /** + * A utility for resolving a {@link ResourceSpec} to resolved resource field values. + */ + private ResourceSpecResolver resourceSpecResolver; +} diff --git a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/FieldResolver.java b/metadata-service/auth-api/src/main/java/com/datahub/authorization/FieldResolver.java similarity index 100% rename from metadata-service/auth-impl/src/main/java/com/datahub/authorization/FieldResolver.java rename to metadata-service/auth-api/src/main/java/com/datahub/authorization/FieldResolver.java diff --git a/metadata-service/auth-api/src/main/java/com/datahub/authorization/ResolvedResourceSpec.java b/metadata-service/auth-api/src/main/java/com/datahub/authorization/ResolvedResourceSpec.java new file mode 100644 index 0000000000..b4fb001ac8 --- /dev/null +++ b/metadata-service/auth-api/src/main/java/com/datahub/authorization/ResolvedResourceSpec.java @@ -0,0 +1,66 @@ +package com.datahub.authorization; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import javax.annotation.Nullable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + + +/** + * Wrapper around authorization request with field resolvers for lazily fetching the field values for each field type + */ +@RequiredArgsConstructor +public class ResolvedResourceSpec { + @Getter + private final ResourceSpec spec; + private final Map fieldResolvers; + + public Set getFieldValues(ResourceFieldType resourceFieldType) { + if (!fieldResolvers.containsKey(resourceFieldType)) { + return Collections.emptySet(); + } + return fieldResolvers.get(resourceFieldType).getFieldValuesFuture().join().getValues(); + } + + /** + * Fetch the entity-registry type for a resource. ('dataset', 'dashboard', 'chart'). + * @return the entity type. + */ + public String getType() { + if (!fieldResolvers.containsKey(ResourceFieldType.RESOURCE_TYPE)) { + throw new UnsupportedOperationException("Failed to resolve resource type! No field resolver for RESOURCE_TYPE provided."); + } + Set resourceTypes = fieldResolvers.get(ResourceFieldType.RESOURCE_TYPE).getFieldValuesFuture().join().getValues(); + assert resourceTypes.size() == 1; // There should always be a single resource type. + return resourceTypes.stream().findFirst().get(); + } + + /** + * Fetch the owners for a resource. + * @return a set of owner urns, or empty set if none exist. + */ + public Set getOwners() { + if (!fieldResolvers.containsKey(ResourceFieldType.OWNER)) { + return Collections.emptySet(); + } + return fieldResolvers.get(ResourceFieldType.OWNER).getFieldValuesFuture().join().getValues(); + } + + /** + * Fetch the domain for a Resolved Resource Spec + * @return a Domain or null if one does not exist. + */ + @Nullable + public String getDomain() { + if (!fieldResolvers.containsKey(ResourceFieldType.DOMAIN)) { + return null; + } + Set domains = fieldResolvers.get(ResourceFieldType.DOMAIN).getFieldValuesFuture().join().getValues(); + if (domains.size() > 0) { + return domains.stream().findFirst().get(); + } + return null; + } +} diff --git a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/fieldresolverprovider/ResourceFieldType.java b/metadata-service/auth-api/src/main/java/com/datahub/authorization/ResourceFieldType.java similarity index 84% rename from metadata-service/auth-impl/src/main/java/com/datahub/authorization/fieldresolverprovider/ResourceFieldType.java rename to metadata-service/auth-api/src/main/java/com/datahub/authorization/ResourceFieldType.java index 856f4df7db..ee54d2bfbb 100644 --- a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/fieldresolverprovider/ResourceFieldType.java +++ b/metadata-service/auth-api/src/main/java/com/datahub/authorization/ResourceFieldType.java @@ -1,4 +1,4 @@ -package com.datahub.authorization.fieldresolverprovider; +package com.datahub.authorization; /** * List of resource field types to fetch for a given resource diff --git a/metadata-service/auth-api/src/main/java/com/datahub/authorization/ResourceSpecResolver.java b/metadata-service/auth-api/src/main/java/com/datahub/authorization/ResourceSpecResolver.java new file mode 100644 index 0000000000..05c35f377b --- /dev/null +++ b/metadata-service/auth-api/src/main/java/com/datahub/authorization/ResourceSpecResolver.java @@ -0,0 +1,11 @@ +package com.datahub.authorization; + +/** + * A Resource Spec Resolver is responsible for resolving a {@link ResourceSpec} to a {@link ResolvedResourceSpec}. + */ +public interface ResourceSpecResolver { + /** + Resolve a {@link ResourceSpec} to a resolved resource spec. + **/ + ResolvedResourceSpec resolve(ResourceSpec resourceSpec); +} diff --git a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/AuthorizerChain.java b/metadata-service/auth-impl/src/main/java/com/datahub/authorization/AuthorizerChain.java index c06adf37bd..f66092bc52 100644 --- a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/AuthorizerChain.java +++ b/metadata-service/auth-impl/src/main/java/com/datahub/authorization/AuthorizerChain.java @@ -30,7 +30,7 @@ public class AuthorizerChain implements Authorizer { } @Override - public void init(@Nonnull Map authorizerConfig) { + public void init(@Nonnull Map authorizerConfig, @Nonnull AuthorizerContext ctx) { // pass. } diff --git a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/DataHubAuthorizer.java b/metadata-service/auth-impl/src/main/java/com/datahub/authorization/DataHubAuthorizer.java index ddbf696269..6c53b37110 100644 --- a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/DataHubAuthorizer.java +++ b/metadata-service/auth-impl/src/main/java/com/datahub/authorization/DataHubAuthorizer.java @@ -2,8 +2,6 @@ package com.datahub.authorization; import com.datahub.authentication.Authentication; import com.google.common.annotations.VisibleForTesting; -import com.linkedin.common.Owner; -import com.linkedin.common.Ownership; import com.linkedin.common.urn.Urn; import com.linkedin.common.urn.UrnUtils; import com.linkedin.entity.client.EntityClient; @@ -13,18 +11,15 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; import javax.annotation.Nonnull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import static com.linkedin.metadata.Constants.CORP_GROUP_ENTITY_NAME; -import static com.linkedin.metadata.Constants.CORP_USER_ENTITY_NAME; - /** * The Authorizer is a singleton class responsible for authorizing @@ -43,13 +38,12 @@ public class DataHubAuthorizer implements Authorizer { */ DEFAULT, /** - * Allow all means that the AuthorizationManager will allow all actions. This is used as an override to disable the + * Allow all means that the DataHubAuthorizer will allow all actions. This is used as an override to disable the * policies feature. */ ALLOW_ALL } - // Credentials used to make / authorize requests as the internal system actor. private final Authentication _systemAuthentication; @@ -59,9 +53,8 @@ public class DataHubAuthorizer implements Authorizer { private final ScheduledExecutorService _refreshExecutorService = Executors.newScheduledThreadPool(1); private final PolicyRefreshRunnable _policyRefreshRunnable; - - private final ResourceSpecResolver _resourceSpecResolver; private final PolicyEngine _policyEngine; + private ResourceSpecResolver _resourceSpecResolver; private AuthorizationMode _mode; public static final String ALL = "ALL"; @@ -72,20 +65,20 @@ public class DataHubAuthorizer implements Authorizer { final int delayIntervalSeconds, final int refreshIntervalSeconds, final AuthorizationMode mode) { - _systemAuthentication = systemAuthentication; + _systemAuthentication = Objects.requireNonNull(systemAuthentication); + _mode = Objects.requireNonNull(mode); + _policyEngine = new PolicyEngine(systemAuthentication, Objects.requireNonNull(entityClient)); _policyRefreshRunnable = new PolicyRefreshRunnable(systemAuthentication, new PolicyFetcher(entityClient), _policyCache); _refreshExecutorService.scheduleAtFixedRate(_policyRefreshRunnable, delayIntervalSeconds, refreshIntervalSeconds, TimeUnit.SECONDS); - _mode = mode; - _resourceSpecResolver = new ResourceSpecResolver(systemAuthentication, entityClient); - _policyEngine = new PolicyEngine(systemAuthentication, entityClient); } @Override - public void init(@Nonnull Map authorizerConfig) { + public void init(@Nonnull Map authorizerConfig, @Nonnull AuthorizerContext ctx) { // Pass. No static config. + _resourceSpecResolver = Objects.requireNonNull(ctx.getResourceSpecResolver()); } - public AuthorizationResult authorize(final AuthorizationRequest request) { + public AuthorizationResult authorize(@Nonnull final AuthorizationRequest request) { // 0. Short circuit: If the action is being performed by the system (root), always allow it. if (isSystemRequest(request, this._systemAuthentication)) { @@ -265,20 +258,4 @@ public class DataHubAuthorizer implements Authorizer { cache.put(ALL, existingPolicies); } } - - private List userOwners(final Ownership ownership) { - return ownership.getOwners() - .stream() - .filter(owner -> CORP_USER_ENTITY_NAME.equals(owner.getOwner().getEntityType())) - .map(Owner::getOwner) - .collect(Collectors.toList()); - } - - private List groupOwners(final Ownership ownership) { - return ownership.getOwners() - .stream() - .filter(owner -> CORP_GROUP_ENTITY_NAME.equals(owner.getOwner().getEntityType())) - .map(Owner::getOwner) - .collect(Collectors.toList()); - } } diff --git a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/ResourceSpecResolver.java b/metadata-service/auth-impl/src/main/java/com/datahub/authorization/DefaultResourceSpecResolver.java similarity index 82% rename from metadata-service/auth-impl/src/main/java/com/datahub/authorization/ResourceSpecResolver.java rename to metadata-service/auth-impl/src/main/java/com/datahub/authorization/DefaultResourceSpecResolver.java index e0a0ff3375..051ba1d8db 100644 --- a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/ResourceSpecResolver.java +++ b/metadata-service/auth-impl/src/main/java/com/datahub/authorization/DefaultResourceSpecResolver.java @@ -4,7 +4,6 @@ import com.datahub.authentication.Authentication; import com.datahub.authorization.fieldresolverprovider.DomainFieldResolverProvider; import com.datahub.authorization.fieldresolverprovider.EntityTypeFieldResolverProvider; import com.datahub.authorization.fieldresolverprovider.EntityUrnFieldResolverProvider; -import com.datahub.authorization.fieldresolverprovider.ResourceFieldType; import com.datahub.authorization.fieldresolverprovider.OwnerFieldResolverProvider; import com.datahub.authorization.fieldresolverprovider.ResourceFieldResolverProvider; import com.google.common.collect.ImmutableList; @@ -14,21 +13,22 @@ import java.util.Map; import java.util.stream.Collectors; -public class ResourceSpecResolver { +public class DefaultResourceSpecResolver implements ResourceSpecResolver { private final List _resourceFieldResolverProviders; - public ResourceSpecResolver(Authentication systemAuthentication, EntityClient entityClient) { + public DefaultResourceSpecResolver(Authentication systemAuthentication, EntityClient entityClient) { _resourceFieldResolverProviders = ImmutableList.of(new EntityTypeFieldResolverProvider(), new EntityUrnFieldResolverProvider(), new DomainFieldResolverProvider(entityClient, systemAuthentication), new OwnerFieldResolverProvider(entityClient, systemAuthentication)); } + @Override public ResolvedResourceSpec resolve(ResourceSpec resourceSpec) { return new ResolvedResourceSpec(resourceSpec, getFieldResolvers(resourceSpec)); } - public Map getFieldResolvers(ResourceSpec resourceSpec) { + private Map getFieldResolvers(ResourceSpec resourceSpec) { return _resourceFieldResolverProviders.stream() .collect(Collectors.toMap(ResourceFieldResolverProvider::getFieldType, hydrator -> hydrator.getFieldResolver(resourceSpec))); diff --git a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/FilterUtils.java b/metadata-service/auth-impl/src/main/java/com/datahub/authorization/FilterUtils.java index 70e2f093a0..76ed18e2ba 100644 --- a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/FilterUtils.java +++ b/metadata-service/auth-impl/src/main/java/com/datahub/authorization/FilterUtils.java @@ -1,6 +1,5 @@ package com.datahub.authorization; -import com.datahub.authorization.fieldresolverprovider.ResourceFieldType; import com.linkedin.data.template.StringArray; import com.linkedin.policy.PolicyMatchCondition; import com.linkedin.policy.PolicyMatchCriterion; diff --git a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/PolicyEngine.java b/metadata-service/auth-impl/src/main/java/com/datahub/authorization/PolicyEngine.java index 01a69b59fa..4fa8a3efe8 100644 --- a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/PolicyEngine.java +++ b/metadata-service/auth-impl/src/main/java/com/datahub/authorization/PolicyEngine.java @@ -1,7 +1,6 @@ package com.datahub.authorization; import com.datahub.authentication.Authentication; -import com.datahub.authorization.fieldresolverprovider.ResourceFieldType; import com.linkedin.common.urn.Urn; import com.linkedin.common.urn.UrnUtils; import com.linkedin.data.template.StringArray; diff --git a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/ResolvedResourceSpec.java b/metadata-service/auth-impl/src/main/java/com/datahub/authorization/ResolvedResourceSpec.java deleted file mode 100644 index 2c7bdfe37d..0000000000 --- a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/ResolvedResourceSpec.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.datahub.authorization; - -import com.datahub.authorization.fieldresolverprovider.ResourceFieldType; -import java.util.Collections; -import java.util.Map; -import java.util.Set; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - - -/** - * Wrapper around authorization request with field resolvers for lazily fetching the field values for each field type - */ -@RequiredArgsConstructor -public class ResolvedResourceSpec { - @Getter - private final ResourceSpec spec; - private final Map fieldResolvers; - - public Set getFieldValues(ResourceFieldType resourceFieldType) { - if (!fieldResolvers.containsKey(resourceFieldType)) { - return Collections.emptySet(); - } - return fieldResolvers.get(resourceFieldType).getFieldValuesFuture().join().getValues(); - } - - public Set getOwners() { - if (!fieldResolvers.containsKey(ResourceFieldType.OWNER)) { - return Collections.emptySet(); - } - return fieldResolvers.get(ResourceFieldType.OWNER).getFieldValuesFuture().join().getValues(); - } -} diff --git a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/fieldresolverprovider/DomainFieldResolverProvider.java b/metadata-service/auth-impl/src/main/java/com/datahub/authorization/fieldresolverprovider/DomainFieldResolverProvider.java index fbc7fcae88..90eeb2dc49 100644 --- a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/fieldresolverprovider/DomainFieldResolverProvider.java +++ b/metadata-service/auth-impl/src/main/java/com/datahub/authorization/fieldresolverprovider/DomainFieldResolverProvider.java @@ -2,6 +2,7 @@ package com.datahub.authorization.fieldresolverprovider; import com.datahub.authentication.Authentication; import com.datahub.authorization.FieldResolver; +import com.datahub.authorization.ResourceFieldType; import com.datahub.authorization.ResourceSpec; import com.linkedin.common.urn.Urn; import com.linkedin.common.urn.UrnUtils; diff --git a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/fieldresolverprovider/EntityTypeFieldResolverProvider.java b/metadata-service/auth-impl/src/main/java/com/datahub/authorization/fieldresolverprovider/EntityTypeFieldResolverProvider.java index 9fc731b8c5..58e3d78ce8 100644 --- a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/fieldresolverprovider/EntityTypeFieldResolverProvider.java +++ b/metadata-service/auth-impl/src/main/java/com/datahub/authorization/fieldresolverprovider/EntityTypeFieldResolverProvider.java @@ -1,6 +1,7 @@ package com.datahub.authorization.fieldresolverprovider; import com.datahub.authorization.FieldResolver; +import com.datahub.authorization.ResourceFieldType; import com.datahub.authorization.ResourceSpec; import java.util.Collections; diff --git a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/fieldresolverprovider/EntityUrnFieldResolverProvider.java b/metadata-service/auth-impl/src/main/java/com/datahub/authorization/fieldresolverprovider/EntityUrnFieldResolverProvider.java index 4b548e61a4..b9d98f1dcb 100644 --- a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/fieldresolverprovider/EntityUrnFieldResolverProvider.java +++ b/metadata-service/auth-impl/src/main/java/com/datahub/authorization/fieldresolverprovider/EntityUrnFieldResolverProvider.java @@ -1,6 +1,7 @@ package com.datahub.authorization.fieldresolverprovider; import com.datahub.authorization.FieldResolver; +import com.datahub.authorization.ResourceFieldType; import com.datahub.authorization.ResourceSpec; import java.util.Collections; diff --git a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/fieldresolverprovider/OwnerFieldResolverProvider.java b/metadata-service/auth-impl/src/main/java/com/datahub/authorization/fieldresolverprovider/OwnerFieldResolverProvider.java index 73438f5363..20ec6a0937 100644 --- a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/fieldresolverprovider/OwnerFieldResolverProvider.java +++ b/metadata-service/auth-impl/src/main/java/com/datahub/authorization/fieldresolverprovider/OwnerFieldResolverProvider.java @@ -2,6 +2,7 @@ package com.datahub.authorization.fieldresolverprovider; import com.datahub.authentication.Authentication; import com.datahub.authorization.FieldResolver; +import com.datahub.authorization.ResourceFieldType; import com.datahub.authorization.ResourceSpec; import com.linkedin.common.Ownership; import com.linkedin.common.urn.Urn; diff --git a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/fieldresolverprovider/ResourceFieldResolverProvider.java b/metadata-service/auth-impl/src/main/java/com/datahub/authorization/fieldresolverprovider/ResourceFieldResolverProvider.java index 2c3b3157e3..4ba4200f80 100644 --- a/metadata-service/auth-impl/src/main/java/com/datahub/authorization/fieldresolverprovider/ResourceFieldResolverProvider.java +++ b/metadata-service/auth-impl/src/main/java/com/datahub/authorization/fieldresolverprovider/ResourceFieldResolverProvider.java @@ -1,6 +1,7 @@ package com.datahub.authorization.fieldresolverprovider; import com.datahub.authorization.FieldResolver; +import com.datahub.authorization.ResourceFieldType; import com.datahub.authorization.ResourceSpec; diff --git a/metadata-service/auth-impl/src/test/java/com/datahub/authorization/DataHubAuthorizerTest.java b/metadata-service/auth-impl/src/test/java/com/datahub/authorization/DataHubAuthorizerTest.java index ef6b83fe37..9989a8e14a 100644 --- a/metadata-service/auth-impl/src/test/java/com/datahub/authorization/DataHubAuthorizerTest.java +++ b/metadata-service/auth-impl/src/test/java/com/datahub/authorization/DataHubAuthorizerTest.java @@ -107,6 +107,7 @@ public class DataHubAuthorizerTest { 10, DataHubAuthorizer.AuthorizationMode.DEFAULT ); + _dataHubAuthorizer.init(Collections.emptyMap(), createAuthorizerContext(systemAuthentication, _entityClient)); _dataHubAuthorizer.invalidateCache(); Thread.sleep(500); // Sleep so the runnable can execute. (not ideal) } @@ -282,4 +283,8 @@ public class DataHubAuthorizerTest { ownershipAspect.setLastModified(new AuditStamp().setTime(0).setActor(Urn.createFromString("urn:li:corpuser:foo"))); return ownershipAspect; } + + private AuthorizerContext createAuthorizerContext(final Authentication systemAuthentication, final EntityClient entityClient) { + return new AuthorizerContext(new DefaultResourceSpecResolver(systemAuthentication, entityClient)); + } } diff --git a/metadata-service/auth-impl/src/test/java/com/datahub/authorization/PolicyEngineTest.java b/metadata-service/auth-impl/src/test/java/com/datahub/authorization/PolicyEngineTest.java index 9064a9f783..dba8c89243 100644 --- a/metadata-service/auth-impl/src/test/java/com/datahub/authorization/PolicyEngineTest.java +++ b/metadata-service/auth-impl/src/test/java/com/datahub/authorization/PolicyEngineTest.java @@ -1,7 +1,6 @@ package com.datahub.authorization; import com.datahub.authentication.Authentication; -import com.datahub.authorization.fieldresolverprovider.ResourceFieldType; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; diff --git a/metadata-service/factories/src/main/java/com/linkedin/gms/factory/auth/AuthorizerChainFactory.java b/metadata-service/factories/src/main/java/com/linkedin/gms/factory/auth/AuthorizerChainFactory.java index e588956be8..fb1c21965d 100644 --- a/metadata-service/factories/src/main/java/com/linkedin/gms/factory/auth/AuthorizerChainFactory.java +++ b/metadata-service/factories/src/main/java/com/linkedin/gms/factory/auth/AuthorizerChainFactory.java @@ -1,9 +1,14 @@ package com.linkedin.gms.factory.auth; +import com.datahub.authentication.Authentication; import com.datahub.authorization.AuthorizerConfiguration; +import com.datahub.authorization.AuthorizerContext; import com.datahub.authorization.DataHubAuthorizer; import com.datahub.authorization.Authorizer; import com.datahub.authorization.AuthorizerChain; +import com.datahub.authorization.DefaultResourceSpecResolver; +import com.datahub.authorization.ResourceSpecResolver; +import com.linkedin.entity.client.JavaEntityClient; import com.linkedin.gms.factory.config.ConfigurationProvider; import com.linkedin.gms.factory.spring.YamlPropertySourceFactory; import java.util.ArrayList; @@ -31,20 +36,36 @@ public class AuthorizerChainFactory { @Autowired @Qualifier("dataHubAuthorizer") - private DataHubAuthorizer _dataHubAuthorizer; + private DataHubAuthorizer dataHubAuthorizer; + + @Autowired + @Qualifier("systemAuthentication") + private Authentication systemAuthentication; + + @Autowired + @Qualifier("javaEntityClient") + private JavaEntityClient entityClient; @Bean(name = "authorizerChain") @Scope("singleton") @Nonnull protected AuthorizerChain getInstance() { + // Init authorizer context + final AuthorizerContext ctx = initAuthorizerContext(); // Extract + initialize customer authorizers from application configs. - final List authorizers = new ArrayList<>(initCustomAuthorizers()); + final List authorizers = new ArrayList<>(initCustomAuthorizers(ctx)); // Add the DataHub core policies-based Authorizer - this one should always be enabled. - authorizers.add(this._dataHubAuthorizer); + this.dataHubAuthorizer.init(Collections.emptyMap(), ctx); + authorizers.add(this.dataHubAuthorizer); return new AuthorizerChain(authorizers); } - private List initCustomAuthorizers() { + private AuthorizerContext initAuthorizerContext() { + final ResourceSpecResolver resolver = new DefaultResourceSpecResolver(systemAuthentication, entityClient); + return new AuthorizerContext(resolver); + } + + private List initCustomAuthorizers(AuthorizerContext ctx) { final List customAuthorizers = new ArrayList<>(); if (this.configurationProvider.getAuthorization().getAuthorizers() != null) { @@ -71,7 +92,7 @@ public class AuthorizerChainFactory { // Else construct an instance of the class, each class should have an empty constructor. try { final Authorizer authorizerInstance = clazz.newInstance(); - authorizerInstance.init(configs); + authorizerInstance.init(configs, ctx); customAuthorizers.add(authorizerInstance); } catch (Exception e) { throw new RuntimeException(String.format("Failed to instantiate custom Authorizer with class name %s", clazz.getCanonicalName()), e);