Skip to content

Commit b89e66a

Browse files
committed
Create user and grant permissions in tests
1 parent 61dd00f commit b89e66a

15 files changed

+387
-20
lines changed

core/build.gradle

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,18 +73,17 @@ sourceSets {
7373
runtimeClasspath += main.output + test.output
7474
srcDir file('src/integration-test/java')
7575
include '**/com/scalar/db/common/*.java'
76+
include '**/com/scalar/db/storage/cassandra/CassandraPermissionTestUtils.java'
7677
include '**/com/scalar/db/storage/cassandra/CassandraAdminTestUtils.java'
7778
include '**/com/scalar/db/storage/cassandra/CassandraEnv.java'
7879
include '**/com/scalar/db/storage/cassandra/CassandraPermissionIntegrationTest.java'
7980
include '**/com/scalar/db/storage/cassandra/CassandraAdminPermissionIntegrationTest.java'
80-
include '**/com/scalar/db/storage/cosmos/CosmosAdminTestUtils.java'
81-
include '**/com/scalar/db/storage/cosmos/CosmosEnv.java'
82-
include '**/com/scalar/db/storage/cosmos/CosmosPermissionIntegrationTest.java'
83-
include '**/com/scalar/db/storage/cosmos/CosmosAdminPermissionIntegrationTest.java'
81+
include '**/com/scalar/db/storage/dynamo/DynamoPermissionTestUtils.java'
8482
include '**/com/scalar/db/storage/dynamo/DynamoAdminTestUtils.java'
8583
include '**/com/scalar/db/storage/dynamo/DynamoEnv.java'
8684
include '**/com/scalar/db/storage/dynamo/DynamoPermissionIntegrationTest.java'
8785
include '**/com/scalar/db/storage/dynamo/DynamoAdminPermissionIntegrationTest.java'
86+
include '**/com/scalar/db/storage/jdbc/JdbcPermissionTestUtils.java'
8887
include '**/com/scalar/db/storage/jdbc/JdbcAdminTestUtils.java'
8988
include '**/com/scalar/db/storage/jdbc/JdbcTestUtils.java'
9089
include '**/com/scalar/db/storage/jdbc/JdbcEnv.java'
@@ -129,6 +128,8 @@ dependencies {
129128
implementation platform("software.amazon.awssdk:bom:${awssdkVersion}")
130129
implementation 'software.amazon.awssdk:applicationautoscaling'
131130
implementation 'software.amazon.awssdk:dynamodb'
131+
implementation 'software.amazon.awssdk:iam'
132+
implementation 'software.amazon.awssdk:iam-policy-builder'
132133
implementation "org.apache.commons:commons-dbcp2:${commonsDbcp2Version}"
133134
implementation "com.mysql:mysql-connector-j:${mysqlDriverVersion}"
134135
implementation "org.postgresql:postgresql:${postgresqlDriverVersion}"

core/src/integration-test/java/com/scalar/db/storage/cassandra/CassandraAdminPermissionIntegrationTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.scalar.db.api.DistributedStorageAdminPermissionIntegrationTestBase;
44
import com.scalar.db.util.AdminTestUtils;
5+
import com.scalar.db.util.PermissionTestUtils;
56
import java.util.Collections;
67
import java.util.Map;
78
import java.util.Properties;
@@ -30,6 +31,11 @@ protected AdminTestUtils getAdminTestUtils(String testName) {
3031
return new CassandraAdminTestUtils(getProperties(testName));
3132
}
3233

34+
@Override
35+
protected PermissionTestUtils getPermissionTestUtils(String testName) {
36+
return new CassandraPermissionTestUtils(getProperties(testName));
37+
}
38+
3339
@Test
3440
@Override
3541
@Disabled("Import-related functionality is not supported in Cassandra")

core/src/integration-test/java/com/scalar/db/storage/cassandra/CassandraEnv.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,7 @@ public static Properties getProperties(String testName) {
3939

4040
return properties;
4141
}
42-
43-
/*
44-
* This method is used for executing commands other than CREATE commands. In Cassandra, the
45-
* ROLE executing the commands has multiple permissions for the object created implicitly.
46-
* To know the exact permissions that should be granted to the ROLE, we avoid this behavior by
47-
* using a different ROLE.
48-
*/
42+
4943
public static Properties getPropertiesForNormalUser(String testName) {
5044
String contactPoints =
5145
System.getProperty(PROP_CASSANDRA_CONTACT_POINTS, DEFAULT_CASSANDRA_CONTACT_POINTS);

core/src/integration-test/java/com/scalar/db/storage/cassandra/CassandraPermissionIntegrationTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.scalar.db.storage.cassandra;
22

33
import com.scalar.db.api.DistributedStoragePermissionIntegrationTestBase;
4+
import com.scalar.db.util.PermissionTestUtils;
45
import java.util.Collections;
56
import java.util.Map;
67
import java.util.Properties;
@@ -21,4 +22,9 @@ protected Properties getPropertiesForNormalUser(String testName) {
2122
protected Map<String, String> getCreationOptions() {
2223
return Collections.singletonMap(CassandraAdmin.REPLICATION_FACTOR, "1");
2324
}
25+
26+
@Override
27+
protected PermissionTestUtils getPermissionTestUtils(String testName) {
28+
return new CassandraPermissionTestUtils(getProperties(testName));
29+
}
2430
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.scalar.db.storage.cassandra;
2+
3+
import com.datastax.driver.core.Session;
4+
import com.scalar.db.config.DatabaseConfig;
5+
import com.scalar.db.util.PermissionTestUtils;
6+
import java.util.Properties;
7+
8+
public class CassandraPermissionTestUtils implements PermissionTestUtils {
9+
private final ClusterManager clusterManager;
10+
11+
public CassandraPermissionTestUtils(Properties properties) {
12+
DatabaseConfig databaseConfig = new DatabaseConfig(properties);
13+
clusterManager = new ClusterManager(databaseConfig);
14+
}
15+
16+
@Override
17+
public void createNormalUser(String userName, String password) {
18+
clusterManager
19+
.getSession()
20+
.execute(
21+
String.format(
22+
"CREATE ROLE IF NOT EXISTS %s WITH PASSWORD = '%s' AND LOGIN = true",
23+
userName, password));
24+
}
25+
26+
@Override
27+
public void dropNormalUser(String userName) {
28+
clusterManager.getSession().execute(String.format("DROP ROLE IF EXISTS %s", userName));
29+
}
30+
31+
@Override
32+
public void grantRequiredPermission(String userName) {
33+
Session session = clusterManager.getSession();
34+
for (String grantStatement : getGrantPermissionStatements(userName)) {
35+
session.execute(grantStatement);
36+
}
37+
}
38+
39+
private String[] getGrantPermissionStatements(String userName) {
40+
return new String[] {
41+
String.format("GRANT CREATE ON ALL KEYSPACES TO %s", userName),
42+
String.format("GRANT DROP ON ALL KEYSPACES TO %s", userName),
43+
String.format("GRANT ALTER ON ALL KEYSPACES TO %s", userName),
44+
String.format("GRANT SELECT ON ALL KEYSPACES TO %s", userName),
45+
String.format("GRANT MODIFY ON ALL KEYSPACES TO %s", userName)
46+
};
47+
}
48+
49+
@Override
50+
public void close() {
51+
clusterManager.close();
52+
}
53+
}

core/src/integration-test/java/com/scalar/db/storage/dynamo/DynamoAdminPermissionIntegrationTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.google.common.collect.ImmutableMap;
44
import com.scalar.db.api.DistributedStorageAdminPermissionIntegrationTestBase;
55
import com.scalar.db.util.AdminTestUtils;
6+
import com.scalar.db.util.PermissionTestUtils;
67
import java.util.Map;
78
import java.util.Properties;
89
import org.junit.jupiter.api.Disabled;
@@ -30,6 +31,11 @@ protected AdminTestUtils getAdminTestUtils(String testName) {
3031
return new DynamoAdminTestUtils(getProperties(testName));
3132
}
3233

34+
@Override
35+
protected PermissionTestUtils getPermissionTestUtils(String testName) {
36+
return new DynamoPermissionTestUtils(getProperties(testName));
37+
}
38+
3339
@Test
3440
@Override
3541
@Disabled("Import-related functionality is not supported in DynamoDB")

core/src/integration-test/java/com/scalar/db/storage/dynamo/DynamoPermissionIntegrationTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.google.common.collect.ImmutableMap;
44
import com.scalar.db.api.DistributedStoragePermissionIntegrationTestBase;
5+
import com.scalar.db.util.PermissionTestUtils;
56
import java.util.Map;
67
import java.util.Properties;
78

@@ -21,4 +22,9 @@ protected Properties getPropertiesForNormalUser(String testName) {
2122
protected Map<String, String> getCreationOptions() {
2223
return ImmutableMap.of(DynamoAdmin.NO_SCALING, "false", DynamoAdmin.NO_BACKUP, "false");
2324
}
25+
26+
@Override
27+
protected PermissionTestUtils getPermissionTestUtils(String testName) {
28+
return new DynamoPermissionTestUtils(getProperties(testName));
29+
}
2430
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package com.scalar.db.storage.dynamo;
2+
3+
import com.scalar.db.config.DatabaseConfig;
4+
import com.scalar.db.util.PermissionTestUtils;
5+
import java.util.Properties;
6+
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
7+
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
8+
import software.amazon.awssdk.policybuilder.iam.IamEffect;
9+
import software.amazon.awssdk.policybuilder.iam.IamPolicy;
10+
import software.amazon.awssdk.policybuilder.iam.IamResource;
11+
import software.amazon.awssdk.regions.Region;
12+
import software.amazon.awssdk.services.iam.IamClient;
13+
import software.amazon.awssdk.services.iam.model.AttachUserPolicyRequest;
14+
import software.amazon.awssdk.services.iam.model.CreatePolicyVersionRequest;
15+
import software.amazon.awssdk.services.iam.model.User;
16+
17+
public class DynamoPermissionTestUtils implements PermissionTestUtils {
18+
private static final String IAM_POLICY_NAME = "test-dynamodb-permissions";
19+
private static final IamPolicy POLICY =
20+
IamPolicy.builder()
21+
.addStatement(
22+
s ->
23+
s.effect(IamEffect.ALLOW)
24+
.addAction("dynamodb:ConditionCheckItem")
25+
.addAction("dynamodb:PutItem")
26+
.addAction("dynamodb:ListTables")
27+
.addAction("dynamodb:DeleteItem")
28+
.addAction("dynamodb:Scan")
29+
.addAction("dynamodb:Query")
30+
.addAction("dynamodb:UpdateItem")
31+
.addAction("dynamodb:DeleteTable")
32+
.addAction("dynamodb:UpdateContinuousBackups")
33+
.addAction("dynamodb:CreateTable")
34+
.addAction("dynamodb:DescribeTable")
35+
.addAction("dynamodb:GetItem")
36+
.addAction("dynamodb:DescribeContinuousBackups")
37+
.addAction("dynamodb:UpdateTable")
38+
.addAction("application-autoscaling:RegisterScalableTarget")
39+
.addAction("application-autoscaling:DeleteScalingPolicy")
40+
.addAction("application-autoscaling:PutScalingPolicy")
41+
.addAction("application-autoscaling:DeregisterScalableTarget")
42+
.addAction("application-autoscaling:TagResource")
43+
.addResource(IamResource.ALL))
44+
.build();
45+
private final IamClient client;
46+
47+
public DynamoPermissionTestUtils(Properties properties) {
48+
DynamoConfig config = new DynamoConfig(new DatabaseConfig(properties));
49+
this.client =
50+
IamClient.builder()
51+
.region(Region.of(config.getRegion()))
52+
.credentialsProvider(
53+
StaticCredentialsProvider.create(
54+
AwsBasicCredentials.create(
55+
config.getAccessKeyId(), config.getSecretAccessKey())))
56+
.build();
57+
}
58+
59+
@Override
60+
public void createNormalUser(String userName, String password) {
61+
// Do nothing for DynamoDB.
62+
}
63+
64+
@Override
65+
public void dropNormalUser(String userName) {
66+
// Do nothing for DynamoDB.
67+
}
68+
69+
@Override
70+
public void grantRequiredPermission(String userName) {
71+
try {
72+
// Get the account ID to construct the ARN\
73+
User user = client.getUser().user();
74+
String accountId = user.arn().split(":")[4];
75+
String policyArn = String.format("arn:aws:iam::%s:policy/%s", accountId, IAM_POLICY_NAME);
76+
77+
// Create a new version of the existing policy
78+
client.createPolicyVersion(
79+
CreatePolicyVersionRequest.builder()
80+
.policyArn(policyArn)
81+
.policyDocument(POLICY.toJson())
82+
.setAsDefault(true)
83+
.build());
84+
85+
// Attach the policy to the user
86+
client.attachUserPolicy(
87+
AttachUserPolicyRequest.builder().userName(user.userName()).policyArn(policyArn).build());
88+
} catch (Exception e) {
89+
throw new RuntimeException("Failed to grant required permissions", e);
90+
}
91+
}
92+
93+
@Override
94+
public void close() {
95+
client.close();
96+
}
97+
}

core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcAdminPermissionIntegrationTest.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.scalar.db.api.DistributedStorageAdminPermissionIntegrationTestBase;
44
import com.scalar.db.util.AdminTestUtils;
5+
import com.scalar.db.util.PermissionTestUtils;
56
import java.util.Properties;
67

78
public class JdbcAdminPermissionIntegrationTest
@@ -13,11 +14,16 @@ protected Properties getProperties(String testName) {
1314

1415
@Override
1516
protected Properties getPropertiesForNormalUser(String testName) {
16-
return JdbcEnv.getProperties(testName);
17+
return JdbcEnv.getPropertiesForNormalUser(testName);
1718
}
1819

1920
@Override
2021
protected AdminTestUtils getAdminTestUtils(String testName) {
2122
return new JdbcAdminTestUtils(getProperties(testName));
2223
}
24+
25+
@Override
26+
protected PermissionTestUtils getPermissionTestUtils(String testName) {
27+
return new JdbcPermissionTestUtils(getProperties(testName));
28+
}
2329
}

core/src/integration-test/java/com/scalar/db/storage/jdbc/JdbcEnv.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,14 @@ public final class JdbcEnv {
77
private static final String PROP_JDBC_URL = "scalardb.jdbc.url";
88
private static final String PROP_JDBC_USERNAME = "scalardb.jdbc.username";
99
private static final String PROP_JDBC_PASSWORD = "scalardb.jdbc.password";
10+
private static final String PROP_JDBC_NORMAL_USERNAME = "scalardb.jdbc.normal_username";
11+
private static final String PROP_JDBC_NORMAL_PASSWORD = "scalardb.jdbc.normal_password";
1012

1113
private static final String DEFAULT_JDBC_URL = "jdbc:mysql://localhost:3306/";
1214
private static final String DEFAULT_JDBC_USERNAME = "root";
1315
private static final String DEFAULT_JDBC_PASSWORD = "mysql";
16+
private static final String DEFAULT_JDBC_NORMAL_USERNAME = "test";
17+
private static final String DEFAULT_JDBC_NORMAL_PASSWORD = "test";
1418

1519
private JdbcEnv() {}
1620

@@ -36,6 +40,28 @@ public static Properties getProperties(String testName) {
3640
return properties;
3741
}
3842

43+
public static Properties getPropertiesForNormalUser(String testName) {
44+
String jdbcUrl = System.getProperty(PROP_JDBC_URL, DEFAULT_JDBC_URL);
45+
String username = System.getProperty(PROP_JDBC_NORMAL_USERNAME, DEFAULT_JDBC_NORMAL_USERNAME);
46+
String password = System.getProperty(PROP_JDBC_NORMAL_PASSWORD, DEFAULT_JDBC_NORMAL_PASSWORD);
47+
48+
Properties properties = new Properties();
49+
properties.setProperty(DatabaseConfig.CONTACT_POINTS, jdbcUrl);
50+
properties.setProperty(DatabaseConfig.USERNAME, username);
51+
properties.setProperty(DatabaseConfig.PASSWORD, password);
52+
properties.setProperty(DatabaseConfig.STORAGE, "jdbc");
53+
properties.setProperty(DatabaseConfig.CROSS_PARTITION_SCAN, "true");
54+
properties.setProperty(DatabaseConfig.CROSS_PARTITION_SCAN_FILTERING, "true");
55+
properties.setProperty(DatabaseConfig.CROSS_PARTITION_SCAN_ORDERING, "true");
56+
57+
// Add testName as a metadata schema suffix
58+
properties.setProperty(
59+
DatabaseConfig.SYSTEM_NAMESPACE_NAME,
60+
DatabaseConfig.DEFAULT_SYSTEM_NAMESPACE_NAME + "_" + testName);
61+
62+
return properties;
63+
}
64+
3965
public static boolean isSqlite() {
4066
Properties properties = new Properties();
4167
properties.setProperty(

0 commit comments

Comments
 (0)