From 5679e50f6ebfed56bbf915bd13f85665bae62561 Mon Sep 17 00:00:00 2001 From: Vasiliy Sadokhin Date: Sat, 29 Sep 2018 21:43:06 +0800 Subject: [PATCH] Added roles to cassandra for receive and get statistics APIs Made data module authorize with cassandra with custom username/password --- cassandra/Dockerfile | 3 ++ init-cassandra => cassandra/init-cassandra | 8 +++- run-cassandra.sh => cassandra/run.sh | 10 +++-- .../data/utility/CassandraClusterUtility.java | 1 + .../iot/data/utility/CassandraConfig.java | 11 ++++++ .../utility/CassandraClusterUtilityTest.java | 15 +++++++ .../iot/data/utility/CassandraConfigTest.java | 39 +++++++++++++++++++ run.sh | 2 +- statistics-api/run.sh | 6 ++- stream-consumer/run.sh | 2 + 10 files changed, 90 insertions(+), 7 deletions(-) create mode 100644 cassandra/Dockerfile rename init-cassandra => cassandra/init-cassandra (52%) rename run-cassandra.sh => cassandra/run.sh (67%) diff --git a/cassandra/Dockerfile b/cassandra/Dockerfile new file mode 100644 index 0000000..cbdae5d --- /dev/null +++ b/cassandra/Dockerfile @@ -0,0 +1,3 @@ +FROM cassandra:3.11.3 +RUN echo "authenticator: PasswordAuthenticator" >> /etc/cassandra/cassandra.yaml && \ + sed -i -e 's/AllowAllAuthorizer/org.apache.cassandra.auth.CassandraAuthorizer/g' /etc/cassandra/cassandra.yaml \ No newline at end of file diff --git a/init-cassandra b/cassandra/init-cassandra similarity index 52% rename from init-cassandra rename to cassandra/init-cassandra index 2498470..8324979 100644 --- a/init-cassandra +++ b/cassandra/init-cassandra @@ -5,4 +5,10 @@ CREATE TABLE metric_by_sensor (sensor_id text, week timestamp, when timestamp, v PRIMARY KEY ((sensor_id, week), when)); CREATE TABLE metric_by_type (type text, day timestamp, sensor_id text, when timestamp, value float, -PRIMARY KEY ((type, day), when, sensor_id)); \ No newline at end of file +PRIMARY KEY ((type, day), when, sensor_id)); + +CREATE ROLE iot_statistics_role WITH PASSWORD = 'iotStatistics123' AND LOGIN = true; +GRANT SELECT ON KEYSPACE iot TO iot_statistics_role; + +CREATE ROLE iot_write_role WITH PASSWORD = 'iotWrite123' AND LOGIN = true; +GRANT MODIFY ON KEYSPACE iot TO iot_write_role; \ No newline at end of file diff --git a/run-cassandra.sh b/cassandra/run.sh similarity index 67% rename from run-cassandra.sh rename to cassandra/run.sh index af86e16..71aa75d 100755 --- a/run-cassandra.sh +++ b/cassandra/run.sh @@ -1,11 +1,13 @@ #!/bin/bash +docker build -t iot-cassandra . docker rm -f iot-cassandra 2>/dev/null startDate=`date +%s` echo 'cassandra iot start' -docker run --rm -d --name iot-cassandra -p 9042:9042 cassandra:3.11.3 +docker run --rm -d --name iot-cassandra -p 9042:9042 iot-cassandra +cqlsh="docker exec iot-cassandra cqlsh -u cassandra -p cassandra" while true; do sleep 1 - status=`docker exec iot-cassandra cqlsh 2>&1` + status=`${cqlsh} 2>&1` if [ -z "$status" ]; then echo 'cassandra iot is started' break @@ -20,8 +22,8 @@ done echo 'cassandra iot init start' docker cp ./init-cassandra iot-cassandra:/tmp -docker exec iot-cassandra cqlsh --file=/tmp/init-cassandra -status=`docker exec iot-cassandra cqlsh -e "DESCRIBE TABLE iot.metric_by_type"` +${cqlsh} --file=/tmp/init-cassandra +status=`${cqlsh} -e "DESCRIBE TABLE iot.metric_by_type"` if [[ ${status} == *"CREATE TABLE iot.metric_by_type"* ]]; then echo 'cassandra iot init is done' else diff --git a/data/src/main/java/me/vsadokhin/iot/data/utility/CassandraClusterUtility.java b/data/src/main/java/me/vsadokhin/iot/data/utility/CassandraClusterUtility.java index e41ade6..e2c11d9 100644 --- a/data/src/main/java/me/vsadokhin/iot/data/utility/CassandraClusterUtility.java +++ b/data/src/main/java/me/vsadokhin/iot/data/utility/CassandraClusterUtility.java @@ -19,6 +19,7 @@ static Cluster createCluster() { Cluster.Builder builder = Cluster.builder(); builder.addContactPoints(CassandraConfig.getContactPoints()); builder.withPort(CassandraConfig.getPort()); + builder.withAuthProvider(CassandraConfig.getAuthProvider()); return builder.build(); } diff --git a/data/src/main/java/me/vsadokhin/iot/data/utility/CassandraConfig.java b/data/src/main/java/me/vsadokhin/iot/data/utility/CassandraConfig.java index a24d59c..e9bd7df 100644 --- a/data/src/main/java/me/vsadokhin/iot/data/utility/CassandraConfig.java +++ b/data/src/main/java/me/vsadokhin/iot/data/utility/CassandraConfig.java @@ -1,5 +1,9 @@ package me.vsadokhin.iot.data.utility; + +import com.datastax.driver.core.AuthProvider; +import com.datastax.driver.core.PlainTextAuthProvider; + final class CassandraConfig { private CassandraConfig() { @@ -16,4 +20,11 @@ static String[] getContactPoints() { static int getPort() { return 9042; } + + static AuthProvider getAuthProvider() { + return new PlainTextAuthProvider( + System.getProperty("cassandra.username","cassandra"), + System.getProperty("cassandra.password","cassandra") + ); + } } \ No newline at end of file diff --git a/data/src/test/java/me/vsadokhin/iot/data/utility/CassandraClusterUtilityTest.java b/data/src/test/java/me/vsadokhin/iot/data/utility/CassandraClusterUtilityTest.java index be37d16..cf6b0c3 100644 --- a/data/src/test/java/me/vsadokhin/iot/data/utility/CassandraClusterUtilityTest.java +++ b/data/src/test/java/me/vsadokhin/iot/data/utility/CassandraClusterUtilityTest.java @@ -10,6 +10,7 @@ import static org.powermock.api.mockito.PowerMockito.verifyStatic; import static org.powermock.api.mockito.PowerMockito.when; +import com.datastax.driver.core.AuthProvider; import com.datastax.driver.core.Cluster; import org.junit.Test; import org.junit.runner.RunWith; @@ -128,6 +129,20 @@ public void createCluster_callClusterBuilderWithPort() { verify(mockClusterBuilder).withPort(port); } + @Test + public void createCluster_callBuilderWithAuthProvider() { + // setup + Cluster.Builder mockClusterBuilder = prepareToTestCreateCluster(); + AuthProvider mockAuthProvider = mock(AuthProvider.class); + when(CassandraConfig.getAuthProvider()).thenReturn(mockAuthProvider); + + // act + CassandraClusterUtility.createCluster(); + + // verify + verify(mockClusterBuilder).withAuthProvider(mockAuthProvider); + } + @Test public void createCluster_checkResult() { // setup diff --git a/data/src/test/java/me/vsadokhin/iot/data/utility/CassandraConfigTest.java b/data/src/test/java/me/vsadokhin/iot/data/utility/CassandraConfigTest.java index fef3581..409168f 100644 --- a/data/src/test/java/me/vsadokhin/iot/data/utility/CassandraConfigTest.java +++ b/data/src/test/java/me/vsadokhin/iot/data/utility/CassandraConfigTest.java @@ -2,13 +2,23 @@ import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.powermock.api.mockito.PowerMockito.whenNew; +import com.datastax.driver.core.AuthProvider; +import com.datastax.driver.core.PlainTextAuthProvider; import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +@RunWith(PowerMockRunner.class) +@PrepareForTest(CassandraConfig.class) public class CassandraConfigTest { @Test public void getKeyspaceName() { + // verify assertThat(CassandraConfig.getKeyspaceName(), is("iot")); } @@ -42,6 +52,35 @@ public void getContactPoints_cassandraEndpointsAreSpecifiedAsSystemProperty_chec @Test public void getPort() { + // verify assertThat(CassandraConfig.getPort(), is(9042)); } + + @Test + public void getAuthProvider() throws Exception { + // setup + PlainTextAuthProvider mockPlainTextAuthProvider = mock(PlainTextAuthProvider.class); + whenNew(PlainTextAuthProvider.class).withArguments("cassandra", "cassandra").thenReturn(mockPlainTextAuthProvider); + + // act + AuthProvider result = CassandraConfig.getAuthProvider(); + + // verify + assertThat(result, is(mockPlainTextAuthProvider)); + } + + @Test + public void getAuthProvider_cassandraCredentialsSpecifiedAsSystemProperties_checkResult() throws Exception { + // setup + System.setProperty("cassandra.username", "custom username"); + System.setProperty("cassandra.password", "custom password"); + PlainTextAuthProvider mockPlainTextAuthProvider = mock(PlainTextAuthProvider.class); + whenNew(PlainTextAuthProvider.class).withArguments("custom username", "custom password").thenReturn(mockPlainTextAuthProvider); + + // act + AuthProvider result = CassandraConfig.getAuthProvider(); + + // verify + assertThat(result, is(mockPlainTextAuthProvider)); + } } \ No newline at end of file diff --git a/run.sh b/run.sh index bf25033..1392ffc 100755 --- a/run.sh +++ b/run.sh @@ -1,6 +1,6 @@ #!/bin/bash ./run-kafka.sh -./run-cassandra.sh +(cd cassandra && ./run.sh) (cd receive-api && ./run.sh) (cd stream-consumer && ./run.sh) (cd statistics-api && ./run.sh) \ No newline at end of file diff --git a/statistics-api/run.sh b/statistics-api/run.sh index f04d6c3..f8f8892 100755 --- a/statistics-api/run.sh +++ b/statistics-api/run.sh @@ -5,4 +5,8 @@ docker run --rm -d --name iot-statistics-api \ -p 8081:8080 \ --link iot-cassandra:iot-cassandra \ -v `pwd`/build/libs/statistics-api-0.0.1-SNAPSHOT.jar:/tmp/statistics-api.jar \ -anapsix/alpine-java:8 java -Dcassandra.contact.points=iot-cassandra -jar /tmp/statistics-api.jar \ No newline at end of file +anapsix/alpine-java:8 java \ +-Dcassandra.contact.points=iot-cassandra \ +-Dcassandra.username=iot_statistics_role \ +-Dcassandra.password=iotStatistics123 \ +-jar /tmp/statistics-api.jar \ No newline at end of file diff --git a/stream-consumer/run.sh b/stream-consumer/run.sh index b596f03..c639e6b 100755 --- a/stream-consumer/run.sh +++ b/stream-consumer/run.sh @@ -8,5 +8,7 @@ docker run --rm -d --name iot-stream-consumer \ anapsix/alpine-java:8 \ java \ -Dcassandra.contact.points=iot-cassandra \ +-Dcassandra.username=iot_write_role \ +-Dcassandra.password=iotWrite123 \ -Dkafka.endpoints=iot-kafka:9092 \ -jar /tmp/stream-consumer.jar