Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add admin interface and operation attributes things for Attribute-Based Access Control #2405

Merged
merged 13 commits into from
Dec 24, 2024
755 changes: 755 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