From b521f26c7cadab877c03452801e7eca7343078a8 Mon Sep 17 00:00:00 2001 From: Rafael Bey Date: Mon, 16 Oct 2023 16:16:06 -0400 Subject: [PATCH] Decouple authorizer from relational store --- .../AbstractMiddleTierExecutionTest.java | 6 +- ...dleTierConnectionCredentialAuthorizer.java | 30 +++++ ...dleTierConnectionCredentialAuthorizer.java | 109 ++++++++++++++++++ ...dleTierConnectionCredentialAuthorizer.java | 1 + ...dleTierConnectionCredentialAuthorizer.java | 6 +- ...onalMiddleTierPlanExecutionAuthorizer.java | 30 +++-- 6 files changed, 169 insertions(+), 13 deletions(-) create mode 100644 legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution-authorizer/src/main/java/org/finos/legend/engine/plan/execution/authorization/AbstractMiddleTierConnectionCredentialAuthorizer.java create mode 100644 legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution-authorizer/src/main/java/org/finos/legend/engine/plan/execution/authorization/MiddleTierConnectionCredentialAuthorizer.java diff --git a/legend-engine-config/legend-engine-server-integration-tests/src/test/java/org/finos/legend/engine/server/integration/tests/AbstractMiddleTierExecutionTest.java b/legend-engine-config/legend-engine-server-integration-tests/src/test/java/org/finos/legend/engine/server/integration/tests/AbstractMiddleTierExecutionTest.java index 7bdd2e6f2b6..8b8ab999205 100644 --- a/legend-engine-config/legend-engine-server-integration-tests/src/test/java/org/finos/legend/engine/server/integration/tests/AbstractMiddleTierExecutionTest.java +++ b/legend-engine-config/legend-engine-server-integration-tests/src/test/java/org/finos/legend/engine/server/integration/tests/AbstractMiddleTierExecutionTest.java @@ -21,7 +21,7 @@ import org.finos.legend.engine.authentication.LegendDefaultDatabaseAuthenticationFlowProviderConfiguration; import org.finos.legend.engine.plan.execution.PlanExecutor; import org.finos.legend.engine.plan.execution.authorization.PlanExecutionAuthorizerInput; -import org.finos.legend.engine.plan.execution.authorization.RelationalMiddleTierConnectionCredentialAuthorizer; +import org.finos.legend.engine.plan.execution.authorization.MiddleTierConnectionCredentialAuthorizer; import org.finos.legend.engine.plan.execution.stores.StoreExecutor; import org.finos.legend.engine.plan.execution.stores.inMemory.plugin.InMemory; import org.finos.legend.engine.plan.execution.stores.relational.config.RelationalExecutionConfiguration; @@ -141,7 +141,7 @@ protected PlanExecutor buildPlanExecutor() return executor; } - public static class AlwaysAllowCredentialAuthorizer implements RelationalMiddleTierConnectionCredentialAuthorizer + public static class AlwaysAllowCredentialAuthorizer implements MiddleTierConnectionCredentialAuthorizer { @Override public CredentialAuthorization evaluate(Identity currentUser, String credentialVaultReference, PlanExecutionAuthorizerInput.ExecutionMode usageContext, String resourceContext, String policyContext) throws Exception @@ -150,7 +150,7 @@ public CredentialAuthorization evaluate(Identity currentUser, String credentialV } } - public static class AlwaysDenyCredentialAuthorizer implements RelationalMiddleTierConnectionCredentialAuthorizer + public static class AlwaysDenyCredentialAuthorizer implements MiddleTierConnectionCredentialAuthorizer { @Override public CredentialAuthorization evaluate(Identity currentUser, String credentialVaultReference, PlanExecutionAuthorizerInput.ExecutionMode usageContext, String resourceContext, String policyContext) throws Exception diff --git a/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution-authorizer/src/main/java/org/finos/legend/engine/plan/execution/authorization/AbstractMiddleTierConnectionCredentialAuthorizer.java b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution-authorizer/src/main/java/org/finos/legend/engine/plan/execution/authorization/AbstractMiddleTierConnectionCredentialAuthorizer.java new file mode 100644 index 00000000000..1458b58b2a2 --- /dev/null +++ b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution-authorizer/src/main/java/org/finos/legend/engine/plan/execution/authorization/AbstractMiddleTierConnectionCredentialAuthorizer.java @@ -0,0 +1,30 @@ +// Copyright 2023 Goldman Sachs +// +// Licensed 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.finos.legend.engine.plan.execution.authorization; + +import org.finos.legend.engine.shared.core.identity.Identity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AbstractMiddleTierConnectionCredentialAuthorizer implements MiddleTierConnectionCredentialAuthorizer +{ + @Override + public CredentialAuthorization evaluate(Identity subject, String credentialVaultReference, PlanExecutionAuthorizerInput.ExecutionMode usageContext, String resourceContext, String policyContext) throws Exception + { + return this.evaluateImpl(subject, credentialVaultReference, usageContext, resourceContext, policyContext); + } + + public abstract CredentialAuthorization evaluateImpl(Identity subject, String credentialVaultReference, PlanExecutionAuthorizerInput.ExecutionMode usageContext, String resourceContext, String policyContext) throws Exception; +} diff --git a/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution-authorizer/src/main/java/org/finos/legend/engine/plan/execution/authorization/MiddleTierConnectionCredentialAuthorizer.java b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution-authorizer/src/main/java/org/finos/legend/engine/plan/execution/authorization/MiddleTierConnectionCredentialAuthorizer.java new file mode 100644 index 00000000000..df79dcfb6bf --- /dev/null +++ b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-executionPlan-execution-authorizer/src/main/java/org/finos/legend/engine/plan/execution/authorization/MiddleTierConnectionCredentialAuthorizer.java @@ -0,0 +1,109 @@ +// Copyright 2023 Goldman Sachs +// +// Licensed 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.finos.legend.engine.plan.execution.authorization; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.eclipse.collections.api.list.ImmutableList; +import org.finos.legend.engine.shared.core.identity.Identity; + +public interface MiddleTierConnectionCredentialAuthorizer +{ + /* + Is 'Alice' allowed to use 'credref1' for interactive development ? + Is 'Alice' allowed to use 'credref1' during a service execution ? + */ + CredentialAuthorization evaluate(Identity currentUser, String credentialVaultReference, PlanExecutionAuthorizerInput.ExecutionMode usageContext, String resourceContext, String policyContext) throws Exception; + + @JsonPropertyOrder({"status","summary","subject","vaultReference","details"}) + class CredentialAuthorization + { + public enum Status + { + ALLOW, + DENY + } + + private Status status; + + private String subject; + + private String vaultReference; + + // details are expected to be JSON serializable + private ImmutableList details; + + public CredentialAuthorization(String subject, String vaultReference, Status status, ImmutableList details) + { + this.subject = subject; + this.vaultReference = vaultReference; + this.status = status; + this.details = details; + } + + public static CredentialAuthorization allow(String subject, String vaultReference, ImmutableList details) + { + return new CredentialAuthorization(subject, vaultReference, Status.ALLOW, details); + } + + public static CredentialAuthorization deny(String subject, String vaultReference, ImmutableList details) + { + return new CredentialAuthorization(subject, vaultReference, Status.DENY, details); + } + + public Status getStatus() + { + return status; + } + + @JsonIgnore + public boolean isAllowed() + { + return this.status.equals(Status.ALLOW); + } + + @JsonIgnore + public boolean isDenied() + { + return !this.isAllowed(); + } + + public ImmutableList getDetails() + { + return details; + } + + public String getSubject() + { + return subject; + } + + public String getVaultReference() + { + return vaultReference; + } + + public Object toJSON() throws Exception + { + return new ObjectMapper().writeValueAsString(this); + } + + public Object toPrettyJSON() throws Exception + { + return new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this); + } + } +} diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan-authorizer/src/main/java/org/finos/legend/engine/plan/execution/authorization/AbstractRelationalMiddleTierConnectionCredentialAuthorizer.java b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan-authorizer/src/main/java/org/finos/legend/engine/plan/execution/authorization/AbstractRelationalMiddleTierConnectionCredentialAuthorizer.java index 4bbc4cf3a8d..209bad2ec29 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan-authorizer/src/main/java/org/finos/legend/engine/plan/execution/authorization/AbstractRelationalMiddleTierConnectionCredentialAuthorizer.java +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan-authorizer/src/main/java/org/finos/legend/engine/plan/execution/authorization/AbstractRelationalMiddleTierConnectionCredentialAuthorizer.java @@ -18,6 +18,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +@Deprecated public abstract class AbstractRelationalMiddleTierConnectionCredentialAuthorizer implements RelationalMiddleTierConnectionCredentialAuthorizer { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractRelationalMiddleTierConnectionCredentialAuthorizer.class); diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan-authorizer/src/main/java/org/finos/legend/engine/plan/execution/authorization/RelationalMiddleTierConnectionCredentialAuthorizer.java b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan-authorizer/src/main/java/org/finos/legend/engine/plan/execution/authorization/RelationalMiddleTierConnectionCredentialAuthorizer.java index 662eb383887..a99437859ca 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan-authorizer/src/main/java/org/finos/legend/engine/plan/execution/authorization/RelationalMiddleTierConnectionCredentialAuthorizer.java +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan-authorizer/src/main/java/org/finos/legend/engine/plan/execution/authorization/RelationalMiddleTierConnectionCredentialAuthorizer.java @@ -1,4 +1,4 @@ -// Copyright 2021 Goldman Sachs +// Copyright 2023 Goldman Sachs // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -11,6 +11,7 @@ // 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.finos.legend.engine.plan.execution.authorization; @@ -20,6 +21,7 @@ import org.eclipse.collections.api.list.ImmutableList; import org.finos.legend.engine.shared.core.identity.Identity; +@Deprecated public interface RelationalMiddleTierConnectionCredentialAuthorizer { /* @@ -28,7 +30,7 @@ public interface RelationalMiddleTierConnectionCredentialAuthorizer */ CredentialAuthorization evaluate(Identity currentUser, String credentialVaultReference, PlanExecutionAuthorizerInput.ExecutionMode usageContext, String resourceContext, String policyContext) throws Exception; - @JsonPropertyOrder({"status","summary","subject","vaultReference","details"}) + @JsonPropertyOrder({"status", "summary", "subject", "vaultReference", "details"}) class CredentialAuthorization { public enum Status diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan-authorizer/src/main/java/org/finos/legend/engine/plan/execution/authorization/RelationalMiddleTierPlanExecutionAuthorizer.java b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan-authorizer/src/main/java/org/finos/legend/engine/plan/execution/authorization/RelationalMiddleTierPlanExecutionAuthorizer.java index 9bc723ea761..5d99fb9d7e1 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan-authorizer/src/main/java/org/finos/legend/engine/plan/execution/authorization/RelationalMiddleTierPlanExecutionAuthorizer.java +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan-authorizer/src/main/java/org/finos/legend/engine/plan/execution/authorization/RelationalMiddleTierPlanExecutionAuthorizer.java @@ -15,6 +15,7 @@ package org.finos.legend.engine.plan.execution.authorization; import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.stream.Collectors; import org.eclipse.collections.api.factory.Lists; import org.eclipse.collections.api.factory.Maps; import org.eclipse.collections.api.list.MutableList; @@ -34,8 +35,6 @@ import org.finos.legend.engine.shared.core.identity.credential.middletier.MiddleTierUserPasswordCredential; import org.finos.legend.engine.shared.core.vault.Vault; -import java.util.stream.Collectors; - import static org.finos.legend.engine.plan.execution.authorization.PlanExecutionAuthorizerInput.ExecutionMode.INTERACTIVE_EXECUTION; import static org.finos.legend.engine.plan.execution.authorization.PlanExecutionAuthorizerInput.ExecutionMode.SERVICE_EXECUTION; @@ -43,13 +42,28 @@ public class RelationalMiddleTierPlanExecutionAuthorizer implements PlanExecutio { public static final String DATABASE_PREFIX = "DB"; - private RelationalMiddleTierConnectionCredentialAuthorizer relationalMiddleTierConnectionCredentialAuthorizer; + private final MiddleTierConnectionCredentialAuthorizer middleTierConnectionCredentialAuthorizer; private static final String AUTHORIZER_NAME = RelationalMiddleTierPlanExecutionAuthorizer.class.getSimpleName(); + @Deprecated public RelationalMiddleTierPlanExecutionAuthorizer(RelationalMiddleTierConnectionCredentialAuthorizer relationalMiddleTierConnectionCredentialAuthorizer) { - this.relationalMiddleTierConnectionCredentialAuthorizer = relationalMiddleTierConnectionCredentialAuthorizer; + this((MiddleTierConnectionCredentialAuthorizer) (currentUser, credentialVaultReference, usageContext, resourceContext, policyContext) -> + { + RelationalMiddleTierConnectionCredentialAuthorizer.CredentialAuthorization res = relationalMiddleTierConnectionCredentialAuthorizer.evaluate(currentUser, credentialVaultReference, usageContext, resourceContext, policyContext); + return new MiddleTierConnectionCredentialAuthorizer.CredentialAuthorization( + res.getSubject(), + res.getVaultReference(), + MiddleTierConnectionCredentialAuthorizer.CredentialAuthorization.Status.valueOf(res.getStatus().name()), + res.getDetails() + ); + }); + } + + public RelationalMiddleTierPlanExecutionAuthorizer(MiddleTierConnectionCredentialAuthorizer middleTierConnectionCredentialAuthorizer) + { + this.middleTierConnectionCredentialAuthorizer = middleTierConnectionCredentialAuthorizer; } @Override @@ -62,7 +76,7 @@ private PlanExecutionAuthorizerOutput evaluateImpl(Identity identity, ExecutionP { if (executionPlan instanceof SingleExecutionPlan) { - return evaluateSingleExecutionPlan(identity, (SingleExecutionPlan)executionPlan, authorizationInput); + return evaluateSingleExecutionPlan(identity, (SingleExecutionPlan) executionPlan, authorizationInput); } else { @@ -130,7 +144,7 @@ private MutableList evaluateForServiceExecution(Identity public static String normalizeServiceResourceContext(String servicePath, String serviceUniqueId) { String normalizedResourceContext = String.format("id@%s@%s", serviceUniqueId, servicePath) - // ':' separates tokens in the id + // ':' separates tokens in the id .replaceAll(":", "_") // '/' slashes in the service pattern .replaceAll("/", "_") @@ -146,7 +160,7 @@ private MutableList evaluateForInteractiveExecution(Iden for (RelationalDatabaseConnection relationalDatabaseConnection : nodesWithMiddleTierConnections) { - MiddleTierUserNamePasswordAuthenticationStrategy middleTierAuthNode = (MiddleTierUserNamePasswordAuthenticationStrategy)relationalDatabaseConnection.authenticationStrategy; + MiddleTierUserNamePasswordAuthenticationStrategy middleTierAuthNode = (MiddleTierUserNamePasswordAuthenticationStrategy) relationalDatabaseConnection.authenticationStrategy; String normalizedResourceContext = this.resolveDatabaseContext(relationalDatabaseConnection); authorizations.add(this.evaluateCredentialAuthorization(identity, normalizedResourceContext, INTERACTIVE_EXECUTION, middleTierAuthNode)); } @@ -190,7 +204,7 @@ private ExecutionAuthorization evaluateCredentialAuthorization(Identity identity String vaultReference = authNode.vaultReference; String policyContext = this.resolvePolicyContext(authNode); - RelationalMiddleTierConnectionCredentialAuthorizer.CredentialAuthorization credentialAuthorization = relationalMiddleTierConnectionCredentialAuthorizer.evaluate(identity, vaultReference, executionMode, resourceContext, policyContext); + MiddleTierConnectionCredentialAuthorizer.CredentialAuthorization credentialAuthorization = middleTierConnectionCredentialAuthorizer.evaluate(identity, vaultReference, executionMode, resourceContext, policyContext); ExecutionAuthorization.Builder builder = ExecutionAuthorization.withSubject(identity.getName()) .withResource(Maps.immutable.of("credential", vaultReference))