Skip to content

Commit

Permalink
Decouple authorizer from relational store
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaelbey committed Oct 16, 2023
1 parent 25e62ea commit b521f26
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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<Object> details;

public CredentialAuthorization(String subject, String vaultReference, Status status, ImmutableList<Object> details)
{
this.subject = subject;
this.vaultReference = vaultReference;
this.status = status;
this.details = details;
}

public static CredentialAuthorization allow(String subject, String vaultReference, ImmutableList<Object> details)
{
return new CredentialAuthorization(subject, vaultReference, Status.ALLOW, details);
}

public static CredentialAuthorization deny(String subject, String vaultReference, ImmutableList<Object> 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<Object> 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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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;

Expand All @@ -20,6 +21,7 @@
import org.eclipse.collections.api.list.ImmutableList;
import org.finos.legend.engine.shared.core.identity.Identity;

@Deprecated
public interface RelationalMiddleTierConnectionCredentialAuthorizer
{
/*
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -34,22 +35,35 @@
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;

public class RelationalMiddleTierPlanExecutionAuthorizer implements PlanExecutionAuthorizer
{
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
Expand All @@ -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
{
Expand Down Expand Up @@ -130,7 +144,7 @@ private MutableList<ExecutionAuthorization> 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("/", "_")
Expand All @@ -146,7 +160,7 @@ private MutableList<ExecutionAuthorization> 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));
}
Expand Down Expand Up @@ -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))
Expand Down

0 comments on commit b521f26

Please sign in to comment.