Skip to content

Commit

Permalink
Backport to branch(3) : Add admin interface and operation attributes …
Browse files Browse the repository at this point in the history
…things for Attribute-Based Access Control (#2441)

Co-authored-by: Toshihiro Suzuki <[email protected]>
  • Loading branch information
feeblefakie and brfrn169 authored Dec 24, 2024
1 parent 87e3747 commit 3fd8bb7
Show file tree
Hide file tree
Showing 17 changed files with 2,082 additions and 105 deletions.
786 changes: 786 additions & 0 deletions core/src/main/java/com/scalar/db/api/AbacAdmin.java

Large diffs are not rendered by default.

47 changes: 47 additions & 0 deletions core/src/main/java/com/scalar/db/api/AbacOperationAttributes.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.scalar.db.api;

import java.util.Map;
import java.util.Optional;

/** A utility class to manipulate the operation attributes for attribute-based access control. */
public final class AbacOperationAttributes {

private static final String OPERATION_ATTRIBUTE_PREFIX = "abac-";
public static final String READ_TAG_PREFIX = OPERATION_ATTRIBUTE_PREFIX + "read-tag-";
public static final String WRITE_TAG_PREFIX = OPERATION_ATTRIBUTE_PREFIX + "write-tag-";

private AbacOperationAttributes() {}

public static void setReadTag(Map<String, String> attributes, String policyName, String readTag) {
attributes.put(READ_TAG_PREFIX + policyName, readTag);
}

public static void clearReadTag(Map<String, String> attributes, String policyName) {
attributes.remove(READ_TAG_PREFIX + policyName);
}

public static void clearReadTags(Map<String, String> attributes) {
attributes.entrySet().removeIf(e -> e.getKey().startsWith(READ_TAG_PREFIX));
}

public static void setWriteTag(
Map<String, String> attributes, String policyName, String writeTag) {
attributes.put(WRITE_TAG_PREFIX + policyName, writeTag);
}

public static void clearWriteTag(Map<String, String> attributes, String policyName) {
attributes.remove(WRITE_TAG_PREFIX + policyName);
}

public static void clearWriteTags(Map<String, String> attributes) {
attributes.entrySet().removeIf(e -> e.getKey().startsWith(WRITE_TAG_PREFIX));
}

public static Optional<String> getReadTag(Operation operation, String policyName) {
return operation.getAttribute(READ_TAG_PREFIX + policyName);
}

public static Optional<String> getWriteTag(Operation operation, String policyName) {
return operation.getAttribute(WRITE_TAG_PREFIX + policyName);
}
}
64 changes: 62 additions & 2 deletions core/src/main/java/com/scalar/db/api/DeleteBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.collect.ImmutableMap;
import com.scalar.db.api.OperationBuilder.AbacReadTagAttribute;
import com.scalar.db.api.OperationBuilder.AbacWriteTagAttribute;
import com.scalar.db.api.OperationBuilder.Attribute;
import com.scalar.db.api.OperationBuilder.ClearAbacReadTagAttribute;
import com.scalar.db.api.OperationBuilder.ClearAbacWriteTagAttribute;
import com.scalar.db.api.OperationBuilder.ClearAttribute;
import com.scalar.db.api.OperationBuilder.ClearClusteringKey;
import com.scalar.db.api.OperationBuilder.ClearCondition;
Expand Down Expand Up @@ -68,7 +72,9 @@ public static class Buildable extends OperationBuilder.Buildable<Delete>
implements ClusteringKey<Buildable>,
Consistency<Buildable>,
Condition<Buildable>,
Attribute<Buildable> {
Attribute<Buildable>,
AbacReadTagAttribute<Buildable>,
AbacWriteTagAttribute<Buildable> {
@Nullable Key clusteringKey;
@Nullable com.scalar.db.api.Consistency consistency;
@Nullable MutationCondition condition;
Expand Down Expand Up @@ -114,6 +120,22 @@ public Buildable attributes(Map<String, String> attributes) {
return this;
}

@Override
public Buildable readTag(String policyName, String readTag) {
checkNotNull(policyName);
checkNotNull(readTag);
AbacOperationAttributes.setReadTag(attributes, policyName, readTag);
return this;
}

@Override
public Buildable writeTag(String policyName, String writeTag) {
checkNotNull(policyName);
checkNotNull(writeTag);
AbacOperationAttributes.setWriteTag(attributes, policyName, writeTag);
return this;
}

@Override
public Delete build() {
return new Delete(
Expand All @@ -134,7 +156,9 @@ public static class BuildableFromExisting extends Buildable
ClearCondition<BuildableFromExisting>,
ClearClusteringKey<BuildableFromExisting>,
ClearNamespace<BuildableFromExisting>,
ClearAttribute<BuildableFromExisting> {
ClearAttribute<BuildableFromExisting>,
ClearAbacReadTagAttribute<BuildableFromExisting>,
ClearAbacWriteTagAttribute<BuildableFromExisting> {

BuildableFromExisting(Delete delete) {
super(
Expand Down Expand Up @@ -192,6 +216,18 @@ public BuildableFromExisting attributes(Map<String, String> attributes) {
return this;
}

@Override
public Buildable readTag(String policyName, String readTag) {
super.readTag(policyName, readTag);
return this;
}

@Override
public Buildable writeTag(String policyName, String writeTag) {
super.writeTag(policyName, writeTag);
return this;
}

@Override
public BuildableFromExisting condition(MutationCondition condition) {
super.condition(condition);
Expand Down Expand Up @@ -227,5 +263,29 @@ public BuildableFromExisting clearAttribute(String name) {
this.attributes.remove(name);
return this;
}

@Override
public BuildableFromExisting clearReadTag(String policyName) {
AbacOperationAttributes.clearReadTag(attributes, policyName);
return this;
}

@Override
public BuildableFromExisting clearReadTags() {
AbacOperationAttributes.clearReadTags(attributes);
return this;
}

@Override
public BuildableFromExisting clearWriteTag(String policyName) {
AbacOperationAttributes.clearWriteTag(attributes, policyName);
return this;
}

@Override
public BuildableFromExisting clearWriteTags() {
AbacOperationAttributes.clearWriteTags(attributes);
return this;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* An administrative interface for distributed transaction implementations. The user can execute
* administrative operations with it like createNamespace/createTable/getTableMetadata.
*/
public interface DistributedTransactionAdmin extends Admin, AuthAdmin, AutoCloseable {
public interface DistributedTransactionAdmin extends Admin, AuthAdmin, AbacAdmin, AutoCloseable {

/**
* Creates coordinator namespace and tables.
Expand Down
80 changes: 76 additions & 4 deletions core/src/main/java/com/scalar/db/api/GetBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.scalar.db.api.OperationBuilder.AbacReadTagAttribute;
import com.scalar.db.api.OperationBuilder.And;
import com.scalar.db.api.OperationBuilder.Attribute;
import com.scalar.db.api.OperationBuilder.Buildable;
import com.scalar.db.api.OperationBuilder.ClearAbacReadTagAttribute;
import com.scalar.db.api.OperationBuilder.ClearAttribute;
import com.scalar.db.api.OperationBuilder.ClearClusteringKey;
import com.scalar.db.api.OperationBuilder.ClearConditions;
Expand Down Expand Up @@ -93,7 +95,8 @@ public static class BuildableGet extends Buildable<Get>
implements ClusteringKey<BuildableGet>,
Consistency<BuildableGet>,
Projection<BuildableGet>,
Attribute<BuildableGet> {
Attribute<BuildableGet>,
AbacReadTagAttribute<BuildableGet> {
final List<String> projections = new ArrayList<>();
@Nullable Key clusteringKey;
@Nullable com.scalar.db.api.Consistency consistency;
Expand Down Expand Up @@ -158,6 +161,14 @@ public BuildableGet attributes(Map<String, String> attributes) {
return this;
}

@Override
public BuildableGet readTag(String policyName, String readTag) {
checkNotNull(policyName);
checkNotNull(readTag);
AbacOperationAttributes.setReadTag(attributes, policyName, readTag);
return this;
}

@Override
public Get build() {
return build(ImmutableSet.of());
Expand Down Expand Up @@ -227,6 +238,12 @@ public BuildableGetWithPartitionKey attributes(Map<String, String> attributes) {
return this;
}

@Override
public BuildableGet readTag(String policyName, String readTag) {
super.readTag(policyName, readTag);
return this;
}

@Override
public BuildableGetWithOngoingWhere where(ConditionalExpression condition) {
checkNotNull(condition);
Expand Down Expand Up @@ -390,6 +407,7 @@ public static class BuildableGetWithIndex
implements Consistency<BuildableGetWithIndex>,
Projection<BuildableGetWithIndex>,
Attribute<BuildableGetWithIndex>,
AbacReadTagAttribute<BuildableGetWithIndex>,
OperationBuilder.Where<BuildableGetWithIndexOngoingWhere>,
WhereAnd<BuildableGetWithIndexOngoingWhereAnd>,
WhereOr<BuildableGetWithIndexOngoingWhereOr> {
Expand Down Expand Up @@ -447,6 +465,14 @@ public BuildableGetWithIndex attributes(Map<String, String> attributes) {
return this;
}

@Override
public BuildableGetWithIndex readTag(String policyName, String readTag) {
checkNotNull(policyName);
checkNotNull(readTag);
AbacOperationAttributes.setReadTag(attributes, policyName, readTag);
return this;
}

@Override
public BuildableGetWithIndexOngoingWhere where(ConditionalExpression condition) {
checkNotNull(condition);
Expand Down Expand Up @@ -602,7 +628,8 @@ public BuildableGetWithIndexOngoingWhereOr or(AndConditionSet andConditionSet) {
public static class BuildableGetWithIndexWhere
implements Consistency<BuildableGetWithIndexWhere>,
Projection<BuildableGetWithIndexWhere>,
Attribute<BuildableGetWithIndexWhere> {
Attribute<BuildableGetWithIndexWhere>,
AbacReadTagAttribute<BuildableGetWithIndexWhere> {

BuildableGetWithIndex buildableGetWithIndex;
final SelectionBuilder.Where where;
Expand Down Expand Up @@ -657,6 +684,12 @@ public BuildableGetWithIndexWhere attributes(Map<String, String> attributes) {
return this;
}

@Override
public BuildableGetWithIndexWhere readTag(String policyName, String readTag) {
buildableGetWithIndex = buildableGetWithIndex.readTag(policyName, readTag);
return this;
}

public Get build() {
return buildableGetWithIndex.build(getConjunctions(where));
}
Expand All @@ -674,7 +707,8 @@ public static class BuildableGetOrGetWithIndexFromExisting extends BuildableGet
ClearProjections<BuildableGetOrGetWithIndexFromExisting>,
ClearClusteringKey<BuildableGetOrGetWithIndexFromExisting>,
ClearNamespace<BuildableGetOrGetWithIndexFromExisting>,
ClearAttribute<BuildableGetOrGetWithIndexFromExisting> {
ClearAttribute<BuildableGetOrGetWithIndexFromExisting>,
ClearAbacReadTagAttribute<BuildableGetOrGetWithIndexFromExisting> {

private Key indexKey;
private final boolean isGetWithIndex;
Expand Down Expand Up @@ -770,6 +804,12 @@ public BuildableGetOrGetWithIndexFromExisting attributes(Map<String, String> att
return this;
}

@Override
public BuildableGet readTag(String policyName, String readTag) {
super.readTag(policyName, readTag);
return this;
}

@Override
public BuildableGetFromExistingWithOngoingWhere where(ConditionalExpression condition) {
checkConditionsEmpty();
Expand Down Expand Up @@ -845,6 +885,18 @@ public BuildableGetOrGetWithIndexFromExisting clearAttribute(String name) {
return this;
}

@Override
public BuildableGetOrGetWithIndexFromExisting clearReadTag(String policyName) {
AbacOperationAttributes.clearReadTag(attributes, policyName);
return this;
}

@Override
public BuildableGetOrGetWithIndexFromExisting clearReadTags() {
AbacOperationAttributes.clearReadTags(attributes);
return this;
}

private void checkNotGet() {
if (!isGetWithIndex) {
throw new UnsupportedOperationException(
Expand Down Expand Up @@ -910,9 +962,11 @@ public static class BuildableGetFromExistingWithWhere
Consistency<BuildableGetFromExistingWithWhere>,
Projection<BuildableGetFromExistingWithWhere>,
Attribute<BuildableGetFromExistingWithWhere>,
AbacReadTagAttribute<BuildableGetFromExistingWithWhere>,
ClearProjections<BuildableGetFromExistingWithWhere>,
ClearNamespace<BuildableGetFromExistingWithWhere>,
ClearAttribute<BuildableGetFromExistingWithWhere> {
ClearAttribute<BuildableGetFromExistingWithWhere>,
ClearAbacReadTagAttribute<BuildableGetFromExistingWithWhere> {

private final BuildableGetOrGetWithIndexFromExisting BuildableGetFromExisting;
final SelectionBuilder.Where where;
Expand Down Expand Up @@ -999,6 +1053,12 @@ public BuildableGetFromExistingWithWhere attributes(Map<String, String> attribut
return this;
}

@Override
public BuildableGetFromExistingWithWhere readTag(String policyName, String readTag) {
BuildableGetFromExisting.readTag(policyName, readTag);
return this;
}

@Override
public BuildableGetFromExistingWithWhere clearProjections() {
BuildableGetFromExisting.clearProjections();
Expand All @@ -1023,6 +1083,18 @@ public BuildableGetFromExistingWithWhere clearAttribute(String name) {
return this;
}

@Override
public BuildableGetFromExistingWithWhere clearReadTag(String policyName) {
BuildableGetFromExisting.clearReadTag(policyName);
return this;
}

@Override
public BuildableGetFromExistingWithWhere clearReadTags() {
BuildableGetFromExisting.clearReadTags();
return this;
}

public Get build() {
return BuildableGetFromExisting.build(getConjunctions(where));
}
Expand Down
Loading

0 comments on commit 3fd8bb7

Please sign in to comment.