From 67721c62985f9a0e87033bd2b086aaa5481aa637 Mon Sep 17 00:00:00 2001 From: brfrn169 Date: Sat, 16 Nov 2024 13:02:10 +0900 Subject: [PATCH 01/11] Add admin interface and operation attributes things for Attribute-Based Access Control --- .../java/com/scalar/db/api/AbacAdmin.java | 755 ++++++++++++++++++ .../db/api/AbacOperationAttributes.java | 47 ++ .../java/com/scalar/db/api/DeleteBuilder.java | 64 +- .../db/api/DistributedTransactionAdmin.java | 2 +- .../java/com/scalar/db/api/GetBuilder.java | 80 +- .../com/scalar/db/api/OperationBuilder.java | 60 ++ .../java/com/scalar/db/api/ScanBuilder.java | 102 ++- .../java/com/scalar/db/api/UpdateBuilder.java | 64 +- .../java/com/scalar/db/api/UpsertBuilder.java | 66 +- .../DecoratedDistributedTransactionAdmin.java | 209 +++++ .../com/scalar/db/common/error/CoreError.java | 6 + .../db/api/AbacOperationAttributesTest.java | 152 ++++ .../com/scalar/db/api/DeleteBuilderTest.java | 64 +- .../com/scalar/db/api/GetBuilderTest.java | 103 ++- .../com/scalar/db/api/ScanBuilderTest.java | 167 +++- .../com/scalar/db/api/UpdateBuilderTest.java | 102 ++- .../com/scalar/db/api/UpsertBuilderTest.java | 100 ++- 17 files changed, 2038 insertions(+), 105 deletions(-) create mode 100644 core/src/main/java/com/scalar/db/api/AbacAdmin.java create mode 100644 core/src/main/java/com/scalar/db/api/AbacOperationAttributes.java create mode 100644 core/src/test/java/com/scalar/db/api/AbacOperationAttributesTest.java diff --git a/core/src/main/java/com/scalar/db/api/AbacAdmin.java b/core/src/main/java/com/scalar/db/api/AbacAdmin.java new file mode 100644 index 0000000000..8941ae07cb --- /dev/null +++ b/core/src/main/java/com/scalar/db/api/AbacAdmin.java @@ -0,0 +1,755 @@ +package com.scalar.db.api; + +import com.scalar.db.common.error.CoreError; +import com.scalar.db.exception.storage.ExecutionException; +import java.util.List; +import java.util.Optional; +import javax.annotation.Nullable; + +/** An interface for administrative operations for Attribute-Based Access Control. */ +public interface AbacAdmin { + + /** + * Creates a policy with the given name and data tag column name. + * + * @param policyName the policy name + * @param dataTagColumnName the data tag column name. If null, the default data tag column name is + * used + * @throws ExecutionException if the operation fails + */ + default void createPolicy(String policyName, @Nullable String dataTagColumnName) + throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Enables a policy with the given name. + * + * @param policyName the policy name + * @throws ExecutionException if the operation fails + */ + default void enablePolicy(String policyName) throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Disables a policy with the given name. + * + * @param policyName the policy name + * @throws ExecutionException if the operation fails + */ + default void disablePolicy(String policyName) throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Retrieves a policy with the given name. + * + * @param policyName the policy name + * @return the policy + * @throws ExecutionException if the operation fails + */ + default Optional getPolicy(String policyName) throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Retrieves all policies. + * + * @return the policies + * @throws ExecutionException if the operation fails + */ + default List getPolicies() throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Creates a level with the given short name, long name and level number for the given policy. + * + * @param policyName the policy name + * @param levelShortName the level short name + * @param levelLongName the level long name + * @param levelNumber the level number + * @throws ExecutionException if the operation fails + */ + default void createLevel( + String policyName, String levelShortName, String levelLongName, int levelNumber) + throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Drops a level with the given short name for the given policy. + * + * @param policyName the policy name + * @param levelShortName the level short name + * @throws ExecutionException if the operation fails + */ + default void dropLevel(String policyName, String levelShortName) throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Retrieves a level with the given short name for the given policy. + * + * @param policyName the policy name + * @param levelShortName the level short name + * @return the level + * @throws ExecutionException if the operation fails + */ + default Optional getLevel(String policyName, String levelShortName) + throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Retrieves all levels for the given policy. + * + * @param policyName the policy name + * @return the levels + * @throws ExecutionException if the operation fails + */ + default List getLevels(String policyName) throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Creates a compartment with the given short name and long name for the given policy. + * + * @param policyName the policy name + * @param compartmentShortName the compartment short name + * @param compartmentLongName the compartment long name + * @throws ExecutionException if the operation fails + */ + default void createCompartment( + String policyName, String compartmentShortName, String compartmentLongName) + throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Drops a compartment with the given short name for the given policy. + * + * @param policyName the policy name + * @param compartmentShortName the compartment short name + * @throws ExecutionException if the operation fails + */ + default void dropCompartment(String policyName, String compartmentShortName) + throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Retrieves a compartment with the given short name for the given policy. + * + * @param policyName the policy name + * @param compartmentShortName the compartment short name + * @return the compartment + * @throws ExecutionException if the operation fails + */ + default Optional getCompartment(String policyName, String compartmentShortName) + throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Retrieves all compartments for the given policy. + * + * @param policyName the policy name + * @return the compartments + * @throws ExecutionException if the operation fails + */ + default List getCompartments(String policyName) throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Creates a group with the given short name, long name and parent group short name for the given + * policy. + * + * @param policyName the policy name + * @param groupShortName the group short name + * @param groupLongName the group long name + * @param parentGroupShortName the parent group short name. If null, the group is a top-level + * group + * @throws ExecutionException if the operation fails + */ + default void createGroup( + String policyName, + String groupShortName, + String groupLongName, + @Nullable String parentGroupShortName) + throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Drops a group with the given short name for the given policy. + * + * @param policyName the policy name + * @param groupShortName the group short name + * @throws ExecutionException if the operation fails + */ + default void dropGroup(String policyName, String groupShortName) throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Retrieves a group with the given short name for the given policy. + * + * @param policyName the policy name + * @param groupShortName the group short name + * @return the group + * @throws ExecutionException if the operation fails + */ + default Optional getGroup(String policyName, String groupShortName) + throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Retrieves all groups for the given policy. + * + * @param policyName the policy name + * @return the groups + * @throws ExecutionException if the operation fails + */ + default List getGroups(String policyName) throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Sets levels to a user with the given username for the given policy. + * + * @param policyName the policy name + * @param username the username + * @param levelShortName the level short name + * @param defaultLevelShortName the default level short name. If null, the default is the level + * @param rowLevelShortName the row level short name. If null, the default is the default level + * @throws ExecutionException if the operation fails + */ + default void setLevelsToUser( + String policyName, + String username, + String levelShortName, + @Nullable String defaultLevelShortName, + @Nullable String rowLevelShortName) + throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Adds a compartment to a user with the given username for the given policy. Before adding the + * compartment, levels must be set to the user. + * + * @param policyName the policy name + * @param username the username + * @param compartmentShortName the compartment short name + * @param accessMode the access mode + * @param defaultCompartment whether the compartment is the default compartment + * @param rowCompartment whether the compartment is the row compartment + * @throws ExecutionException if the operation fails + */ + default void addCompartmentToUser( + String policyName, + String username, + String compartmentShortName, + AccessMode accessMode, + boolean defaultCompartment, + boolean rowCompartment) + throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Removes a compartment from a user with the given username for the given policy. + * + * @param policyName the policy name + * @param username the username + * @param compartmentShortName the compartment short name + * @throws ExecutionException if the operation fails + */ + default void removeCompartmentFromUser( + String policyName, String username, String compartmentShortName) throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Adds a group to a user with the given username for the given policy. Before adding the group, + * levels must be set to the user. + * + * @param policyName the policy name + * @param username the username + * @param groupShortName the group short name + * @param accessMode the access mode + * @param defaultGroup whether the group is the default group + * @param rowGroup whether the group is the row group + * @throws ExecutionException if the operation fails + */ + default void addGroupToUser( + String policyName, + String username, + String groupShortName, + AccessMode accessMode, + boolean defaultGroup, + boolean rowGroup) + throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Removes a group from a user with the given username for the given policy. + * + * @param policyName the policy name + * @param username the username + * @param groupShortName the group short name + * @throws ExecutionException if the operation fails + */ + default void removeGroupFromUser(String policyName, String username, String groupShortName) + throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Drops the user access for the given username for the given policy. + * + * @param policyName the policy name + * @param username the username + * @throws ExecutionException if the operation fails + */ + default void dropUserAccess(String policyName, String username) throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Retrieves the user tag information of a user with the given username for the given policy. + * + * @param policyName the policy name + * @param username the username + * @return the user tag information. If the user tag information is not registered, returns an + * empty optional + * @throws ExecutionException if the operation fails + */ + default Optional getUserTagInfo(String policyName, String username) + throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Applies a policy to a namespace. + * + * @param policyName the policy name + * @param namespaceName the namespace name + * @throws ExecutionException if the operation fails + */ + default void applyNamespacePolicy(String policyName, String namespaceName) + throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Enables a namespace policy. + * + * @param policyName the policy name + * @param namespaceName the namespace name + * @throws ExecutionException if the operation fails + */ + default void enableNamespacePolicy(String policyName, String namespaceName) + throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Disables a namespace policy. + * + * @param policyName the policy name + * @param namespaceName the namespace name + * @throws ExecutionException if the operation fails + */ + default void disableNamespacePolicy(String policyName, String namespaceName) + throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Retrieves the namespace policies. + * + * @return the namespaces policies + * @throws ExecutionException if the operation fails + */ + default List getNamespacePolicies() throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Applies a policy to a table. + * + * @param policyName the policy name + * @param namespaceName the namespace name + * @param tableName the table name + * @throws ExecutionException if the operation fails + */ + default void applyTablePolicy(String policyName, String namespaceName, String tableName) + throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Enables a table policy. + * + * @param policyName the policy name + * @param namespaceName the namespace name + * @param tableName the table name + * @throws ExecutionException if the operation fails + */ + default void enableTablePolicy(String policyName, String namespaceName, String tableName) + throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Disables a table policy. + * + * @param policyName the policy name + * @param namespaceName the namespace name + * @param tableName the table name + * @throws ExecutionException if the operation fails + */ + default void disableTablePolicy(String policyName, String namespaceName, String tableName) + throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** + * Retrieves the table policies. + * + * @return the table policies + * @throws ExecutionException if the operation fails + */ + default List getTablePolicies() throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + + /** The state of a policy. */ + enum PolicyState { + /** The policy is enabled. */ + ENABLED, + + /** The policy is disabled. */ + DISABLED + } + + /** The access mode for compartments and groups. */ + enum AccessMode { + /** The access mode for read only. */ + READ_ONLY, + + /** The access mode for read and write. */ + READ_WRITE + } + + /** A policy for ABAC. All components of ABAC are associated with a policy. */ + interface Policy { + /** + * Returns the policy name. + * + * @return the policy name + */ + String getName(); + + /** + * Returns the data tag column name. + * + * @return the data tag column name + */ + String getDataTagColumnName(); + + /** + * Returns the state of the policy. + * + * @return the state + */ + PolicyState getState(); + } + + /** A level that is one of the components of a tag in ABAC. */ + interface Level { + /** + * Returns the policy name. + * + * @return the policy name + */ + String getPolicyName(); + + /** + * Returns the short name of the level. + * + * @return the short name + */ + String getShortName(); + + /** + * Returns the long name of the level. + * + * @return the long name + */ + String getLongName(); + + /** + * Returns the level number. + * + * @return the level number + */ + int getLevelNumber(); + } + + /** A compartment that is one of the components of a tag in ABAC. */ + interface Compartment { + /** + * Returns the policy name. + * + * @return the policy name + */ + String getPolicyName(); + + /** + * Returns the short name of the compartment. + * + * @return the short name + */ + String getShortName(); + + /** + * Returns the long name of the compartment. + * + * @return the long name + */ + String getLongName(); + } + + /** A group that is one of the components of a tag in ABAC. */ + interface Group { + /** + * Returns the policy name. + * + * @return the policy name + */ + String getPolicyName(); + + /** + * Returns the short name of the group. + * + * @return the short name + */ + String getShortName(); + + /** + * Returns the long name of the group. + * + * @return the long name + */ + String getLongName(); + + /** + * Returns the parent group short name if the group is not a top-level group. + * + * @return the parent group short name. If the group is a top-level group, returns an empty + * optional + */ + Optional getParentGroupShortName(); + } + + /** The user tag information of a user for a policy in ABAC. */ + interface UserTagInfo { + + /** The level information. */ + interface LevelInfo { + /** + * Returns the level short name. + * + * @return the level short name + */ + String getLevelShortName(); + + /** + * Returns the default level short name. + * + * @return the default level short name + */ + String getDefaultLevelShortName(); + + /** + * Returns the row level short name. + * + * @return the row level short name + */ + String getRowLevelShortName(); + } + + /** The compartment information. */ + interface CompartmentInfo { + /** + * Returns the short names of the compartments that the user has read access to. + * + * @return the short names of the compartments that the user has read access to + */ + List getReadCompartmentShortNames(); + + /** + * Returns the short names of the compartments that the user has write access to. + * + * @return the short names of the compartments that the user has write access to + */ + List getWriteCompartmentShortNames(); + + /** + * Returns the short names of the default compartments that the user has read access to. + * + * @return the short names of the default compartments that the user has read access to + */ + List getDefaultReadCompartmentShortNames(); + + /** + * Returns the short names of the default compartments that the user has write access to. + * + * @return the short names of + */ + List getDefaultWriteCompartmentShortNames(); + + /** + * Returns the short names of the row compartments. + * + * @return the short names of the row compartments + */ + List getRowCompartmentShortNames(); + } + + /** The group information. */ + interface GroupInfo { + /** + * Returns the short names of the groups that the user has read access to. + * + * @return the short names of the groups that the user has read access to + */ + List getReadGroupShortNames(); + + /** + * Returns the short names of the groups that the user has write access to. + * + * @return the short names of the groups that the user has write access to + */ + List getWriteGroupShortNames(); + + /** + * Returns the short names of the default groups that the user has read access to. + * + * @return the short names of the default groups that the user has read access to + */ + List getDefaultReadGroupShortNames(); + + /** + * Returns the short names of the default groups that the user has write access to. + * + * @return the short names of the default groups that the user has write access to + */ + List getDefaultWriteGroupShortNames(); + + /** + * Returns the short names of the row groups. + * + * @return the short names of the row groups. + */ + List getRowGroupShortNames(); + } + + /** + * Returns the policy name. + * + * @return the policy name + */ + String getPolicyName(); + + /** + * Returns the username. + * + * @return the username + */ + String getUsername(); + + /** + * Returns the level information. + * + * @return the level information + */ + LevelInfo getLevelInfo(); + + /** + * Returns the compartment information. + * + * @return the compartment information + */ + CompartmentInfo getCompartmentInfo(); + + /** + * Returns the group information. + * + * @return the group information + */ + GroupInfo getGroupInfo(); + } + + /** The namespace policy. */ + interface NamespacePolicy { + /** + * Returns the policy name. + * + * @return the policy name + */ + String getPolicyName(); + + /** + * Returns the namespace name. + * + * @return the namespace name + */ + String getNamespaceName(); + + /** + * Returns the state of the policy. + * + * @return the state + */ + PolicyState getState(); + } + + /** The table policy. */ + interface TablePolicy { + /** + * Returns the policy name. + * + * @return the policy name + */ + String getPolicyName(); + + /** + * Returns the namespace name. + * + * @return the namespace name + */ + String getNamespaceName(); + + /** + * Returns the table name. + * + * @return the table name + */ + String getTableName(); + + /** + * Returns the state of the policy. + * + * @return the state + */ + PolicyState getState(); + } +} diff --git a/core/src/main/java/com/scalar/db/api/AbacOperationAttributes.java b/core/src/main/java/com/scalar/db/api/AbacOperationAttributes.java new file mode 100644 index 0000000000..5a8ddb286f --- /dev/null +++ b/core/src/main/java/com/scalar/db/api/AbacOperationAttributes.java @@ -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 attributes, String policyName, String readTag) { + attributes.put(READ_TAG_PREFIX + policyName, readTag); + } + + public static void clearReadTag(Map attributes, String policyName) { + attributes.remove(READ_TAG_PREFIX + policyName); + } + + public static void clearReadTags(Map attributes) { + attributes.entrySet().removeIf(e -> e.getKey().startsWith(READ_TAG_PREFIX)); + } + + public static void setWriteTag( + Map attributes, String policyName, String writeTag) { + attributes.put(WRITE_TAG_PREFIX + policyName, writeTag); + } + + public static void clearWriteTag(Map attributes, String policyName) { + attributes.remove(WRITE_TAG_PREFIX + policyName); + } + + public static void clearWriteTags(Map attributes) { + attributes.entrySet().removeIf(e -> e.getKey().startsWith(WRITE_TAG_PREFIX)); + } + + public static Optional getReadTag(Operation operation, String policyName) { + return operation.getAttribute(READ_TAG_PREFIX + policyName); + } + + public static Optional getWriteTag(Operation operation, String policyName) { + return operation.getAttribute(WRITE_TAG_PREFIX + policyName); + } +} diff --git a/core/src/main/java/com/scalar/db/api/DeleteBuilder.java b/core/src/main/java/com/scalar/db/api/DeleteBuilder.java index 0b2831d53a..e312d7d1a3 100644 --- a/core/src/main/java/com/scalar/db/api/DeleteBuilder.java +++ b/core/src/main/java/com/scalar/db/api/DeleteBuilder.java @@ -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; @@ -68,7 +72,9 @@ public static class Buildable extends OperationBuilder.Buildable implements ClusteringKey, Consistency, Condition, - Attribute { + Attribute, + AbacReadTagAttribute, + AbacWriteTagAttribute { @Nullable Key clusteringKey; @Nullable com.scalar.db.api.Consistency consistency; @Nullable MutationCondition condition; @@ -114,6 +120,22 @@ public Buildable attributes(Map 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( @@ -134,7 +156,9 @@ public static class BuildableFromExisting extends Buildable ClearCondition, ClearClusteringKey, ClearNamespace, - ClearAttribute { + ClearAttribute, + ClearAbacReadTagAttribute, + ClearAbacWriteTagAttribute { BuildableFromExisting(Delete delete) { super( @@ -192,6 +216,18 @@ public BuildableFromExisting attributes(Map 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); @@ -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; + } } } diff --git a/core/src/main/java/com/scalar/db/api/DistributedTransactionAdmin.java b/core/src/main/java/com/scalar/db/api/DistributedTransactionAdmin.java index 608a520062..3617e14270 100644 --- a/core/src/main/java/com/scalar/db/api/DistributedTransactionAdmin.java +++ b/core/src/main/java/com/scalar/db/api/DistributedTransactionAdmin.java @@ -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. diff --git a/core/src/main/java/com/scalar/db/api/GetBuilder.java b/core/src/main/java/com/scalar/db/api/GetBuilder.java index 1ce8882862..0b4d2f8de9 100644 --- a/core/src/main/java/com/scalar/db/api/GetBuilder.java +++ b/core/src/main/java/com/scalar/db/api/GetBuilder.java @@ -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; @@ -93,7 +95,8 @@ public static class BuildableGet extends Buildable implements ClusteringKey, Consistency, Projection, - Attribute { + Attribute, + AbacReadTagAttribute { final List projections = new ArrayList<>(); @Nullable Key clusteringKey; @Nullable com.scalar.db.api.Consistency consistency; @@ -158,6 +161,14 @@ public BuildableGet attributes(Map 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()); @@ -227,6 +238,12 @@ public BuildableGetWithPartitionKey attributes(Map 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); @@ -390,6 +407,7 @@ public static class BuildableGetWithIndex implements Consistency, Projection, Attribute, + AbacReadTagAttribute, OperationBuilder.Where, WhereAnd, WhereOr { @@ -447,6 +465,14 @@ public BuildableGetWithIndex attributes(Map 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); @@ -602,7 +628,8 @@ public BuildableGetWithIndexOngoingWhereOr or(AndConditionSet andConditionSet) { public static class BuildableGetWithIndexWhere implements Consistency, Projection, - Attribute { + Attribute, + AbacReadTagAttribute { BuildableGetWithIndex buildableGetWithIndex; final SelectionBuilder.Where where; @@ -657,6 +684,12 @@ public BuildableGetWithIndexWhere attributes(Map 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)); } @@ -674,7 +707,8 @@ public static class BuildableGetOrGetWithIndexFromExisting extends BuildableGet ClearProjections, ClearClusteringKey, ClearNamespace, - ClearAttribute { + ClearAttribute, + ClearAbacReadTagAttribute { private Key indexKey; private final boolean isGetWithIndex; @@ -770,6 +804,12 @@ public BuildableGetOrGetWithIndexFromExisting attributes(Map att return this; } + @Override + public BuildableGet readTag(String policyName, String readTag) { + super.readTag(policyName, readTag); + return this; + } + @Override public BuildableGetFromExistingWithOngoingWhere where(ConditionalExpression condition) { checkConditionsEmpty(); @@ -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( @@ -910,9 +962,11 @@ public static class BuildableGetFromExistingWithWhere Consistency, Projection, Attribute, + AbacReadTagAttribute, ClearProjections, ClearNamespace, - ClearAttribute { + ClearAttribute, + ClearAbacReadTagAttribute { private final BuildableGetOrGetWithIndexFromExisting BuildableGetFromExisting; final SelectionBuilder.Where where; @@ -999,6 +1053,12 @@ public BuildableGetFromExistingWithWhere attributes(Map attribut return this; } + @Override + public BuildableGetFromExistingWithWhere readTag(String policyName, String readTag) { + BuildableGetFromExisting.readTag(policyName, readTag); + return this; + } + @Override public BuildableGetFromExistingWithWhere clearProjections() { BuildableGetFromExisting.clearProjections(); @@ -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)); } diff --git a/core/src/main/java/com/scalar/db/api/OperationBuilder.java b/core/src/main/java/com/scalar/db/api/OperationBuilder.java index 7c54695ace..9b891ba188 100644 --- a/core/src/main/java/com/scalar/db/api/OperationBuilder.java +++ b/core/src/main/java/com/scalar/db/api/OperationBuilder.java @@ -586,6 +586,66 @@ public interface ClearAttribute { T clearAttribute(String name); } + public interface AbacReadTagAttribute { + /** + * Adds a read tag attribute for the specified policy. This is a utility method for + * Attribute-Based Access Control. + * + * @param policyName the policy name + * @param readTag the read tag + * @return the operation builder + */ + T readTag(String policyName, String readTag); + } + + public interface AbacWriteTagAttribute { + /** + * Adds a write tag attribute for the specified policy. This is a utility method for + * Attribute-Based Access Control. + * + * @param policyName the policy name + * @param writeTag the write tag + * @return the operation builder + */ + T writeTag(String policyName, String writeTag); + } + + public interface ClearAbacReadTagAttribute { + /** + * Clear the read tag attribute for the specified policy. This is a utility method for + * Attribute-Based Access Control. + * + * @param policyName the policy name + * @return the operation builder + */ + T clearReadTag(String policyName); + + /** + * Clear all read tags. This is a utility method for Attribute-Based Access Control. + * + * @return the operation builder + */ + T clearReadTags(); + } + + public interface ClearAbacWriteTagAttribute { + /** + * Clear the write tag attribute for the specified policy. This is a utility method for + * Attribute-Based Access Control. + * + * @param policyName the policy name + * @return the operation builder + */ + T clearWriteTag(String policyName); + + /** + * Clear all write tags. This is a utility method for Attribute-Based Access Control. + * + * @return the operation builder + */ + T clearWriteTags(); + } + public abstract static class TableBuilder implements Table { final String namespace; diff --git a/core/src/main/java/com/scalar/db/api/ScanBuilder.java b/core/src/main/java/com/scalar/db/api/ScanBuilder.java index 32a38c16bb..116c6c9bb2 100644 --- a/core/src/main/java/com/scalar/db/api/ScanBuilder.java +++ b/core/src/main/java/com/scalar/db/api/ScanBuilder.java @@ -4,10 +4,12 @@ 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.All; 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.ClearBoundaries; import com.scalar.db.api.OperationBuilder.ClearConditions; @@ -106,7 +108,8 @@ public static class BuildableScan extends Buildable Consistency, Projection, Limit, - Attribute { + Attribute, + AbacReadTagAttribute { final List orderings = new ArrayList<>(); final List projections = new ArrayList<>(); @Nullable Key startClusteringKey; @@ -215,6 +218,14 @@ public BuildableScan attributes(Map attributes) { return this; } + @Override + public BuildableScan readTag(String policyName, String readTag) { + checkNotNull(policyName); + checkNotNull(readTag); + AbacOperationAttributes.setReadTag(attributes, policyName, readTag); + return this; + } + @Override public Scan build() { return build(ImmutableSet.of()); @@ -330,6 +341,12 @@ public BuildableScanWithPartitionKey attributes(Map attributes) return this; } + @Override + public BuildableScan readTag(String policyName, String readTag) { + super.readTag(policyName, readTag); + return this; + } + @Override public BuildableScanWithOngoingWhere where(ConditionalExpression condition) { checkNotNull(condition); @@ -498,7 +515,8 @@ public static class BuildableScanWithIndex WhereAnd, WhereOr, Limit, - Attribute { + Attribute, + AbacReadTagAttribute { @Nullable private final String namespaceName; private final String tableName; private final Key indexKey; @@ -560,6 +578,14 @@ public BuildableScanWithIndex attributes(Map attributes) { return this; } + @Override + public BuildableScanWithIndex readTag(String policyName, String readTag) { + checkNotNull(policyName); + checkNotNull(readTag); + AbacOperationAttributes.setReadTag(attributes, policyName, readTag); + return this; + } + @Override public BuildableScanWithIndexOngoingWhere where(ConditionalExpression condition) { checkNotNull(condition); @@ -717,7 +743,8 @@ public static class BuildableScanWithIndexWhere implements Consistency, Projection, Limit, - Attribute { + Attribute, + AbacReadTagAttribute { BuildableScanWithIndex buildableScanWithIndex; final Where where; @@ -778,6 +805,12 @@ public BuildableScanWithIndexWhere attributes(Map attributes) { return this; } + @Override + public BuildableScanWithIndexWhere readTag(String policyName, String readTag) { + buildableScanWithIndex = buildableScanWithIndex.readTag(policyName, readTag); + return this; + } + public Scan build() { return buildableScanWithIndex.build(getConjunctions(where)); } @@ -791,7 +824,8 @@ public static class BuildableScanAll WhereAnd, WhereOr, Limit, - Attribute { + Attribute, + AbacReadTagAttribute { private final String namespaceName; private final String tableName; private final List orderings = new ArrayList<>(); @@ -871,6 +905,14 @@ public BuildableScanAll attributes(Map attributes) { return this; } + @Override + public BuildableScanAll readTag(String policyName, String readTag) { + checkNotNull(policyName); + checkNotNull(readTag); + AbacOperationAttributes.setReadTag(attributes, policyName, readTag); + return this; + } + @Override public BuildableScanAllWithOngoingWhere where(ConditionalExpression condition) { checkNotNull(condition); @@ -1028,7 +1070,8 @@ public static class BuildableScanAllWithWhere Projection, Ordering, Limit, - Attribute { + Attribute, + AbacReadTagAttribute { final BuildableScanAll buildableScanAll; final Where where; @@ -1106,6 +1149,12 @@ public BuildableScanAllWithWhere attributes(Map attributes) { return this; } + @Override + public BuildableScanAllWithWhere readTag(String policyName, String readTag) { + buildableScanAll.readTag(policyName, readTag); + return this; + } + public Scan build() { return buildableScanAll.build(getConjunctions(where)); } @@ -1124,7 +1173,8 @@ public static class BuildableScanOrScanAllFromExisting extends BuildableScan ClearOrderings, ClearBoundaries, ClearNamespace, - ClearAttribute { + ClearAttribute, + ClearAbacReadTagAttribute { private final boolean isScanWithIndex; private final boolean isScanAll; @@ -1210,6 +1260,12 @@ public BuildableScanOrScanAllFromExisting attributes(Map attribu return this; } + @Override + public BuildableScan readTag(String policyName, String readTag) { + super.readTag(policyName, readTag); + return this; + } + @Override public BuildableScanOrScanAllFromExisting projection(String projection) { super.projection(projection); @@ -1374,6 +1430,18 @@ public BuildableScanOrScanAllFromExisting clearAttribute(String name) { return this; } + @Override + public BuildableScanOrScanAllFromExisting clearReadTag(String policyName) { + AbacOperationAttributes.clearReadTag(attributes, policyName); + return this; + } + + @Override + public BuildableScanOrScanAllFromExisting clearReadTags() { + AbacOperationAttributes.clearReadTags(attributes); + return this; + } + private void checkNotScanWithIndexOrScanAll() { if (isScanWithIndex || isScanAll) { throw new UnsupportedOperationException( @@ -1466,10 +1534,12 @@ public static class BuildableScanFromExistingWithWhere Ordering, Limit, Attribute, + AbacReadTagAttribute, ClearProjections, ClearOrderings, ClearNamespace, - ClearAttribute { + ClearAttribute, + ClearAbacReadTagAttribute { private final BuildableScanOrScanAllFromExisting buildableScanFromExisting; final Where where; @@ -1584,6 +1654,12 @@ public BuildableScanFromExistingWithWhere attributes(Map attribu return this; } + @Override + public BuildableScanFromExistingWithWhere readTag(String policyName, String readTag) { + buildableScanFromExisting.readTag(policyName, readTag); + return this; + } + @Override public BuildableScanFromExistingWithWhere clearProjections() { buildableScanFromExisting.clearProjections(); @@ -1614,6 +1690,18 @@ public BuildableScanFromExistingWithWhere clearAttribute(String name) { return this; } + @Override + public BuildableScanFromExistingWithWhere clearReadTag(String policyName) { + buildableScanFromExisting.clearReadTag(policyName); + return this; + } + + @Override + public BuildableScanFromExistingWithWhere clearReadTags() { + buildableScanFromExisting.clearReadTags(); + return this; + } + public Scan build() { return buildableScanFromExisting.build(getConjunctions(where)); } diff --git a/core/src/main/java/com/scalar/db/api/UpdateBuilder.java b/core/src/main/java/com/scalar/db/api/UpdateBuilder.java index 3b9d1fdf03..69975a81eb 100644 --- a/core/src/main/java/com/scalar/db/api/UpdateBuilder.java +++ b/core/src/main/java/com/scalar/db/api/UpdateBuilder.java @@ -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; @@ -79,7 +83,9 @@ public static class Buildable extends OperationBuilder.Buildable implements ClusteringKey, Condition, Values, - Attribute { + Attribute, + AbacReadTagAttribute, + AbacWriteTagAttribute { final Map> columns = new LinkedHashMap<>(); @Nullable Key clusteringKey; @Nullable MutationCondition condition; @@ -111,6 +117,22 @@ public Buildable attributes(Map 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 Buildable condition(MutationCondition condition) { checkNotNull(condition); @@ -238,7 +260,9 @@ public static class BuildableFromExisting extends Buildable ClearValues, ClearCondition, ClearNamespace, - ClearAttribute { + ClearAttribute, + ClearAbacReadTagAttribute, + ClearAbacWriteTagAttribute { BuildableFromExisting(Update update) { super( @@ -290,6 +314,18 @@ public BuildableFromExisting attributes(Map 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); @@ -421,5 +457,29 @@ public BuildableFromExisting clearAttribute(String name) { 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; + } } } diff --git a/core/src/main/java/com/scalar/db/api/UpsertBuilder.java b/core/src/main/java/com/scalar/db/api/UpsertBuilder.java index f5d7189c94..f30f5dff24 100644 --- a/core/src/main/java/com/scalar/db/api/UpsertBuilder.java +++ b/core/src/main/java/com/scalar/db/api/UpsertBuilder.java @@ -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.ClearNamespace; @@ -74,7 +78,11 @@ public Buildable partitionKey(Key partitionKey) { } public static class Buildable extends OperationBuilder.Buildable - implements ClusteringKey, Values, Attribute { + implements ClusteringKey, + Values, + Attribute, + AbacReadTagAttribute, + AbacWriteTagAttribute { final Map> columns = new LinkedHashMap<>(); @Nullable Key clusteringKey; final Map attributes = new HashMap<>(); @@ -105,6 +113,22 @@ public Buildable attributes(Map 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 Buildable booleanValue(String columnName, boolean value) { columns.put(columnName, BooleanColumn.of(columnName, value)); @@ -223,7 +247,9 @@ public static class BuildableFromExisting extends Buildable ClearClusteringKey, ClearValues, ClearNamespace, - ClearAttribute { + ClearAttribute, + ClearAbacReadTagAttribute, + ClearAbacWriteTagAttribute { BuildableFromExisting(Upsert upsert) { super( @@ -274,6 +300,18 @@ public BuildableFromExisting attributes(Map 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 booleanValue(String columnName, boolean value) { super.booleanValue(columnName, value); @@ -393,5 +431,29 @@ public BuildableFromExisting clearAttribute(String name) { 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; + } } } diff --git a/core/src/main/java/com/scalar/db/common/DecoratedDistributedTransactionAdmin.java b/core/src/main/java/com/scalar/db/common/DecoratedDistributedTransactionAdmin.java index c33eb1bbc4..7f47ba7cdd 100644 --- a/core/src/main/java/com/scalar/db/common/DecoratedDistributedTransactionAdmin.java +++ b/core/src/main/java/com/scalar/db/common/DecoratedDistributedTransactionAdmin.java @@ -327,6 +327,215 @@ public Set getPrivileges(String username, String namespaceName, Strin return distributedTransactionAdmin.getPrivileges(username, namespaceName, tableName); } + @Override + public void createPolicy(String policyName, @Nullable String dataTagColumnName) + throws ExecutionException { + distributedTransactionAdmin.createPolicy(policyName, dataTagColumnName); + } + + @Override + public void enablePolicy(String policyName) throws ExecutionException { + distributedTransactionAdmin.enablePolicy(policyName); + } + + @Override + public void disablePolicy(String policyName) throws ExecutionException { + distributedTransactionAdmin.disablePolicy(policyName); + } + + @Override + public Optional getPolicy(String policyName) throws ExecutionException { + return distributedTransactionAdmin.getPolicy(policyName); + } + + @Override + public List getPolicies() throws ExecutionException { + return distributedTransactionAdmin.getPolicies(); + } + + @Override + public void createLevel( + String policyName, String levelShortName, String levelLongName, int levelNumber) + throws ExecutionException { + distributedTransactionAdmin.createLevel(policyName, levelShortName, levelLongName, levelNumber); + } + + @Override + public void dropLevel(String policyName, String levelShortName) throws ExecutionException { + distributedTransactionAdmin.dropLevel(policyName, levelShortName); + } + + @Override + public Optional getLevel(String policyName, String levelShortName) + throws ExecutionException { + return distributedTransactionAdmin.getLevel(policyName, levelShortName); + } + + @Override + public List getLevels(String policyName) throws ExecutionException { + return distributedTransactionAdmin.getLevels(policyName); + } + + @Override + public void createCompartment( + String policyName, String compartmentShortName, String compartmentLongName) + throws ExecutionException { + distributedTransactionAdmin.createCompartment( + policyName, compartmentShortName, compartmentLongName); + } + + @Override + public void dropCompartment(String policyName, String compartmentShortName) + throws ExecutionException { + distributedTransactionAdmin.dropCompartment(policyName, compartmentShortName); + } + + @Override + public Optional getCompartment(String policyName, String compartmentShortName) + throws ExecutionException { + return distributedTransactionAdmin.getCompartment(policyName, compartmentShortName); + } + + @Override + public List getCompartments(String policyName) throws ExecutionException { + return distributedTransactionAdmin.getCompartments(policyName); + } + + @Override + public void createGroup( + String policyName, + String groupShortName, + String groupLongName, + @Nullable String parentGroupShortName) + throws ExecutionException { + distributedTransactionAdmin.createGroup( + policyName, groupShortName, groupLongName, parentGroupShortName); + } + + @Override + public void dropGroup(String policyName, String groupShortName) throws ExecutionException { + distributedTransactionAdmin.dropGroup(policyName, groupShortName); + } + + @Override + public Optional getGroup(String policyName, String groupShortName) + throws ExecutionException { + return distributedTransactionAdmin.getGroup(policyName, groupShortName); + } + + @Override + public List getGroups(String policyName) throws ExecutionException { + return distributedTransactionAdmin.getGroups(policyName); + } + + @Override + public void setLevelsToUser( + String policyName, + String username, + String levelShortName, + @Nullable String defaultLevelShortName, + @Nullable String rowLevelShortName) + throws ExecutionException { + distributedTransactionAdmin.setLevelsToUser( + policyName, username, levelShortName, defaultLevelShortName, rowLevelShortName); + } + + @Override + public void addCompartmentToUser( + String policyName, + String username, + String compartmentShortName, + AccessMode accessMode, + boolean defaultCompartment, + boolean rowCompartment) + throws ExecutionException { + distributedTransactionAdmin.addCompartmentToUser( + policyName, username, compartmentShortName, accessMode, defaultCompartment, rowCompartment); + } + + @Override + public void removeCompartmentFromUser( + String policyName, String username, String compartmentShortName) throws ExecutionException { + distributedTransactionAdmin.removeCompartmentFromUser( + policyName, username, compartmentShortName); + } + + @Override + public void addGroupToUser( + String policyName, + String username, + String groupShortName, + AccessMode accessMode, + boolean defaultGroup, + boolean rowGroup) + throws ExecutionException { + distributedTransactionAdmin.addGroupToUser( + policyName, username, groupShortName, accessMode, defaultGroup, rowGroup); + } + + @Override + public void removeGroupFromUser(String policyName, String username, String groupShortName) + throws ExecutionException { + distributedTransactionAdmin.removeGroupFromUser(policyName, username, groupShortName); + } + + @Override + public void dropUserAccess(String policyName, String username) throws ExecutionException { + distributedTransactionAdmin.dropUserAccess(policyName, username); + } + + @Override + public Optional getUserTagInfo(String policyName, String username) + throws ExecutionException { + return distributedTransactionAdmin.getUserTagInfo(policyName, username); + } + + @Override + public void applyNamespacePolicy(String policyName, String namespaceName) + throws ExecutionException { + distributedTransactionAdmin.applyNamespacePolicy(policyName, namespaceName); + } + + @Override + public void enableNamespacePolicy(String policyName, String namespaceName) + throws ExecutionException { + distributedTransactionAdmin.enableNamespacePolicy(policyName, namespaceName); + } + + @Override + public void disableNamespacePolicy(String policyName, String namespaceName) + throws ExecutionException { + distributedTransactionAdmin.disableNamespacePolicy(policyName, namespaceName); + } + + @Override + public List getNamespacePolicies() throws ExecutionException { + return distributedTransactionAdmin.getNamespacePolicies(); + } + + @Override + public void applyTablePolicy(String policyName, String namespaceName, String tableName) + throws ExecutionException { + distributedTransactionAdmin.applyTablePolicy(policyName, namespaceName, tableName); + } + + @Override + public void enableTablePolicy(String policyName, String namespaceName, String tableName) + throws ExecutionException { + distributedTransactionAdmin.enableTablePolicy(policyName, namespaceName, tableName); + } + + @Override + public void disableTablePolicy(String policyName, String namespaceName, String tableName) + throws ExecutionException { + distributedTransactionAdmin.disableTablePolicy(policyName, namespaceName, tableName); + } + + @Override + public List getTablePolicies() throws ExecutionException { + return distributedTransactionAdmin.getTablePolicies(); + } + @Override public void close() { distributedTransactionAdmin.close(); diff --git a/core/src/main/java/com/scalar/db/common/error/CoreError.java b/core/src/main/java/com/scalar/db/common/error/CoreError.java index 4325ef0090..3a24c9e91f 100644 --- a/core/src/main/java/com/scalar/db/common/error/CoreError.java +++ b/core/src/main/java/com/scalar/db/common/error/CoreError.java @@ -688,6 +688,12 @@ public enum CoreError implements ScalarDbError { "Invalid number specified for column %s in table %s in namespace %s", "", ""), + ABAC_NOT_ENABLED( + Category.USER_ERROR, + "0151", + "The Attribute-Based Access Control feature is not enabled. To use this feature, you must enable it. Note that this feature is supported only in the ScalarDB Enterprise edition", + "", + ""), // // Errors for the concurrency error category diff --git a/core/src/test/java/com/scalar/db/api/AbacOperationAttributesTest.java b/core/src/test/java/com/scalar/db/api/AbacOperationAttributesTest.java new file mode 100644 index 0000000000..56ed98af0f --- /dev/null +++ b/core/src/test/java/com/scalar/db/api/AbacOperationAttributesTest.java @@ -0,0 +1,152 @@ +package com.scalar.db.api; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.scalar.db.io.Key; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import org.junit.jupiter.api.Test; + +public class AbacOperationAttributesTest { + + @Test + public void setReadTag_ShouldSetReadTag() { + // Arrange + Map attributes = new HashMap<>(); + String policyName = "policyName"; + String readTag = "readTag"; + + // Act + AbacOperationAttributes.setReadTag(attributes, policyName, readTag); + + // Assert + assertThat(attributes) + .containsEntry(AbacOperationAttributes.READ_TAG_PREFIX + policyName, readTag); + } + + @Test + public void clearReadTag_ShouldClearReadTag() { + // Arrange + Map attributes = new HashMap<>(); + String policyName = "policyName"; + String readTag = "readTag"; + AbacOperationAttributes.setReadTag(attributes, policyName, readTag); + + // Act + AbacOperationAttributes.clearReadTag(attributes, policyName); + + // Assert + assertThat(attributes).doesNotContainKey(AbacOperationAttributes.READ_TAG_PREFIX + policyName); + } + + @Test + public void clearReadTags_ShouldClearReadTags() { + // Arrange + Map attributes = new HashMap<>(); + String policyName1 = "policyName1"; + String policyName2 = "policyName2"; + String readTag1 = "readTag1"; + String readTag2 = "readTag2"; + AbacOperationAttributes.setReadTag(attributes, policyName1, readTag1); + AbacOperationAttributes.setReadTag(attributes, policyName2, readTag2); + + // Act + AbacOperationAttributes.clearReadTags(attributes); + + // Assert + assertThat(attributes).doesNotContainKey(AbacOperationAttributes.READ_TAG_PREFIX + policyName1); + assertThat(attributes).doesNotContainKey(AbacOperationAttributes.READ_TAG_PREFIX + policyName2); + } + + @Test + public void setWriteTag_ShouldSetWriteTag() { + // Arrange + Map attributes = new HashMap<>(); + String policyName = "policyName"; + String writeTag = "writeTag"; + + // Act + AbacOperationAttributes.setWriteTag(attributes, policyName, writeTag); + + // Assert + assertThat(attributes) + .containsEntry(AbacOperationAttributes.WRITE_TAG_PREFIX + policyName, writeTag); + } + + @Test + public void clearWriteTag_ShouldClearWriteTag() { + // Arrange + Map attributes = new HashMap<>(); + String policyName = "policyName"; + String writeTag = "writeTag"; + AbacOperationAttributes.setWriteTag(attributes, policyName, writeTag); + + // Act + AbacOperationAttributes.clearWriteTag(attributes, policyName); + + // Assert + assertThat(attributes).doesNotContainKey(AbacOperationAttributes.WRITE_TAG_PREFIX + policyName); + } + + @Test + public void clearWriteTags_ShouldClearWriteTags() { + // Arrange + Map attributes = new HashMap<>(); + String policyName1 = "policyName1"; + String policyName2 = "policyName2"; + String writeTag1 = "writeTag1"; + String writeTag2 = "writeTag2"; + AbacOperationAttributes.setWriteTag(attributes, policyName1, writeTag1); + AbacOperationAttributes.setWriteTag(attributes, policyName2, writeTag2); + + // Act + AbacOperationAttributes.clearWriteTags(attributes); + + // Assert + assertThat(attributes) + .doesNotContainKey(AbacOperationAttributes.WRITE_TAG_PREFIX + policyName1); + assertThat(attributes) + .doesNotContainKey(AbacOperationAttributes.WRITE_TAG_PREFIX + policyName2); + } + + @Test + public void getReadTag_ShouldReturnReadTag() { + // Arrange + String policyName = "policyName"; + String readTag = "readTag"; + Operation operation = + Get.newBuilder() + .namespace("ns") + .table("tbl") + .partitionKey(Key.ofInt("pk", 0)) + .readTag(policyName, readTag) + .build(); + + // Act + Optional actual = AbacOperationAttributes.getReadTag(operation, policyName); + + // Assert + assertThat(actual).hasValue(readTag); + } + + @Test + public void getWriteTag_ShouldReturnWriteTag() { + // Arrange + String policyName = "policyName"; + String writeTag = "writeTag"; + Operation operation = + Update.newBuilder() + .namespace("ns") + .table("tbl") + .partitionKey(Key.ofInt("pk", 0)) + .writeTag(policyName, writeTag) + .build(); + + // Act + Optional actual = AbacOperationAttributes.getWriteTag(operation, policyName); + + // Assert + assertThat(actual).hasValue(writeTag); + } +} diff --git a/core/src/test/java/com/scalar/db/api/DeleteBuilderTest.java b/core/src/test/java/com/scalar/db/api/DeleteBuilderTest.java index c704c8169e..853a87b356 100644 --- a/core/src/test/java/com/scalar/db/api/DeleteBuilderTest.java +++ b/core/src/test/java/com/scalar/db/api/DeleteBuilderTest.java @@ -66,6 +66,8 @@ public void build_WithAllParameters_ShouldBuildDeleteWithAllParameters() { .condition(condition1) .attribute("a1", "v1") .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) + .readTag("policyName1", "readTag") + .writeTag("policyName2", "writeTag") .build(); // Assert @@ -77,7 +79,17 @@ public void build_WithAllParameters_ShouldBuildDeleteWithAllParameters() { partitionKey1, clusteringKey1, Consistency.EVENTUAL, - ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), + ImmutableMap.of( + "a1", + "v1", + "a2", + "v2", + "a3", + "v3", + AbacOperationAttributes.READ_TAG_PREFIX + "policyName1", + "readTag", + AbacOperationAttributes.WRITE_TAG_PREFIX + "policyName2", + "writeTag"), condition1)); } @@ -101,7 +113,7 @@ public void build_FromExistingWithoutChange_ShouldCopy() { @Test public void build_FromExistingAndUpdateAllParameters_ShouldBuildDeleteWithUpdatedParameters() { // Arrange - Delete existingDelete = + Delete existingDelete1 = new Delete( NAMESPACE_1, TABLE_1, @@ -110,10 +122,23 @@ public void build_FromExistingAndUpdateAllParameters_ShouldBuildDeleteWithUpdate Consistency.LINEARIZABLE, ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), condition1); + Delete existingDelete2 = + new Delete( + NAMESPACE_1, + TABLE_1, + partitionKey1, + clusteringKey1, + Consistency.LINEARIZABLE, + ImmutableMap.of( + AbacOperationAttributes.READ_TAG_PREFIX + "policyName1", + "readTag", + AbacOperationAttributes.WRITE_TAG_PREFIX + "policyName2", + "writeTag"), + condition1); // Act - Delete newDelete = - Delete.newBuilder(existingDelete) + Delete newDelete1 = + Delete.newBuilder(existingDelete1) .partitionKey(partitionKey2) .clusteringKey(clusteringKey2) .namespace(NAMESPACE_2) @@ -124,10 +149,17 @@ public void build_FromExistingAndUpdateAllParameters_ShouldBuildDeleteWithUpdate .attribute("a4", "v4") .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) .clearAttribute("a7") + .readTag("policyName1", "readTag") + .writeTag("policyName2", "writeTag") + .build(); + Delete newDelete2 = + Delete.newBuilder(existingDelete2) + .clearReadTag("policyName1") + .clearWriteTag("policyName2") .build(); // Assert - assertThat(newDelete) + assertThat(newDelete1) .isEqualTo( new Delete( NAMESPACE_2, @@ -135,8 +167,28 @@ public void build_FromExistingAndUpdateAllParameters_ShouldBuildDeleteWithUpdate partitionKey2, clusteringKey2, Consistency.EVENTUAL, - ImmutableMap.of("a4", "v4", "a5", "v5", "a6", "v6"), + ImmutableMap.of( + "a4", + "v4", + "a5", + "v5", + "a6", + "v6", + AbacOperationAttributes.READ_TAG_PREFIX + "policyName1", + "readTag", + AbacOperationAttributes.WRITE_TAG_PREFIX + "policyName2", + "writeTag"), condition2)); + assertThat(newDelete2) + .isEqualTo( + new Delete( + NAMESPACE_1, + TABLE_1, + partitionKey1, + clusteringKey1, + Consistency.LINEARIZABLE, + ImmutableMap.of(), + condition1)); } @Test diff --git a/core/src/test/java/com/scalar/db/api/GetBuilderTest.java b/core/src/test/java/com/scalar/db/api/GetBuilderTest.java index e4a9bbd1a0..d99782ba33 100644 --- a/core/src/test/java/com/scalar/db/api/GetBuilderTest.java +++ b/core/src/test/java/com/scalar/db/api/GetBuilderTest.java @@ -9,6 +9,7 @@ import com.scalar.db.api.Selection.Conjunction; import com.scalar.db.io.Key; import java.util.Arrays; +import java.util.Collections; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; @@ -76,6 +77,7 @@ public void buildGet_WithClusteringKey_ShouldBuildGetWithClusteringKey() { .projections("c5", "c6") .attribute("a1", "v1") .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) + .readTag("policyName1", "readTag") .build(); // Assert @@ -87,7 +89,15 @@ public void buildGet_WithClusteringKey_ShouldBuildGetWithClusteringKey() { partitionKey1, clusteringKey1, Consistency.EVENTUAL, - ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), + ImmutableMap.of( + "a1", + "v1", + "a2", + "v2", + "a3", + "v3", + AbacOperationAttributes.READ_TAG_PREFIX + "policyName1", + "readTag"), Arrays.asList("c1", "c2", "c3", "c4", "c5", "c6"), ImmutableSet.of())); } @@ -627,7 +637,7 @@ public void buildGet_FromExistingWithoutChange_ShouldCopy() { public void buildGet_FromExistingAndUpdateAllParametersExceptConjunctions_ShouldBuildGetWithUpdatedParameters() { // Arrange - Get existingGet = + Get existingGet1 = new Get( NAMESPACE_1, TABLE_1, @@ -643,10 +653,20 @@ public void buildGet_FromExistingWithoutChange_ShouldCopy() { Conjunction.of( ConditionBuilder.column("ck4").isGreaterThanInt(10), ConditionBuilder.column("col1").isGreaterThanInt(10)))); + Get existingGet2 = + new Get( + NAMESPACE_1, + TABLE_1, + partitionKey1, + clusteringKey1, + Consistency.LINEARIZABLE, + ImmutableMap.of(AbacOperationAttributes.READ_TAG_PREFIX + "policyName1", "readTag"), + Collections.emptyList(), + ImmutableSet.of()); // Act - Get newGet = - Get.newBuilder(existingGet) + Get newGet1 = + Get.newBuilder(existingGet1) .partitionKey(partitionKey2) .clusteringKey(clusteringKey2) .namespace(NAMESPACE_2) @@ -660,10 +680,12 @@ public void buildGet_FromExistingWithoutChange_ShouldCopy() { .attribute("a4", "v4") .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) .clearAttribute("a7") + .readTag("policyName1", "readTag") .build(); + Get newGet2 = Get.newBuilder(existingGet2).clearReadTag("policyName1").build(); // Assert - assertThat(newGet) + assertThat(newGet1) .isEqualTo( new Get( NAMESPACE_2, @@ -671,7 +693,15 @@ public void buildGet_FromExistingWithoutChange_ShouldCopy() { partitionKey2, clusteringKey2, Consistency.EVENTUAL, - ImmutableMap.of("a4", "v4", "a5", "v5", "a6", "v6"), + ImmutableMap.of( + "a4", + "v4", + "a5", + "v5", + "a6", + "v6", + AbacOperationAttributes.READ_TAG_PREFIX + "policyName1", + "readTag"), Arrays.asList("c3", "c4", "c5", "c6", "c7"), ImmutableSet.of( Conjunction.of( @@ -680,6 +710,17 @@ public void buildGet_FromExistingWithoutChange_ShouldCopy() { Conjunction.of( ConditionBuilder.column("ck4").isGreaterThanInt(10), ConditionBuilder.column("col1").isGreaterThanInt(10))))); + assertThat(newGet2) + .isEqualTo( + new Get( + NAMESPACE_1, + TABLE_1, + partitionKey1, + clusteringKey1, + Consistency.LINEARIZABLE, + ImmutableMap.of(), + Collections.emptyList(), + ImmutableSet.of())); } @Test @@ -1230,6 +1271,7 @@ public void buildGetWithIndex_WithMandatoryParameters_ShouldBuildGetWithMandator .projections("c5", "c6") .attribute("a1", "v1") .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) + .readTag("policyName1", "readTag") .build(); // Assert @@ -1240,7 +1282,15 @@ public void buildGetWithIndex_WithMandatoryParameters_ShouldBuildGetWithMandator TABLE_1, indexKey1, Consistency.EVENTUAL, - ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), + ImmutableMap.of( + "a1", + "v1", + "a2", + "v2", + "a3", + "v3", + AbacOperationAttributes.READ_TAG_PREFIX + "policyName1", + "readTag"), Arrays.asList("c1", "c2", "c3", "c4", "c5", "c6"), ImmutableSet.of())); } @@ -1706,7 +1756,7 @@ public void buildGetWithIndex_FromExistingWithoutChange_ShouldCopy() { public void buildGetWithIndex_FromExistingAndUpdateAllParameters_ShouldBuildGetWithUpdatedParameters() { // Arrange - GetWithIndex existingGet = + GetWithIndex existingGet1 = new GetWithIndex( NAMESPACE_1, TABLE_1, @@ -1715,10 +1765,19 @@ public void buildGetWithIndex_FromExistingWithoutChange_ShouldCopy() { ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), Arrays.asList("c1", "c2"), ImmutableSet.of()); + GetWithIndex existingGet2 = + new GetWithIndex( + NAMESPACE_1, + TABLE_1, + indexKey1, + Consistency.EVENTUAL, + ImmutableMap.of(AbacOperationAttributes.READ_TAG_PREFIX + "policyName1", "readTag"), + Collections.emptyList(), + ImmutableSet.of()); // Act - Get newGet = - Get.newBuilder(existingGet) + Get newGet1 = + Get.newBuilder(existingGet1) .indexKey(indexKey2) .namespace(NAMESPACE_2) .table(TABLE_2) @@ -1731,19 +1790,39 @@ public void buildGetWithIndex_FromExistingWithoutChange_ShouldCopy() { .attribute("a4", "v4") .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) .clearAttribute("a7") + .readTag("policyName1", "readTag") .build(); + Get newGet2 = Get.newBuilder(existingGet2).clearReadTag("policyName1").build(); // Assert - assertThat(newGet) + assertThat(newGet1) .isEqualTo( new GetWithIndex( NAMESPACE_2, TABLE_2, indexKey2, Consistency.EVENTUAL, - ImmutableMap.of("a4", "v4", "a5", "v5", "a6", "v6"), + ImmutableMap.of( + "a4", + "v4", + "a5", + "v5", + "a6", + "v6", + AbacOperationAttributes.READ_TAG_PREFIX + "policyName1", + "readTag"), Arrays.asList("c3", "c4", "c5", "c6", "c7"), ImmutableSet.of())); + assertThat(newGet2) + .isEqualTo( + new GetWithIndex( + NAMESPACE_1, + TABLE_1, + indexKey1, + Consistency.EVENTUAL, + ImmutableMap.of(), + Collections.emptyList(), + ImmutableSet.of())); } @Test diff --git a/core/src/test/java/com/scalar/db/api/ScanBuilderTest.java b/core/src/test/java/com/scalar/db/api/ScanBuilderTest.java index 32b7b159f1..db8d8fe2c6 100644 --- a/core/src/test/java/com/scalar/db/api/ScanBuilderTest.java +++ b/core/src/test/java/com/scalar/db/api/ScanBuilderTest.java @@ -9,6 +9,7 @@ import com.scalar.db.api.Selection.Conjunction; import com.scalar.db.io.Key; import java.util.Arrays; +import java.util.Collections; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; @@ -102,6 +103,7 @@ public void buildScan_ScanWithAllParameters_ShouldBuildScanCorrectly() { .consistency(Consistency.EVENTUAL) .attribute("a1", "v1") .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) + .readTag("policyName1", "readTag") .build(); // Assert @@ -112,7 +114,15 @@ public void buildScan_ScanWithAllParameters_ShouldBuildScanCorrectly() { TABLE_1, partitionKey1, Consistency.EVENTUAL, - ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), + ImmutableMap.of( + "a1", + "v1", + "a2", + "v2", + "a3", + "v3", + AbacOperationAttributes.READ_TAG_PREFIX + "policyName1", + "readTag"), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of(), startClusteringKey1, @@ -201,7 +211,7 @@ public void buildScan_FromExistingWithoutChange_ShouldCopy() { @Test public void buildScan_FromExistingAndUpdateAllParameters_ShouldBuildScanWithUpdatedParameters() { // Arrange - Scan existingScan = + Scan existingScan1 = new Scan( NAMESPACE_1, TABLE_1, @@ -216,10 +226,25 @@ public void buildScan_FromExistingAndUpdateAllParameters_ShouldBuildScanWithUpda true, Arrays.asList(ordering1, ordering2), 10); + Scan existingScan2 = + new Scan( + NAMESPACE_1, + TABLE_1, + partitionKey1, + Consistency.EVENTUAL, + ImmutableMap.of(AbacOperationAttributes.READ_TAG_PREFIX + "policyName1", "readTag"), + Collections.emptyList(), + ImmutableSet.of(), + startClusteringKey1, + false, + endClusteringKey1, + false, + Arrays.asList(ordering1, ordering2), + 10); // Act - Scan newScan = - Scan.newBuilder(existingScan) + Scan newScan1 = + Scan.newBuilder(existingScan1) .namespace(NAMESPACE_2) .table(TABLE_2) .partitionKey(partitionKey2) @@ -239,17 +264,27 @@ public void buildScan_FromExistingAndUpdateAllParameters_ShouldBuildScanWithUpda .attribute("a4", "v4") .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) .clearAttribute("a7") + .readTag("policyName1", "readTag") .build(); + Scan newScan2 = Scan.newBuilder(existingScan2).clearReadTag("policyName1").build(); // Assert - assertThat(newScan) + assertThat(newScan1) .isEqualTo( new Scan( NAMESPACE_2, TABLE_2, partitionKey2, Consistency.LINEARIZABLE, - ImmutableMap.of("a4", "v4", "a5", "v5", "a6", "v6"), + ImmutableMap.of( + "a4", + "v4", + "a5", + "v5", + "a6", + "v6", + AbacOperationAttributes.READ_TAG_PREFIX + "policyName1", + "readTag"), Arrays.asList("pk2", "ck2", "ck3", "ck4", "ck5"), ImmutableSet.of(), startClusteringKey2, @@ -258,6 +293,22 @@ public void buildScan_FromExistingAndUpdateAllParameters_ShouldBuildScanWithUpda false, Arrays.asList(ordering3, ordering4, ordering5, ordering1, ordering2), 5)); + assertThat(newScan2) + .isEqualTo( + new Scan( + NAMESPACE_1, + TABLE_1, + partitionKey1, + Consistency.EVENTUAL, + ImmutableMap.of(), + Collections.emptyList(), + ImmutableSet.of(), + startClusteringKey1, + false, + endClusteringKey1, + false, + Arrays.asList(ordering1, ordering2), + 10)); } @Test @@ -329,6 +380,7 @@ public void buildScanAll_ScanWithAllParameters_ShouldBuildScanCorrectly() { .where(ConditionBuilder.column("ck1").isGreaterThanInt(10)) .attribute("a1", "v1") .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) + .readTag("policyName1", "readTag") .build(); // Assert @@ -338,7 +390,15 @@ public void buildScanAll_ScanWithAllParameters_ShouldBuildScanCorrectly() { NAMESPACE_1, TABLE_1, Consistency.EVENTUAL, - ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), + ImmutableMap.of( + "a1", + "v1", + "a2", + "v2", + "a3", + "v3", + AbacOperationAttributes.READ_TAG_PREFIX + "policyName1", + "readTag"), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of( Conjunction.of(ConditionBuilder.column("ck1").isGreaterThanInt(10))), @@ -368,7 +428,7 @@ public void buildScanAll_FromExistingWithoutChange_ShouldCopy() { public void buildScanAll_FromExistingAndUpdateAllParameters_ShouldBuildScanWithUpdatedParameters() { // Arrange - Scan existingScan = + Scan existingScan1 = new ScanAll( NAMESPACE_1, TABLE_1, @@ -378,10 +438,20 @@ public void buildScanAll_FromExistingWithoutChange_ShouldCopy() { ImmutableSet.of(), ImmutableList.of(ordering1, ordering2), 10); + Scan existingScan2 = + new ScanAll( + NAMESPACE_1, + TABLE_1, + Consistency.EVENTUAL, + ImmutableMap.of(AbacOperationAttributes.READ_TAG_PREFIX + "policyName1", "readTag"), + Collections.emptyList(), + ImmutableSet.of(), + ImmutableList.of(ordering1, ordering2), + 10); // Act - Scan newScan = - Scan.newBuilder(existingScan) + Scan newScan1 = + Scan.newBuilder(existingScan1) .namespace(NAMESPACE_2) .table(TABLE_2) .limit(5) @@ -398,20 +468,41 @@ public void buildScanAll_FromExistingWithoutChange_ShouldCopy() { .attribute("a4", "v4") .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) .clearAttribute("a7") + .readTag("policyName1", "readTag") .build(); + Scan newScan2 = Scan.newBuilder(existingScan2).clearReadTag("policyName1").build(); // Assert - assertThat(newScan) + assertThat(newScan1) .isEqualTo( new ScanAll( NAMESPACE_2, TABLE_2, Consistency.LINEARIZABLE, - ImmutableMap.of("a4", "v4", "a5", "v5", "a6", "v6"), + ImmutableMap.of( + "a4", + "v4", + "a5", + "v5", + "a6", + "v6", + AbacOperationAttributes.READ_TAG_PREFIX + "policyName1", + "readTag"), Arrays.asList("pk2", "ck2", "ck3", "ck4", "ck5"), ImmutableSet.of(), ImmutableList.of(ordering3, ordering4, ordering5, ordering1, ordering2), 5)); + assertThat(newScan2) + .isEqualTo( + new ScanAll( + NAMESPACE_1, + TABLE_1, + Consistency.EVENTUAL, + ImmutableMap.of(), + Collections.emptyList(), + ImmutableSet.of(), + ImmutableList.of(ordering1, ordering2), + 10)); } @Test @@ -475,6 +566,7 @@ public void buildScanWithIndex_ScanWithAllParameters_ShouldBuildScanCorrectly() .consistency(Consistency.EVENTUAL) .attribute("a1", "v1") .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) + .readTag("policyName1", "readTag") .build(); // Assert @@ -485,7 +577,15 @@ public void buildScanWithIndex_ScanWithAllParameters_ShouldBuildScanCorrectly() TABLE_1, indexKey1, Consistency.EVENTUAL, - ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3"), + ImmutableMap.of( + "a1", + "v1", + "a2", + "v2", + "a3", + "v3", + AbacOperationAttributes.READ_TAG_PREFIX + "policyName1", + "readTag"), Arrays.asList("pk1", "ck1", "ck2", "ck3", "ck4"), ImmutableSet.of(), 10)); @@ -513,7 +613,7 @@ public void buildScanWithIndex_FromExistingWithoutChange_ShouldCopy() { public void buildScanWithIndex_FromExistingAndUpdateAllParameters_ShouldBuildScanWithUpdatedParameters() { // Arrange - Scan existingScan = + Scan existingScan1 = new ScanWithIndex( NAMESPACE_1, TABLE_1, @@ -523,10 +623,20 @@ public void buildScanWithIndex_FromExistingWithoutChange_ShouldCopy() { Arrays.asList("pk1", "ck1"), ImmutableSet.of(), 10); + Scan existingScan2 = + new ScanWithIndex( + NAMESPACE_1, + TABLE_1, + indexKey1, + Consistency.EVENTUAL, + ImmutableMap.of(AbacOperationAttributes.READ_TAG_PREFIX + "policyName1", "readTag"), + Collections.emptyList(), + ImmutableSet.of(), + 10); // Act - Scan newScan = - Scan.newBuilder(existingScan) + Scan newScan1 = + Scan.newBuilder(existingScan1) .namespace(NAMESPACE_2) .table(TABLE_2) .indexKey(indexKey2) @@ -540,20 +650,41 @@ public void buildScanWithIndex_FromExistingWithoutChange_ShouldCopy() { .attribute("a4", "v4") .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) .clearAttribute("a7") + .readTag("policyName1", "readTag") .build(); + Scan newScan2 = Scan.newBuilder(existingScan2).clearReadTag("policyName1").build(); // Assert - assertThat(newScan) + assertThat(newScan1) .isEqualTo( new ScanWithIndex( NAMESPACE_2, TABLE_2, indexKey2, Consistency.LINEARIZABLE, - ImmutableMap.of("a4", "v4", "a5", "v5", "a6", "v6"), + ImmutableMap.of( + "a4", + "v4", + "a5", + "v5", + "a6", + "v6", + AbacOperationAttributes.READ_TAG_PREFIX + "policyName1", + "readTag"), Arrays.asList("pk2", "ck2", "ck3", "ck4", "ck5"), ImmutableSet.of(), 5)); + assertThat(newScan2) + .isEqualTo( + new ScanWithIndex( + NAMESPACE_1, + TABLE_1, + indexKey1, + Consistency.EVENTUAL, + ImmutableMap.of(), + Collections.emptyList(), + ImmutableSet.of(), + 10)); } @Test diff --git a/core/src/test/java/com/scalar/db/api/UpdateBuilderTest.java b/core/src/test/java/com/scalar/db/api/UpdateBuilderTest.java index 92712d7b0c..1d2691138b 100644 --- a/core/src/test/java/com/scalar/db/api/UpdateBuilderTest.java +++ b/core/src/test/java/com/scalar/db/api/UpdateBuilderTest.java @@ -92,6 +92,8 @@ public void build_WithAllParameters_ShouldBuildUpdateCorrectly() { .condition(condition1) .attribute("a1", "v1") .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) + .readTag("policyName1", "readTag") + .writeTag("policyName2", "writeTag") .build(); // Assert @@ -123,7 +125,18 @@ public void build_WithAllParameters_ShouldBuildUpdateCorrectly() { assertThat(actual.getColumns().get("text2").getTextValue()).isEqualTo("another_value"); assertThat(actual.getCondition()).hasValue(condition1); assertThat(actual.getAttributes()) - .isEqualTo(ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3")); + .isEqualTo( + ImmutableMap.of( + "a1", + "v1", + "a2", + "v2", + "a3", + "v3", + AbacOperationAttributes.READ_TAG_PREFIX + "policyName1", + "readTag", + AbacOperationAttributes.WRITE_TAG_PREFIX + "policyName2", + "writeTag")); } @Test @@ -219,7 +232,7 @@ public void build_FromExistingWithoutChange_ShouldCopy() { @Test public void build_FromExistingAndUpdateAllParameters_ShouldBuildUpdateWithUpdatedParameters() { // Arrange - Update existingUpdate = + Update existingUpdate1 = Update.newBuilder() .namespace(NAMESPACE_1) .table(TABLE_1) @@ -243,10 +256,20 @@ public void build_FromExistingAndUpdateAllParameters_ShouldBuildUpdateWithUpdate .attribute("a1", "v1") .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); + Update existingUpdate2 = + Update.newBuilder() + .namespace(NAMESPACE_1) + .table(TABLE_1) + .partitionKey(partitionKey1) + .clusteringKey(clusteringKey1) + .bigIntValue("bigint1", BigIntColumn.MIN_VALUE) + .readTag("policyName1", "readTag") + .writeTag("policyName2", "writeTag") + .build(); // Act - Update newUpdate = - Update.newBuilder(existingUpdate) + Update newUpdate1 = + Update.newBuilder(existingUpdate1) .namespace(NAMESPACE_2) .table(TABLE_2) .partitionKey(partitionKey2) @@ -271,38 +294,65 @@ public void build_FromExistingAndUpdateAllParameters_ShouldBuildUpdateWithUpdate .attribute("a4", "v4") .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) .clearAttribute("a7") + .readTag("policyName1", "readTag") + .writeTag("policyName2", "writeTag") + .build(); + Update newUpdate2 = + Update.newBuilder(existingUpdate2) + .clearReadTag("policyName1") + .clearWriteTag("policyName2") .build(); // Assert - assertThat(newUpdate.forNamespace()).hasValue(NAMESPACE_2); - assertThat(newUpdate.forTable()).hasValue(TABLE_2); - Assertions.assertThat(newUpdate.getPartitionKey()).isEqualTo(partitionKey2); - assertThat(newUpdate.getClusteringKey()).hasValue(clusteringKey2); - assertThat(newUpdate.getColumns().size()).isEqualTo(14); - assertThat(newUpdate.getColumns().get("bigint1").getBigIntValue()) + assertThat(newUpdate1.forNamespace()).hasValue(NAMESPACE_2); + assertThat(newUpdate1.forTable()).hasValue(TABLE_2); + Assertions.assertThat(newUpdate1.getPartitionKey()).isEqualTo(partitionKey2); + assertThat(newUpdate1.getClusteringKey()).hasValue(clusteringKey2); + assertThat(newUpdate1.getColumns().size()).isEqualTo(14); + assertThat(newUpdate1.getColumns().get("bigint1").getBigIntValue()) .isEqualTo(BigIntColumn.MIN_VALUE); - assertThat(newUpdate.getColumns().get("bigint2").getBigIntValue()) + assertThat(newUpdate1.getColumns().get("bigint2").getBigIntValue()) .isEqualTo(Long.valueOf(BigIntColumn.MIN_VALUE)); - assertThat(newUpdate.getColumns().get("blob1").getBlobValueAsBytes()) + assertThat(newUpdate1.getColumns().get("blob1").getBlobValueAsBytes()) .isEqualTo("foo".getBytes(StandardCharsets.UTF_8)); - assertThat(newUpdate.getColumns().get("blob2").getBlobValueAsByteBuffer()) + assertThat(newUpdate1.getColumns().get("blob2").getBlobValueAsByteBuffer()) .isEqualTo(ByteBuffer.allocate(2)); - assertThat(newUpdate.getColumns().get("bool1").getBooleanValue()).isFalse(); - assertThat(newUpdate.getColumns().get("bool2").getBooleanValue()).isFalse(); - assertThat(newUpdate.getColumns().get("double1").getDoubleValue()).isEqualTo(Double.MIN_VALUE); - assertThat(newUpdate.getColumns().get("double2").getDoubleValue()) + assertThat(newUpdate1.getColumns().get("bool1").getBooleanValue()).isFalse(); + assertThat(newUpdate1.getColumns().get("bool2").getBooleanValue()).isFalse(); + assertThat(newUpdate1.getColumns().get("double1").getDoubleValue()).isEqualTo(Double.MIN_VALUE); + assertThat(newUpdate1.getColumns().get("double2").getDoubleValue()) .isEqualTo(Double.valueOf(Double.MIN_VALUE)); - assertThat(newUpdate.getColumns().get("float1").getFloatValue()).isEqualTo(Float.MIN_VALUE); - assertThat(newUpdate.getColumns().get("float2").getFloatValue()) + assertThat(newUpdate1.getColumns().get("float1").getFloatValue()).isEqualTo(Float.MIN_VALUE); + assertThat(newUpdate1.getColumns().get("float2").getFloatValue()) .isEqualTo(Float.valueOf(Float.MIN_VALUE)); - assertThat(newUpdate.getColumns().get("int1").getIntValue()).isEqualTo(Integer.MIN_VALUE); - assertThat(newUpdate.getColumns().get("int2").getIntValue()) + assertThat(newUpdate1.getColumns().get("int1").getIntValue()).isEqualTo(Integer.MIN_VALUE); + assertThat(newUpdate1.getColumns().get("int2").getIntValue()) .isEqualTo(Integer.valueOf(Integer.MIN_VALUE)); - assertThat(newUpdate.getColumns().get("text").getTextValue()).isEqualTo("another_value"); - assertThat(newUpdate.getColumns().get("text2").getTextValue()).isEqualTo("foo"); - assertThat(newUpdate.getCondition()).hasValue(condition2); - assertThat(newUpdate.getAttributes()) - .isEqualTo(ImmutableMap.of("a4", "v4", "a5", "v5", "a6", "v6")); + assertThat(newUpdate1.getColumns().get("text").getTextValue()).isEqualTo("another_value"); + assertThat(newUpdate1.getColumns().get("text2").getTextValue()).isEqualTo("foo"); + assertThat(newUpdate1.getCondition()).hasValue(condition2); + assertThat(newUpdate1.getAttributes()) + .isEqualTo( + ImmutableMap.of( + "a4", + "v4", + "a5", + "v5", + "a6", + "v6", + AbacOperationAttributes.READ_TAG_PREFIX + "policyName1", + "readTag", + AbacOperationAttributes.WRITE_TAG_PREFIX + "policyName2", + "writeTag")); + + assertThat(newUpdate2.forNamespace()).hasValue(NAMESPACE_1); + assertThat(newUpdate2.forTable()).hasValue(TABLE_1); + Assertions.assertThat(newUpdate2.getPartitionKey()).isEqualTo(partitionKey1); + assertThat(newUpdate2.getClusteringKey()).hasValue(clusteringKey1); + assertThat(newUpdate2.getColumns().size()).isEqualTo(1); + assertThat(newUpdate2.getColumns().get("bigint1").getBigIntValue()) + .isEqualTo(BigIntColumn.MIN_VALUE); + assertThat(newUpdate2.getAttributes()).isEmpty(); } @Test diff --git a/core/src/test/java/com/scalar/db/api/UpsertBuilderTest.java b/core/src/test/java/com/scalar/db/api/UpsertBuilderTest.java index 6fd92fb120..7d43a9c878 100644 --- a/core/src/test/java/com/scalar/db/api/UpsertBuilderTest.java +++ b/core/src/test/java/com/scalar/db/api/UpsertBuilderTest.java @@ -87,6 +87,8 @@ public void build_WithAllParameters_ShouldBuildUpsertCorrectly() { .value(TextColumn.of("text2", "another_value")) .attribute("a1", "v1") .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) + .readTag("policyName1", "readTag") + .writeTag("policyName2", "writeTag") .build(); // Assert @@ -117,7 +119,18 @@ public void build_WithAllParameters_ShouldBuildUpsertCorrectly() { assertThat(actual.getColumns().get("text").getTextValue()).isEqualTo("a_value"); assertThat(actual.getColumns().get("text2").getTextValue()).isEqualTo("another_value"); assertThat(actual.getAttributes()) - .isEqualTo(ImmutableMap.of("a1", "v1", "a2", "v2", "a3", "v3")); + .isEqualTo( + ImmutableMap.of( + "a1", + "v1", + "a2", + "v2", + "a3", + "v3", + AbacOperationAttributes.READ_TAG_PREFIX + "policyName1", + "readTag", + AbacOperationAttributes.WRITE_TAG_PREFIX + "policyName2", + "writeTag")); } @Test @@ -210,7 +223,7 @@ public void build_FromExistingWithoutChange_ShouldCopy() { @Test public void build_FromExistingAndUpdateAllParameters_ShouldBuildUpsertWithUpdatedParameters() { // Arrange - Upsert existingUpsert = + Upsert existingUpsert1 = Upsert.newBuilder() .namespace(NAMESPACE_1) .table(TABLE_1) @@ -233,10 +246,20 @@ public void build_FromExistingAndUpdateAllParameters_ShouldBuildUpsertWithUpdate .attribute("a1", "v1") .attributes(ImmutableMap.of("a2", "v2", "a3", "v3")) .build(); + Upsert existingUpsert2 = + Upsert.newBuilder() + .namespace(NAMESPACE_1) + .table(TABLE_1) + .partitionKey(partitionKey1) + .clusteringKey(clusteringKey1) + .bigIntValue("bigint1", BigIntColumn.MAX_VALUE) + .readTag("policyName1", "readTag") + .writeTag("policyName2", "writeTag") + .build(); // Act - Upsert newUpsert = - Upsert.newBuilder(existingUpsert) + Upsert newUpsert1 = + Upsert.newBuilder(existingUpsert1) .namespace(NAMESPACE_2) .table(TABLE_2) .partitionKey(partitionKey2) @@ -260,37 +283,64 @@ public void build_FromExistingAndUpdateAllParameters_ShouldBuildUpsertWithUpdate .attribute("a4", "v4") .attributes(ImmutableMap.of("a5", "v5", "a6", "v6", "a7", "v7")) .clearAttribute("a7") + .readTag("policyName1", "readTag") + .writeTag("policyName2", "writeTag") + .build(); + Upsert newUpsert2 = + Upsert.newBuilder(existingUpsert2) + .clearReadTag("policyName1") + .clearWriteTag("policyName2") .build(); // Assert - assertThat(newUpsert.forNamespace()).hasValue(NAMESPACE_2); - assertThat(newUpsert.forTable()).hasValue(TABLE_2); - Assertions.assertThat(newUpsert.getPartitionKey()).isEqualTo(partitionKey2); - assertThat(newUpsert.getClusteringKey()).hasValue(clusteringKey2); - assertThat(newUpsert.getColumns().size()).isEqualTo(14); - assertThat(newUpsert.getColumns().get("bigint1").getBigIntValue()) + assertThat(newUpsert1.forNamespace()).hasValue(NAMESPACE_2); + assertThat(newUpsert1.forTable()).hasValue(TABLE_2); + Assertions.assertThat(newUpsert1.getPartitionKey()).isEqualTo(partitionKey2); + assertThat(newUpsert1.getClusteringKey()).hasValue(clusteringKey2); + assertThat(newUpsert1.getColumns().size()).isEqualTo(14); + assertThat(newUpsert1.getColumns().get("bigint1").getBigIntValue()) .isEqualTo(BigIntColumn.MIN_VALUE); - assertThat(newUpsert.getColumns().get("bigint2").getBigIntValue()) + assertThat(newUpsert1.getColumns().get("bigint2").getBigIntValue()) .isEqualTo(Long.valueOf(BigIntColumn.MIN_VALUE)); - assertThat(newUpsert.getColumns().get("blob1").getBlobValueAsBytes()) + assertThat(newUpsert1.getColumns().get("blob1").getBlobValueAsBytes()) .isEqualTo("foo".getBytes(StandardCharsets.UTF_8)); - assertThat(newUpsert.getColumns().get("blob2").getBlobValueAsByteBuffer()) + assertThat(newUpsert1.getColumns().get("blob2").getBlobValueAsByteBuffer()) .isEqualTo(ByteBuffer.allocate(2)); - assertThat(newUpsert.getColumns().get("bool1").getBooleanValue()).isFalse(); - assertThat(newUpsert.getColumns().get("bool2").getBooleanValue()).isFalse(); - assertThat(newUpsert.getColumns().get("double1").getDoubleValue()).isEqualTo(Double.MIN_VALUE); - assertThat(newUpsert.getColumns().get("double2").getDoubleValue()) + assertThat(newUpsert1.getColumns().get("bool1").getBooleanValue()).isFalse(); + assertThat(newUpsert1.getColumns().get("bool2").getBooleanValue()).isFalse(); + assertThat(newUpsert1.getColumns().get("double1").getDoubleValue()).isEqualTo(Double.MIN_VALUE); + assertThat(newUpsert1.getColumns().get("double2").getDoubleValue()) .isEqualTo(Double.valueOf(Double.MIN_VALUE)); - assertThat(newUpsert.getColumns().get("float1").getFloatValue()).isEqualTo(Float.MIN_VALUE); - assertThat(newUpsert.getColumns().get("float2").getFloatValue()) + assertThat(newUpsert1.getColumns().get("float1").getFloatValue()).isEqualTo(Float.MIN_VALUE); + assertThat(newUpsert1.getColumns().get("float2").getFloatValue()) .isEqualTo(Float.valueOf(Float.MIN_VALUE)); - assertThat(newUpsert.getColumns().get("int1").getIntValue()).isEqualTo(Integer.MIN_VALUE); - assertThat(newUpsert.getColumns().get("int2").getIntValue()) + assertThat(newUpsert1.getColumns().get("int1").getIntValue()).isEqualTo(Integer.MIN_VALUE); + assertThat(newUpsert1.getColumns().get("int2").getIntValue()) .isEqualTo(Integer.valueOf(Integer.MIN_VALUE)); - assertThat(newUpsert.getColumns().get("text").getTextValue()).isEqualTo("another_value"); - assertThat(newUpsert.getColumns().get("text2").getTextValue()).isEqualTo("foo"); - assertThat(newUpsert.getAttributes()) - .isEqualTo(ImmutableMap.of("a4", "v4", "a5", "v5", "a6", "v6")); + assertThat(newUpsert1.getColumns().get("text").getTextValue()).isEqualTo("another_value"); + assertThat(newUpsert1.getColumns().get("text2").getTextValue()).isEqualTo("foo"); + assertThat(newUpsert1.getAttributes()) + .isEqualTo( + ImmutableMap.of( + "a4", + "v4", + "a5", + "v5", + "a6", + "v6", + AbacOperationAttributes.READ_TAG_PREFIX + "policyName1", + "readTag", + AbacOperationAttributes.WRITE_TAG_PREFIX + "policyName2", + "writeTag")); + + assertThat(newUpsert2.forNamespace()).hasValue(NAMESPACE_1); + assertThat(newUpsert2.forTable()).hasValue(TABLE_1); + Assertions.assertThat(newUpsert2.getPartitionKey()).isEqualTo(partitionKey1); + assertThat(newUpsert2.getClusteringKey()).hasValue(clusteringKey1); + assertThat(newUpsert2.getColumns().size()).isEqualTo(1); + assertThat(newUpsert2.getColumns().get("bigint1").getBigIntValue()) + .isEqualTo(BigIntColumn.MAX_VALUE); + assertThat(newUpsert2.getAttributes()).isEmpty(); } @Test From 11f38dbf38fd216b4ff005fe160c5fbd242ccc4f Mon Sep 17 00:00:00 2001 From: brfrn169 Date: Wed, 18 Dec 2024 13:39:29 +0900 Subject: [PATCH 02/11] Fix based on feedback --- core/src/main/java/com/scalar/db/common/error/CoreError.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/scalar/db/common/error/CoreError.java b/core/src/main/java/com/scalar/db/common/error/CoreError.java index 7966a68cc6..5d2eba33e5 100644 --- a/core/src/main/java/com/scalar/db/common/error/CoreError.java +++ b/core/src/main/java/com/scalar/db/common/error/CoreError.java @@ -693,7 +693,7 @@ public enum CoreError implements ScalarDbError { ABAC_NOT_ENABLED( Category.USER_ERROR, "0152", - "The Attribute-Based Access Control feature is not enabled. To use this feature, you must enable it. Note that this feature is supported only in the ScalarDB Enterprise edition", + "The attribute-based access control feature is not enabled. To use this feature, you must enable it. Note that this feature is supported only in the ScalarDB Enterprise edition", "", ""), From dd38c2a4d89fe00be0445affa51f6afcac3f92b2 Mon Sep 17 00:00:00 2001 From: Toshihiro Suzuki Date: Wed, 18 Dec 2024 13:43:58 +0900 Subject: [PATCH 03/11] [skip ci] Update core/src/main/java/com/scalar/db/api/AbacOperationAttributes.java Co-authored-by: Mitsunori Komatsu --- .../main/java/com/scalar/db/api/AbacOperationAttributes.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/com/scalar/db/api/AbacOperationAttributes.java b/core/src/main/java/com/scalar/db/api/AbacOperationAttributes.java index 5a8ddb286f..a2ae7a3515 100644 --- a/core/src/main/java/com/scalar/db/api/AbacOperationAttributes.java +++ b/core/src/main/java/com/scalar/db/api/AbacOperationAttributes.java @@ -8,7 +8,7 @@ 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"; + public static final String WRITE_TAG_PREFIX = OPERATION_ATTRIBUTE_PREFIX + "write-tag-"; private AbacOperationAttributes() {} From 967d7bd606efce034bfd8d453b43031ad0d63cc4 Mon Sep 17 00:00:00 2001 From: brfrn169 Date: Wed, 18 Dec 2024 16:00:22 +0900 Subject: [PATCH 04/11] Fix based on feedback --- core/src/main/java/com/scalar/db/api/AbacAdmin.java | 2 +- .../com/scalar/db/api/AbacOperationAttributes.java | 2 +- .../java/com/scalar/db/api/OperationBuilder.java | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/com/scalar/db/api/AbacAdmin.java b/core/src/main/java/com/scalar/db/api/AbacAdmin.java index 8941ae07cb..ecabb1326d 100644 --- a/core/src/main/java/com/scalar/db/api/AbacAdmin.java +++ b/core/src/main/java/com/scalar/db/api/AbacAdmin.java @@ -6,7 +6,7 @@ import java.util.Optional; import javax.annotation.Nullable; -/** An interface for administrative operations for Attribute-Based Access Control. */ +/** An interface for administrative operations for attribute-based access control. */ public interface AbacAdmin { /** diff --git a/core/src/main/java/com/scalar/db/api/AbacOperationAttributes.java b/core/src/main/java/com/scalar/db/api/AbacOperationAttributes.java index a2ae7a3515..b558f8726a 100644 --- a/core/src/main/java/com/scalar/db/api/AbacOperationAttributes.java +++ b/core/src/main/java/com/scalar/db/api/AbacOperationAttributes.java @@ -3,7 +3,7 @@ import java.util.Map; import java.util.Optional; -/** A utility class to manipulate the operation attributes for Attribute-Based Access Control. */ +/** 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-"; diff --git a/core/src/main/java/com/scalar/db/api/OperationBuilder.java b/core/src/main/java/com/scalar/db/api/OperationBuilder.java index 9b891ba188..6838222025 100644 --- a/core/src/main/java/com/scalar/db/api/OperationBuilder.java +++ b/core/src/main/java/com/scalar/db/api/OperationBuilder.java @@ -589,7 +589,7 @@ public interface ClearAttribute { public interface AbacReadTagAttribute { /** * Adds a read tag attribute for the specified policy. This is a utility method for - * Attribute-Based Access Control. + * attribute-based access control. * * @param policyName the policy name * @param readTag the read tag @@ -601,7 +601,7 @@ public interface AbacReadTagAttribute { public interface AbacWriteTagAttribute { /** * Adds a write tag attribute for the specified policy. This is a utility method for - * Attribute-Based Access Control. + * attribute-based access control. * * @param policyName the policy name * @param writeTag the write tag @@ -613,7 +613,7 @@ public interface AbacWriteTagAttribute { public interface ClearAbacReadTagAttribute { /** * Clear the read tag attribute for the specified policy. This is a utility method for - * Attribute-Based Access Control. + * attribute-based access control. * * @param policyName the policy name * @return the operation builder @@ -621,7 +621,7 @@ public interface ClearAbacReadTagAttribute { T clearReadTag(String policyName); /** - * Clear all read tags. This is a utility method for Attribute-Based Access Control. + * Clear all read tags. This is a utility method for attribute-based access control. * * @return the operation builder */ @@ -631,7 +631,7 @@ public interface ClearAbacReadTagAttribute { public interface ClearAbacWriteTagAttribute { /** * Clear the write tag attribute for the specified policy. This is a utility method for - * Attribute-Based Access Control. + * attribute-based access control. * * @param policyName the policy name * @return the operation builder @@ -639,7 +639,7 @@ public interface ClearAbacWriteTagAttribute { T clearWriteTag(String policyName); /** - * Clear all write tags. This is a utility method for Attribute-Based Access Control. + * Clear all write tags. This is a utility method for attribute-based access control. * * @return the operation builder */ From 661d076be1b490361bfbced93dda21c9f269ab36 Mon Sep 17 00:00:00 2001 From: brfrn169 Date: Wed, 18 Dec 2024 16:23:40 +0900 Subject: [PATCH 05/11] Fix Javadoc of AbacAdmin --- .../java/com/scalar/db/api/AbacAdmin.java | 74 ++++++++++--------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/core/src/main/java/com/scalar/db/api/AbacAdmin.java b/core/src/main/java/com/scalar/db/api/AbacAdmin.java index ecabb1326d..01e1632f4d 100644 --- a/core/src/main/java/com/scalar/db/api/AbacAdmin.java +++ b/core/src/main/java/com/scalar/db/api/AbacAdmin.java @@ -67,8 +67,8 @@ default List getPolicies() throws ExecutionException { * Creates a level with the given short name, long name and level number for the given policy. * * @param policyName the policy name - * @param levelShortName the level short name - * @param levelLongName the level long name + * @param levelShortName the short name of the level + * @param levelLongName the long name of the level * @param levelNumber the level number * @throws ExecutionException if the operation fails */ @@ -82,7 +82,7 @@ default void createLevel( * Drops a level with the given short name for the given policy. * * @param policyName the policy name - * @param levelShortName the level short name + * @param levelShortName the short name of the level * @throws ExecutionException if the operation fails */ default void dropLevel(String policyName, String levelShortName) throws ExecutionException { @@ -93,7 +93,7 @@ default void dropLevel(String policyName, String levelShortName) throws Executio * Retrieves a level with the given short name for the given policy. * * @param policyName the policy name - * @param levelShortName the level short name + * @param levelShortName the short name of the level * @return the level * @throws ExecutionException if the operation fails */ @@ -117,8 +117,8 @@ default List getLevels(String policyName) throws ExecutionException { * Creates a compartment with the given short name and long name for the given policy. * * @param policyName the policy name - * @param compartmentShortName the compartment short name - * @param compartmentLongName the compartment long name + * @param compartmentShortName the short name of the compartment + * @param compartmentLongName the long name of the compartment * @throws ExecutionException if the operation fails */ default void createCompartment( @@ -131,7 +131,7 @@ default void createCompartment( * Drops a compartment with the given short name for the given policy. * * @param policyName the policy name - * @param compartmentShortName the compartment short name + * @param compartmentShortName the short name of the compartment * @throws ExecutionException if the operation fails */ default void dropCompartment(String policyName, String compartmentShortName) @@ -143,7 +143,7 @@ default void dropCompartment(String policyName, String compartmentShortName) * Retrieves a compartment with the given short name for the given policy. * * @param policyName the policy name - * @param compartmentShortName the compartment short name + * @param compartmentShortName the short name of the compartment * @return the compartment * @throws ExecutionException if the operation fails */ @@ -164,14 +164,14 @@ default List getCompartments(String policyName) throws ExecutionExc } /** - * Creates a group with the given short name, long name and parent group short name for the given - * policy. + * Creates a group for the given policy with the specified short name, long name, and the short + * name of the parent group. * * @param policyName the policy name - * @param groupShortName the group short name - * @param groupLongName the group long name - * @param parentGroupShortName the parent group short name. If null, the group is a top-level - * group + * @param groupShortName the short name of the group + * @param groupLongName the long name of the group + * @param parentGroupShortName the short name of the parent group. If null, the group is a + * top-level group * @throws ExecutionException if the operation fails */ default void createGroup( @@ -187,7 +187,7 @@ default void createGroup( * Drops a group with the given short name for the given policy. * * @param policyName the policy name - * @param groupShortName the group short name + * @param groupShortName the short name of the group * @throws ExecutionException if the operation fails */ default void dropGroup(String policyName, String groupShortName) throws ExecutionException { @@ -198,7 +198,7 @@ default void dropGroup(String policyName, String groupShortName) throws Executio * Retrieves a group with the given short name for the given policy. * * @param policyName the policy name - * @param groupShortName the group short name + * @param groupShortName the short name of the group * @return the group * @throws ExecutionException if the operation fails */ @@ -223,9 +223,11 @@ default List getGroups(String policyName) throws ExecutionException { * * @param policyName the policy name * @param username the username - * @param levelShortName the level short name - * @param defaultLevelShortName the default level short name. If null, the default is the level - * @param rowLevelShortName the row level short name. If null, the default is the default level + * @param levelShortName the short name of the level to set + * @param defaultLevelShortName the short name of the default level. If null, the {@code + * levelShortName} will be used as the default level + * @param rowLevelShortName the short name of the row level. If null, the {@code + * defaultLevelShortName} will be used as the row level * @throws ExecutionException if the operation fails */ default void setLevelsToUser( @@ -244,7 +246,7 @@ default void setLevelsToUser( * * @param policyName the policy name * @param username the username - * @param compartmentShortName the compartment short name + * @param compartmentShortName the short name of the compartment to set * @param accessMode the access mode * @param defaultCompartment whether the compartment is the default compartment * @param rowCompartment whether the compartment is the row compartment @@ -266,7 +268,7 @@ default void addCompartmentToUser( * * @param policyName the policy name * @param username the username - * @param compartmentShortName the compartment short name + * @param compartmentShortName the short name of the compartment to remove * @throws ExecutionException if the operation fails */ default void removeCompartmentFromUser( @@ -280,7 +282,7 @@ default void removeCompartmentFromUser( * * @param policyName the policy name * @param username the username - * @param groupShortName the group short name + * @param groupShortName the short name of the group to set * @param accessMode the access mode * @param defaultGroup whether the group is the default group * @param rowGroup whether the group is the row group @@ -302,7 +304,7 @@ default void addGroupToUser( * * @param policyName the policy name * @param username the username - * @param groupShortName the group short name + * @param groupShortName the short name of the group to remove * @throws ExecutionException if the operation fails */ default void removeGroupFromUser(String policyName, String username, String groupShortName) @@ -484,14 +486,14 @@ interface Level { /** * Returns the short name of the level. * - * @return the short name + * @return the short name of the level */ String getShortName(); /** * Returns the long name of the level. * - * @return the long name + * @return the long name of the level */ String getLongName(); @@ -515,14 +517,14 @@ interface Compartment { /** * Returns the short name of the compartment. * - * @return the short name + * @return the short name of the compartment */ String getShortName(); /** * Returns the long name of the compartment. * - * @return the long name + * @return the long name of the compartment */ String getLongName(); } @@ -539,7 +541,7 @@ interface Group { /** * Returns the short name of the group. * - * @return the short name + * @return the short name of the group */ String getShortName(); @@ -565,23 +567,23 @@ interface UserTagInfo { /** The level information. */ interface LevelInfo { /** - * Returns the level short name. + * Returns the short name of the level. * - * @return the level short name + * @return the short name of the level */ String getLevelShortName(); /** - * Returns the default level short name. + * Returns the short name of the default level. * - * @return the default level short name + * @return the short name of the default level */ String getDefaultLevelShortName(); /** - * Returns the row level short name. + * Returns the short name of the row level. * - * @return the row level short name + * @return the short name of the row level */ String getRowLevelShortName(); } @@ -717,7 +719,7 @@ interface NamespacePolicy { /** * Returns the state of the policy. * - * @return the state + * @return the state of the policy */ PolicyState getState(); } @@ -748,7 +750,7 @@ interface TablePolicy { /** * Returns the state of the policy. * - * @return the state + * @return the state of the policy */ PolicyState getState(); } From 07b5e09a72c0874968ee55e31596c1c9cae28ba3 Mon Sep 17 00:00:00 2001 From: Toshihiro Suzuki Date: Fri, 20 Dec 2024 14:59:20 +0900 Subject: [PATCH 06/11] [skip ci] Apply suggestions from code review Co-authored-by: Hiroyuki Yamada --- .../java/com/scalar/db/api/AbacAdmin.java | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/core/src/main/java/com/scalar/db/api/AbacAdmin.java b/core/src/main/java/com/scalar/db/api/AbacAdmin.java index 01e1632f4d..3f6be4290f 100644 --- a/core/src/main/java/com/scalar/db/api/AbacAdmin.java +++ b/core/src/main/java/com/scalar/db/api/AbacAdmin.java @@ -23,7 +23,7 @@ default void createPolicy(String policyName, @Nullable String dataTagColumnName) } /** - * Enables a policy with the given name. + * Enables a policy that has the given name. * * @param policyName the policy name * @throws ExecutionException if the operation fails @@ -33,7 +33,7 @@ default void enablePolicy(String policyName) throws ExecutionException { } /** - * Disables a policy with the given name. + * Disables a policy that has the given name. * * @param policyName the policy name * @throws ExecutionException if the operation fails @@ -43,7 +43,7 @@ default void disablePolicy(String policyName) throws ExecutionException { } /** - * Retrieves a policy with the given name. + * Retrieves a policy that has the given name. * * @param policyName the policy name * @return the policy @@ -79,7 +79,7 @@ default void createLevel( } /** - * Drops a level with the given short name for the given policy. + * Drops a level that has the given short name for the given policy. * * @param policyName the policy name * @param levelShortName the short name of the level @@ -90,7 +90,7 @@ default void dropLevel(String policyName, String levelShortName) throws Executio } /** - * Retrieves a level with the given short name for the given policy. + * Retrieves a level that has the given short name for the given policy. * * @param policyName the policy name * @param levelShortName the short name of the level @@ -128,7 +128,7 @@ default void createCompartment( } /** - * Drops a compartment with the given short name for the given policy. + * Drops a compartment that has the given short name for the given policy. * * @param policyName the policy name * @param compartmentShortName the short name of the compartment @@ -140,7 +140,7 @@ default void dropCompartment(String policyName, String compartmentShortName) } /** - * Retrieves a compartment with the given short name for the given policy. + * Retrieves a compartment that has the given short name for the given policy. * * @param policyName the policy name * @param compartmentShortName the short name of the compartment @@ -184,7 +184,7 @@ default void createGroup( } /** - * Drops a group with the given short name for the given policy. + * Drops a group that has the given short name for the given policy. * * @param policyName the policy name * @param groupShortName the short name of the group @@ -195,7 +195,7 @@ default void dropGroup(String policyName, String groupShortName) throws Executio } /** - * Retrieves a group with the given short name for the given policy. + * Retrieves a group that has the given short name for the given policy. * * @param policyName the policy name * @param groupShortName the short name of the group @@ -219,7 +219,7 @@ default List getGroups(String policyName) throws ExecutionException { } /** - * Sets levels to a user with the given username for the given policy. + * Sets the given levels of the given policy to a user that has the given username. * * @param policyName the policy name * @param username the username @@ -241,7 +241,7 @@ default void setLevelsToUser( } /** - * Adds a compartment to a user with the given username for the given policy. Before adding the + * Adds the given compartment of the given policy to a user that has the given username. Before adding the * compartment, levels must be set to the user. * * @param policyName the policy name @@ -264,7 +264,7 @@ default void addCompartmentToUser( } /** - * Removes a compartment from a user with the given username for the given policy. + * Removes the given compartment of the given policy from a user that has the given username. * * @param policyName the policy name * @param username the username @@ -277,7 +277,7 @@ default void removeCompartmentFromUser( } /** - * Adds a group to a user with the given username for the given policy. Before adding the group, + * Adds the given group of the given policy to a user that has the given username. Before adding the group, * levels must be set to the user. * * @param policyName the policy name @@ -300,7 +300,7 @@ default void addGroupToUser( } /** - * Removes a group from a user with the given username for the given policy. + * Removes the given group of the given policy from a user that has the given username. * * @param policyName the policy name * @param username the username @@ -338,7 +338,7 @@ default Optional getUserTagInfo(String policyName, String username) } /** - * Applies a policy to a namespace. + * Applies the given policy to the given namespace. * * @param policyName the policy name * @param namespaceName the namespace name @@ -350,7 +350,7 @@ default void applyNamespacePolicy(String policyName, String namespaceName) } /** - * Enables a namespace policy. + * Enables the given policy for the given namespace. * * @param policyName the policy name * @param namespaceName the namespace name @@ -362,7 +362,7 @@ default void enableNamespacePolicy(String policyName, String namespaceName) } /** - * Disables a namespace policy. + * Disables the given policy for the given namespace. * * @param policyName the policy name * @param namespaceName the namespace name @@ -374,7 +374,7 @@ default void disableNamespacePolicy(String policyName, String namespaceName) } /** - * Retrieves the namespace policies. + * Retrieves all namespace policies. * * @return the namespaces policies * @throws ExecutionException if the operation fails @@ -384,7 +384,7 @@ default List getNamespacePolicies() throws ExecutionException { } /** - * Applies a policy to a table. + * Applies the given policy to the given table of the given namespace. * * @param policyName the policy name * @param namespaceName the namespace name @@ -397,7 +397,7 @@ default void applyTablePolicy(String policyName, String namespaceName, String ta } /** - * Enables a table policy. + * Enables the given policy of the given table of the given namespace. * * @param policyName the policy name * @param namespaceName the namespace name @@ -410,7 +410,7 @@ default void enableTablePolicy(String policyName, String namespaceName, String t } /** - * Disables a table policy. + * Disables the given policy of the given table of the given namespace. * * @param policyName the policy name * @param namespaceName the namespace name @@ -423,7 +423,7 @@ default void disableTablePolicy(String policyName, String namespaceName, String } /** - * Retrieves the table policies. + * Retrieves all table policies. * * @return the table policies * @throws ExecutionException if the operation fails From da47a33d97509280559201f6f5d5d05cb0068afa Mon Sep 17 00:00:00 2001 From: brfrn169 Date: Fri, 20 Dec 2024 15:08:27 +0900 Subject: [PATCH 07/11] Fix --- core/src/main/java/com/scalar/db/api/AbacAdmin.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/com/scalar/db/api/AbacAdmin.java b/core/src/main/java/com/scalar/db/api/AbacAdmin.java index 3f6be4290f..4f65d77a50 100644 --- a/core/src/main/java/com/scalar/db/api/AbacAdmin.java +++ b/core/src/main/java/com/scalar/db/api/AbacAdmin.java @@ -164,8 +164,8 @@ default List getCompartments(String policyName) throws ExecutionExc } /** - * Creates a group for the given policy with the specified short name, long name, and the short - * name of the parent group. + * Creates a group with the given short name, long name, and the short name of the parent group + * for the given policy. * * @param policyName the policy name * @param groupShortName the short name of the group @@ -241,8 +241,8 @@ default void setLevelsToUser( } /** - * Adds the given compartment of the given policy to a user that has the given username. Before adding the - * compartment, levels must be set to the user. + * Adds the given compartment of the given policy to a user that has the given username. Before + * adding the compartment, levels must be set to the user. * * @param policyName the policy name * @param username the username @@ -277,8 +277,8 @@ default void removeCompartmentFromUser( } /** - * Adds the given group of the given policy to a user that has the given username. Before adding the group, - * levels must be set to the user. + * Adds the given group of the given policy to a user that has the given username. Before adding + * the group, levels must be set to the user. * * @param policyName the policy name * @param username the username From 2c387a75f0db8f83fee32d78ed34462126e2ec82 Mon Sep 17 00:00:00 2001 From: brfrn169 Date: Mon, 23 Dec 2024 13:48:54 +0900 Subject: [PATCH 08/11] Rename method names --- core/src/main/java/com/scalar/db/api/AbacAdmin.java | 9 +++++---- .../DecoratedDistributedTransactionAdmin.java | 13 +++++++------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/com/scalar/db/api/AbacAdmin.java b/core/src/main/java/com/scalar/db/api/AbacAdmin.java index 4f65d77a50..62a2c033a2 100644 --- a/core/src/main/java/com/scalar/db/api/AbacAdmin.java +++ b/core/src/main/java/com/scalar/db/api/AbacAdmin.java @@ -313,13 +313,14 @@ default void removeGroupFromUser(String policyName, String username, String grou } /** - * Drops the user access for the given username for the given policy. + * Drops the user tag information of a user with the given username for the given policy. * * @param policyName the policy name * @param username the username * @throws ExecutionException if the operation fails */ - default void dropUserAccess(String policyName, String username) throws ExecutionException { + default void dropUserTagInfoFromUser(String policyName, String username) + throws ExecutionException { throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); } @@ -344,7 +345,7 @@ default Optional getUserTagInfo(String policyName, String username) * @param namespaceName the namespace name * @throws ExecutionException if the operation fails */ - default void applyNamespacePolicy(String policyName, String namespaceName) + default void applyPolicyToNamespace(String policyName, String namespaceName) throws ExecutionException { throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); } @@ -391,7 +392,7 @@ default List getNamespacePolicies() throws ExecutionException { * @param tableName the table name * @throws ExecutionException if the operation fails */ - default void applyTablePolicy(String policyName, String namespaceName, String tableName) + default void applyPolicyToTable(String policyName, String namespaceName, String tableName) throws ExecutionException { throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); } diff --git a/core/src/main/java/com/scalar/db/common/DecoratedDistributedTransactionAdmin.java b/core/src/main/java/com/scalar/db/common/DecoratedDistributedTransactionAdmin.java index 7f47ba7cdd..cb6ec9dfa3 100644 --- a/core/src/main/java/com/scalar/db/common/DecoratedDistributedTransactionAdmin.java +++ b/core/src/main/java/com/scalar/db/common/DecoratedDistributedTransactionAdmin.java @@ -480,8 +480,9 @@ public void removeGroupFromUser(String policyName, String username, String group } @Override - public void dropUserAccess(String policyName, String username) throws ExecutionException { - distributedTransactionAdmin.dropUserAccess(policyName, username); + public void dropUserTagInfoFromUser(String policyName, String username) + throws ExecutionException { + distributedTransactionAdmin.dropUserTagInfoFromUser(policyName, username); } @Override @@ -491,9 +492,9 @@ public Optional getUserTagInfo(String policyName, String username) } @Override - public void applyNamespacePolicy(String policyName, String namespaceName) + public void applyPolicyToNamespace(String policyName, String namespaceName) throws ExecutionException { - distributedTransactionAdmin.applyNamespacePolicy(policyName, namespaceName); + distributedTransactionAdmin.applyPolicyToNamespace(policyName, namespaceName); } @Override @@ -514,9 +515,9 @@ public List getNamespacePolicies() throws ExecutionException { } @Override - public void applyTablePolicy(String policyName, String namespaceName, String tableName) + public void applyPolicyToTable(String policyName, String namespaceName, String tableName) throws ExecutionException { - distributedTransactionAdmin.applyTablePolicy(policyName, namespaceName, tableName); + distributedTransactionAdmin.applyPolicyToTable(policyName, namespaceName, tableName); } @Override From d0fa05f3cb90f5fa38dd54714ef7263e6d11fc6a Mon Sep 17 00:00:00 2001 From: brfrn169 Date: Mon, 23 Dec 2024 16:28:48 +0900 Subject: [PATCH 09/11] Add methods to AbacAdmin --- .../java/com/scalar/db/api/AbacAdmin.java | 28 +++++++++++++++++++ .../DecoratedDistributedTransactionAdmin.java | 12 ++++++++ 2 files changed, 40 insertions(+) diff --git a/core/src/main/java/com/scalar/db/api/AbacAdmin.java b/core/src/main/java/com/scalar/db/api/AbacAdmin.java index 62a2c033a2..e2b377190d 100644 --- a/core/src/main/java/com/scalar/db/api/AbacAdmin.java +++ b/core/src/main/java/com/scalar/db/api/AbacAdmin.java @@ -374,6 +374,20 @@ default void disableNamespacePolicy(String policyName, String namespaceName) throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); } + /** + * Retrieves the namespace policy for the given namespace. + * + * @param policyName the policy name + * @param namespaceName the namespace name + * @return the namespace policy. If the policy is not applied to the namespace, returns an empty + * optional + * @throws ExecutionException if the operation fails + */ + default Optional getNamespacePolicy(String policyName, String namespaceName) + throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + /** * Retrieves all namespace policies. * @@ -423,6 +437,20 @@ default void disableTablePolicy(String policyName, String namespaceName, String throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); } + /** + * Retrieves the table policy for the given table of the given namespace. + * + * @param policyName the policy name + * @param namespaceName the namespace name + * @param tableName the table name + * @return the table policy. If the policy is not applied to the table, returns an empty optional + * @throws ExecutionException if the operation fails + */ + default Optional getTablePolicy( + String policyName, String namespaceName, String tableName) throws ExecutionException { + throw new UnsupportedOperationException(CoreError.ABAC_NOT_ENABLED.buildMessage()); + } + /** * Retrieves all table policies. * diff --git a/core/src/main/java/com/scalar/db/common/DecoratedDistributedTransactionAdmin.java b/core/src/main/java/com/scalar/db/common/DecoratedDistributedTransactionAdmin.java index cb6ec9dfa3..518fd40549 100644 --- a/core/src/main/java/com/scalar/db/common/DecoratedDistributedTransactionAdmin.java +++ b/core/src/main/java/com/scalar/db/common/DecoratedDistributedTransactionAdmin.java @@ -509,6 +509,12 @@ public void disableNamespacePolicy(String policyName, String namespaceName) distributedTransactionAdmin.disableNamespacePolicy(policyName, namespaceName); } + @Override + public Optional getNamespacePolicy(String policyName, String namespaceName) + throws ExecutionException { + return distributedTransactionAdmin.getNamespacePolicy(policyName, namespaceName); + } + @Override public List getNamespacePolicies() throws ExecutionException { return distributedTransactionAdmin.getNamespacePolicies(); @@ -532,6 +538,12 @@ public void disableTablePolicy(String policyName, String namespaceName, String t distributedTransactionAdmin.disableTablePolicy(policyName, namespaceName, tableName); } + @Override + public Optional getTablePolicy( + String policyName, String namespaceName, String tableName) throws ExecutionException { + return distributedTransactionAdmin.getTablePolicy(policyName, namespaceName, tableName); + } + @Override public List getTablePolicies() throws ExecutionException { return distributedTransactionAdmin.getTablePolicies(); From 960cf2bf0d77830b42c1743bbe05c23cbd919480 Mon Sep 17 00:00:00 2001 From: brfrn169 Date: Mon, 23 Dec 2024 17:09:23 +0900 Subject: [PATCH 10/11] Fix --- core/src/main/java/com/scalar/db/api/AbacAdmin.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/scalar/db/api/AbacAdmin.java b/core/src/main/java/com/scalar/db/api/AbacAdmin.java index e2b377190d..dcac49670f 100644 --- a/core/src/main/java/com/scalar/db/api/AbacAdmin.java +++ b/core/src/main/java/com/scalar/db/api/AbacAdmin.java @@ -246,7 +246,7 @@ default void setLevelsToUser( * * @param policyName the policy name * @param username the username - * @param compartmentShortName the short name of the compartment to set + * @param compartmentShortName the short name of the compartment * @param accessMode the access mode * @param defaultCompartment whether the compartment is the default compartment * @param rowCompartment whether the compartment is the row compartment @@ -268,7 +268,7 @@ default void addCompartmentToUser( * * @param policyName the policy name * @param username the username - * @param compartmentShortName the short name of the compartment to remove + * @param compartmentShortName the short name of the compartment * @throws ExecutionException if the operation fails */ default void removeCompartmentFromUser( @@ -282,7 +282,7 @@ default void removeCompartmentFromUser( * * @param policyName the policy name * @param username the username - * @param groupShortName the short name of the group to set + * @param groupShortName the short name of the group * @param accessMode the access mode * @param defaultGroup whether the group is the default group * @param rowGroup whether the group is the row group @@ -304,7 +304,7 @@ default void addGroupToUser( * * @param policyName the policy name * @param username the username - * @param groupShortName the short name of the group to remove + * @param groupShortName the short name of the group * @throws ExecutionException if the operation fails */ default void removeGroupFromUser(String policyName, String username, String groupShortName) From c4e523a2b100b0c13e366f48e8e9be82007357cf Mon Sep 17 00:00:00 2001 From: Toshihiro Suzuki Date: Tue, 24 Dec 2024 17:55:58 +0900 Subject: [PATCH 11/11] [skip ci] Apply suggestions from code review Co-authored-by: Vincent Guilpain --- core/src/main/java/com/scalar/db/api/AbacAdmin.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/scalar/db/api/AbacAdmin.java b/core/src/main/java/com/scalar/db/api/AbacAdmin.java index dcac49670f..4ae41b7cfa 100644 --- a/core/src/main/java/com/scalar/db/api/AbacAdmin.java +++ b/core/src/main/java/com/scalar/db/api/AbacAdmin.java @@ -248,8 +248,8 @@ default void setLevelsToUser( * @param username the username * @param compartmentShortName the short name of the compartment * @param accessMode the access mode - * @param defaultCompartment whether the compartment is the default compartment - * @param rowCompartment whether the compartment is the row compartment + * @param defaultCompartment whether the compartment is a default compartment + * @param rowCompartment whether the compartment is a row compartment * @throws ExecutionException if the operation fails */ default void addCompartmentToUser( @@ -284,8 +284,8 @@ default void removeCompartmentFromUser( * @param username the username * @param groupShortName the short name of the group * @param accessMode the access mode - * @param defaultGroup whether the group is the default group - * @param rowGroup whether the group is the row group + * @param defaultGroup whether the group is a default group + * @param rowGroup whether the group is a row group * @throws ExecutionException if the operation fails */ default void addGroupToUser(