Skip to content

Commit e982d74

Browse files
authored
Add admin interface and operation attributes things for Attribute-Based Access Control (#2405)
1 parent a706e7f commit e982d74

17 files changed

+2082
-105
lines changed

core/src/main/java/com/scalar/db/api/AbacAdmin.java

Lines changed: 786 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.scalar.db.api;
2+
3+
import java.util.Map;
4+
import java.util.Optional;
5+
6+
/** A utility class to manipulate the operation attributes for attribute-based access control. */
7+
public final class AbacOperationAttributes {
8+
9+
private static final String OPERATION_ATTRIBUTE_PREFIX = "abac-";
10+
public static final String READ_TAG_PREFIX = OPERATION_ATTRIBUTE_PREFIX + "read-tag-";
11+
public static final String WRITE_TAG_PREFIX = OPERATION_ATTRIBUTE_PREFIX + "write-tag-";
12+
13+
private AbacOperationAttributes() {}
14+
15+
public static void setReadTag(Map<String, String> attributes, String policyName, String readTag) {
16+
attributes.put(READ_TAG_PREFIX + policyName, readTag);
17+
}
18+
19+
public static void clearReadTag(Map<String, String> attributes, String policyName) {
20+
attributes.remove(READ_TAG_PREFIX + policyName);
21+
}
22+
23+
public static void clearReadTags(Map<String, String> attributes) {
24+
attributes.entrySet().removeIf(e -> e.getKey().startsWith(READ_TAG_PREFIX));
25+
}
26+
27+
public static void setWriteTag(
28+
Map<String, String> attributes, String policyName, String writeTag) {
29+
attributes.put(WRITE_TAG_PREFIX + policyName, writeTag);
30+
}
31+
32+
public static void clearWriteTag(Map<String, String> attributes, String policyName) {
33+
attributes.remove(WRITE_TAG_PREFIX + policyName);
34+
}
35+
36+
public static void clearWriteTags(Map<String, String> attributes) {
37+
attributes.entrySet().removeIf(e -> e.getKey().startsWith(WRITE_TAG_PREFIX));
38+
}
39+
40+
public static Optional<String> getReadTag(Operation operation, String policyName) {
41+
return operation.getAttribute(READ_TAG_PREFIX + policyName);
42+
}
43+
44+
public static Optional<String> getWriteTag(Operation operation, String policyName) {
45+
return operation.getAttribute(WRITE_TAG_PREFIX + policyName);
46+
}
47+
}

core/src/main/java/com/scalar/db/api/DeleteBuilder.java

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
import static com.google.common.base.Preconditions.checkNotNull;
44

55
import com.google.common.collect.ImmutableMap;
6+
import com.scalar.db.api.OperationBuilder.AbacReadTagAttribute;
7+
import com.scalar.db.api.OperationBuilder.AbacWriteTagAttribute;
68
import com.scalar.db.api.OperationBuilder.Attribute;
9+
import com.scalar.db.api.OperationBuilder.ClearAbacReadTagAttribute;
10+
import com.scalar.db.api.OperationBuilder.ClearAbacWriteTagAttribute;
711
import com.scalar.db.api.OperationBuilder.ClearAttribute;
812
import com.scalar.db.api.OperationBuilder.ClearClusteringKey;
913
import com.scalar.db.api.OperationBuilder.ClearCondition;
@@ -68,7 +72,9 @@ public static class Buildable extends OperationBuilder.Buildable<Delete>
6872
implements ClusteringKey<Buildable>,
6973
Consistency<Buildable>,
7074
Condition<Buildable>,
71-
Attribute<Buildable> {
75+
Attribute<Buildable>,
76+
AbacReadTagAttribute<Buildable>,
77+
AbacWriteTagAttribute<Buildable> {
7278
@Nullable Key clusteringKey;
7379
@Nullable com.scalar.db.api.Consistency consistency;
7480
@Nullable MutationCondition condition;
@@ -114,6 +120,22 @@ public Buildable attributes(Map<String, String> attributes) {
114120
return this;
115121
}
116122

123+
@Override
124+
public Buildable readTag(String policyName, String readTag) {
125+
checkNotNull(policyName);
126+
checkNotNull(readTag);
127+
AbacOperationAttributes.setReadTag(attributes, policyName, readTag);
128+
return this;
129+
}
130+
131+
@Override
132+
public Buildable writeTag(String policyName, String writeTag) {
133+
checkNotNull(policyName);
134+
checkNotNull(writeTag);
135+
AbacOperationAttributes.setWriteTag(attributes, policyName, writeTag);
136+
return this;
137+
}
138+
117139
@Override
118140
public Delete build() {
119141
return new Delete(
@@ -134,7 +156,9 @@ public static class BuildableFromExisting extends Buildable
134156
ClearCondition<BuildableFromExisting>,
135157
ClearClusteringKey<BuildableFromExisting>,
136158
ClearNamespace<BuildableFromExisting>,
137-
ClearAttribute<BuildableFromExisting> {
159+
ClearAttribute<BuildableFromExisting>,
160+
ClearAbacReadTagAttribute<BuildableFromExisting>,
161+
ClearAbacWriteTagAttribute<BuildableFromExisting> {
138162

139163
BuildableFromExisting(Delete delete) {
140164
super(
@@ -192,6 +216,18 @@ public BuildableFromExisting attributes(Map<String, String> attributes) {
192216
return this;
193217
}
194218

219+
@Override
220+
public Buildable readTag(String policyName, String readTag) {
221+
super.readTag(policyName, readTag);
222+
return this;
223+
}
224+
225+
@Override
226+
public Buildable writeTag(String policyName, String writeTag) {
227+
super.writeTag(policyName, writeTag);
228+
return this;
229+
}
230+
195231
@Override
196232
public BuildableFromExisting condition(MutationCondition condition) {
197233
super.condition(condition);
@@ -227,5 +263,29 @@ public BuildableFromExisting clearAttribute(String name) {
227263
this.attributes.remove(name);
228264
return this;
229265
}
266+
267+
@Override
268+
public BuildableFromExisting clearReadTag(String policyName) {
269+
AbacOperationAttributes.clearReadTag(attributes, policyName);
270+
return this;
271+
}
272+
273+
@Override
274+
public BuildableFromExisting clearReadTags() {
275+
AbacOperationAttributes.clearReadTags(attributes);
276+
return this;
277+
}
278+
279+
@Override
280+
public BuildableFromExisting clearWriteTag(String policyName) {
281+
AbacOperationAttributes.clearWriteTag(attributes, policyName);
282+
return this;
283+
}
284+
285+
@Override
286+
public BuildableFromExisting clearWriteTags() {
287+
AbacOperationAttributes.clearWriteTags(attributes);
288+
return this;
289+
}
230290
}
231291
}

core/src/main/java/com/scalar/db/api/DistributedTransactionAdmin.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* An administrative interface for distributed transaction implementations. The user can execute
99
* administrative operations with it like createNamespace/createTable/getTableMetadata.
1010
*/
11-
public interface DistributedTransactionAdmin extends Admin, AuthAdmin, AutoCloseable {
11+
public interface DistributedTransactionAdmin extends Admin, AuthAdmin, AbacAdmin, AutoCloseable {
1212

1313
/**
1414
* Creates coordinator namespace and tables.

core/src/main/java/com/scalar/db/api/GetBuilder.java

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44

55
import com.google.common.collect.ImmutableMap;
66
import com.google.common.collect.ImmutableSet;
7+
import com.scalar.db.api.OperationBuilder.AbacReadTagAttribute;
78
import com.scalar.db.api.OperationBuilder.And;
89
import com.scalar.db.api.OperationBuilder.Attribute;
910
import com.scalar.db.api.OperationBuilder.Buildable;
11+
import com.scalar.db.api.OperationBuilder.ClearAbacReadTagAttribute;
1012
import com.scalar.db.api.OperationBuilder.ClearAttribute;
1113
import com.scalar.db.api.OperationBuilder.ClearClusteringKey;
1214
import com.scalar.db.api.OperationBuilder.ClearConditions;
@@ -93,7 +95,8 @@ public static class BuildableGet extends Buildable<Get>
9395
implements ClusteringKey<BuildableGet>,
9496
Consistency<BuildableGet>,
9597
Projection<BuildableGet>,
96-
Attribute<BuildableGet> {
98+
Attribute<BuildableGet>,
99+
AbacReadTagAttribute<BuildableGet> {
97100
final List<String> projections = new ArrayList<>();
98101
@Nullable Key clusteringKey;
99102
@Nullable com.scalar.db.api.Consistency consistency;
@@ -158,6 +161,14 @@ public BuildableGet attributes(Map<String, String> attributes) {
158161
return this;
159162
}
160163

164+
@Override
165+
public BuildableGet readTag(String policyName, String readTag) {
166+
checkNotNull(policyName);
167+
checkNotNull(readTag);
168+
AbacOperationAttributes.setReadTag(attributes, policyName, readTag);
169+
return this;
170+
}
171+
161172
@Override
162173
public Get build() {
163174
return build(ImmutableSet.of());
@@ -227,6 +238,12 @@ public BuildableGetWithPartitionKey attributes(Map<String, String> attributes) {
227238
return this;
228239
}
229240

241+
@Override
242+
public BuildableGet readTag(String policyName, String readTag) {
243+
super.readTag(policyName, readTag);
244+
return this;
245+
}
246+
230247
@Override
231248
public BuildableGetWithOngoingWhere where(ConditionalExpression condition) {
232249
checkNotNull(condition);
@@ -390,6 +407,7 @@ public static class BuildableGetWithIndex
390407
implements Consistency<BuildableGetWithIndex>,
391408
Projection<BuildableGetWithIndex>,
392409
Attribute<BuildableGetWithIndex>,
410+
AbacReadTagAttribute<BuildableGetWithIndex>,
393411
OperationBuilder.Where<BuildableGetWithIndexOngoingWhere>,
394412
WhereAnd<BuildableGetWithIndexOngoingWhereAnd>,
395413
WhereOr<BuildableGetWithIndexOngoingWhereOr> {
@@ -447,6 +465,14 @@ public BuildableGetWithIndex attributes(Map<String, String> attributes) {
447465
return this;
448466
}
449467

468+
@Override
469+
public BuildableGetWithIndex readTag(String policyName, String readTag) {
470+
checkNotNull(policyName);
471+
checkNotNull(readTag);
472+
AbacOperationAttributes.setReadTag(attributes, policyName, readTag);
473+
return this;
474+
}
475+
450476
@Override
451477
public BuildableGetWithIndexOngoingWhere where(ConditionalExpression condition) {
452478
checkNotNull(condition);
@@ -602,7 +628,8 @@ public BuildableGetWithIndexOngoingWhereOr or(AndConditionSet andConditionSet) {
602628
public static class BuildableGetWithIndexWhere
603629
implements Consistency<BuildableGetWithIndexWhere>,
604630
Projection<BuildableGetWithIndexWhere>,
605-
Attribute<BuildableGetWithIndexWhere> {
631+
Attribute<BuildableGetWithIndexWhere>,
632+
AbacReadTagAttribute<BuildableGetWithIndexWhere> {
606633

607634
BuildableGetWithIndex buildableGetWithIndex;
608635
final SelectionBuilder.Where where;
@@ -657,6 +684,12 @@ public BuildableGetWithIndexWhere attributes(Map<String, String> attributes) {
657684
return this;
658685
}
659686

687+
@Override
688+
public BuildableGetWithIndexWhere readTag(String policyName, String readTag) {
689+
buildableGetWithIndex = buildableGetWithIndex.readTag(policyName, readTag);
690+
return this;
691+
}
692+
660693
public Get build() {
661694
return buildableGetWithIndex.build(getConjunctions(where));
662695
}
@@ -674,7 +707,8 @@ public static class BuildableGetOrGetWithIndexFromExisting extends BuildableGet
674707
ClearProjections<BuildableGetOrGetWithIndexFromExisting>,
675708
ClearClusteringKey<BuildableGetOrGetWithIndexFromExisting>,
676709
ClearNamespace<BuildableGetOrGetWithIndexFromExisting>,
677-
ClearAttribute<BuildableGetOrGetWithIndexFromExisting> {
710+
ClearAttribute<BuildableGetOrGetWithIndexFromExisting>,
711+
ClearAbacReadTagAttribute<BuildableGetOrGetWithIndexFromExisting> {
678712

679713
private Key indexKey;
680714
private final boolean isGetWithIndex;
@@ -770,6 +804,12 @@ public BuildableGetOrGetWithIndexFromExisting attributes(Map<String, String> att
770804
return this;
771805
}
772806

807+
@Override
808+
public BuildableGet readTag(String policyName, String readTag) {
809+
super.readTag(policyName, readTag);
810+
return this;
811+
}
812+
773813
@Override
774814
public BuildableGetFromExistingWithOngoingWhere where(ConditionalExpression condition) {
775815
checkConditionsEmpty();
@@ -845,6 +885,18 @@ public BuildableGetOrGetWithIndexFromExisting clearAttribute(String name) {
845885
return this;
846886
}
847887

888+
@Override
889+
public BuildableGetOrGetWithIndexFromExisting clearReadTag(String policyName) {
890+
AbacOperationAttributes.clearReadTag(attributes, policyName);
891+
return this;
892+
}
893+
894+
@Override
895+
public BuildableGetOrGetWithIndexFromExisting clearReadTags() {
896+
AbacOperationAttributes.clearReadTags(attributes);
897+
return this;
898+
}
899+
848900
private void checkNotGet() {
849901
if (!isGetWithIndex) {
850902
throw new UnsupportedOperationException(
@@ -910,9 +962,11 @@ public static class BuildableGetFromExistingWithWhere
910962
Consistency<BuildableGetFromExistingWithWhere>,
911963
Projection<BuildableGetFromExistingWithWhere>,
912964
Attribute<BuildableGetFromExistingWithWhere>,
965+
AbacReadTagAttribute<BuildableGetFromExistingWithWhere>,
913966
ClearProjections<BuildableGetFromExistingWithWhere>,
914967
ClearNamespace<BuildableGetFromExistingWithWhere>,
915-
ClearAttribute<BuildableGetFromExistingWithWhere> {
968+
ClearAttribute<BuildableGetFromExistingWithWhere>,
969+
ClearAbacReadTagAttribute<BuildableGetFromExistingWithWhere> {
916970

917971
private final BuildableGetOrGetWithIndexFromExisting BuildableGetFromExisting;
918972
final SelectionBuilder.Where where;
@@ -999,6 +1053,12 @@ public BuildableGetFromExistingWithWhere attributes(Map<String, String> attribut
9991053
return this;
10001054
}
10011055

1056+
@Override
1057+
public BuildableGetFromExistingWithWhere readTag(String policyName, String readTag) {
1058+
BuildableGetFromExisting.readTag(policyName, readTag);
1059+
return this;
1060+
}
1061+
10021062
@Override
10031063
public BuildableGetFromExistingWithWhere clearProjections() {
10041064
BuildableGetFromExisting.clearProjections();
@@ -1023,6 +1083,18 @@ public BuildableGetFromExistingWithWhere clearAttribute(String name) {
10231083
return this;
10241084
}
10251085

1086+
@Override
1087+
public BuildableGetFromExistingWithWhere clearReadTag(String policyName) {
1088+
BuildableGetFromExisting.clearReadTag(policyName);
1089+
return this;
1090+
}
1091+
1092+
@Override
1093+
public BuildableGetFromExistingWithWhere clearReadTags() {
1094+
BuildableGetFromExisting.clearReadTags();
1095+
return this;
1096+
}
1097+
10261098
public Get build() {
10271099
return BuildableGetFromExisting.build(getConjunctions(where));
10281100
}

0 commit comments

Comments
 (0)