From c6f3b6f1f6c3c4aaf2148e16d7baf148d92098ed Mon Sep 17 00:00:00 2001 From: Guang Yang Date: Wed, 19 Jul 2017 10:40:32 -0700 Subject: [PATCH] Add password authentication for Cassandra (#249) * Add password authentication for Cassandra --- .travis.yml | 2 +- clients/metadata/metadata_cassandra.go | 8 ++++++ clients/metadata/util.go | 32 ++++++++++++++++++++++-- common/configure/commonmetadataconfig.go | 13 ++++++++++ common/configure/interfaces.go | 2 ++ config/base.yaml | 4 +++ config/local.yaml | 6 ++++- test/integration/base.go | 9 ++++++- 8 files changed, 71 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index a7e71027..48ebab35 100644 --- a/.travis.yml +++ b/.travis.yml @@ -60,7 +60,7 @@ install: - go get github.com/mattn/goveralls - go get golang.org/x/tools/cmd/cover - go get github.com/golang/lint/golint - - ccm create test -v 2.2.8 -n 1 -s + - ccm create test -v 2.2.8 -n 1 -s --pwd-auth - sudo ln -sf /home/travis/.local/bin/cqlsh /usr/local/bin/cqlsh - wget https://github.com/uber/cherami-server/releases/download/rocksdb-5.0.2-trusty/librocksdb.so.5.0.2 - ln -s librocksdb.so.5.0.2 librocksdb.so.5.0 diff --git a/clients/metadata/metadata_cassandra.go b/clients/metadata/metadata_cassandra.go index 2afc9fdc..9f420440 100644 --- a/clients/metadata/metadata_cassandra.go +++ b/clients/metadata/metadata_cassandra.go @@ -193,6 +193,14 @@ func NewCassandraMetadataService(cfg configure.CommonMetadataConfig) (*Cassandra cluster.Keyspace = cfg.GetKeyspace() cluster.ProtoVersion = cassandraProtoVersion + auth := cfg.GetAuthentication() + if auth.Enabled { + cluster.Authenticator = gocql.PasswordAuthenticator{ + Username: auth.Username, + Password: auth.Password, + } + } + cms := new(CassandraMetadataService) cms.lowConsLevel = gocql.Two cms.midConsLevel = gocql.Two diff --git a/clients/metadata/util.go b/clients/metadata/util.go index 051aa908..955c3dd0 100644 --- a/clients/metadata/util.go +++ b/clients/metadata/util.go @@ -73,7 +73,12 @@ func LoadSchema(cqlshpath string, fileName string, keyspace string) (err error) // Using cqlsh as I couldn't find a way to execute multiple commands through gocql.Session var out bytes.Buffer var stderr bytes.Buffer - cmd := exec.Command(cqlshpath, fmt.Sprintf("--keyspace=%v", keyspace), fmt.Sprintf("--file=%v", fileName), `127.0.0.1`) + cmd := exec.Command(cqlshpath, + "--username=cassandra", + "--password=cassandra", + fmt.Sprintf("--keyspace=%v", keyspace), + fmt.Sprintf("--file=%v", fileName), + `127.0.0.1`) cmd.Stdout = &out cmd.Stderr = &stderr err = cmd.Run() @@ -97,7 +102,13 @@ func newCluster(clusterHosts string) *gocql.ClusterConfig { } // CreateKeyspaceNoSession is used to create a keyspace when we don't have a session -func CreateKeyspaceNoSession(clusterHosts string, keyspace string, replicas int, overwrite bool) error { +func CreateKeyspaceNoSession( + clusterHosts string, + keyspace string, + replicas int, + overwrite bool, + auth configure.Authentication, +) error { // open a session to the "system" keyspace just to create the new keyspace // TODO: Find out if we can do this "outside" of a session (cqlsh?) cluster := newCluster(clusterHosts) @@ -105,6 +116,12 @@ func CreateKeyspaceNoSession(clusterHosts string, keyspace string, replicas int, cluster.Keyspace = "system" cluster.Timeout = 40 * time.Second cluster.ProtoVersion = cassandraProtoVersion + if auth.Enabled { + cluster.Authenticator = gocql.PasswordAuthenticator{ + Username: auth.Username, + Password: auth.Password, + } + } session, err := cluster.CreateSession() if err != nil { log.WithField(common.TagErr, err).Error(`CreateKeyspaceNoSession: unable to create session`) @@ -146,11 +163,18 @@ func (s *TestCluster) SetupTestCluster() { s.createKeyspace(1) s.loadSchema("schema/metadata.cql") + auth := configure.Authentication{ + Enabled: true, + Username: "cassandra", + Password: "cassandra", + } + var err error s.client, err = NewCassandraMetadataService(&configure.MetadataConfig{ CassandraHosts: ip, Keyspace: s.keyspace, Consistency: "One", + Authentication: auth, }) if err != nil { log.Fatal(err) @@ -169,6 +193,10 @@ func (s *TestCluster) createCluster(clusterHosts string, cons gocql.Consistency, s.cluster.Keyspace = "system" s.cluster.Timeout = 40 * time.Second s.cluster.ProtoVersion = cassandraProtoVersion + s.cluster.Authenticator = gocql.PasswordAuthenticator{ + Username: "cassandra", + Password: "cassandra", + } var err error s.session, err = s.cluster.CreateSession() if err != nil { diff --git a/common/configure/commonmetadataconfig.go b/common/configure/commonmetadataconfig.go index c6ff32e4..b9007217 100644 --- a/common/configure/commonmetadataconfig.go +++ b/common/configure/commonmetadataconfig.go @@ -20,10 +20,18 @@ package configure +// Authentication holds the authentication info to our metadata +type Authentication struct { + Enabled bool `yaml:"Enabled"` + Username string `yaml:"Username"` + Password string `yaml:"Password"` +} + // MetadataConfig holds the config info related to our metadata type MetadataConfig struct { CassandraHosts string `yaml:"CassandraHosts"` Keyspace string `yaml:"Keyspace"` + Authentication Authentication `yaml:"Authentication"` Consistency string `yaml:"Consistency"` ClusterName string `yaml:"ClusterName"` NumConns int `yaml:"NumConns"` @@ -47,6 +55,11 @@ func (r *MetadataConfig) GetKeyspace() string { return r.Keyspace } +// GetAuthentication returns the authentication info to be used for cherami cluster +func (r *MetadataConfig) GetAuthentication() Authentication { + return r.Authentication +} + // GetConsistency returns the consistency level to be used for cherami cluster func (r *MetadataConfig) GetConsistency() string { return r.Consistency diff --git a/common/configure/interfaces.go b/common/configure/interfaces.go index 2e8d82c0..caf147cc 100644 --- a/common/configure/interfaces.go +++ b/common/configure/interfaces.go @@ -147,6 +147,8 @@ type ( GetCassandraHosts() string // GetKeyspace returns the keyspace for our cassandra cluster GetKeyspace() string + // GetAuthentication returns the authentication info for our cassandra cluster + GetAuthentication() Authentication // GetConsistency returns the configured consistency level GetConsistency() string // GetDcFilter returns the dc filter map for the cassandra cluster diff --git a/config/base.yaml b/config/base.yaml index d9195e7d..0a9b7df0 100644 --- a/config/base.yaml +++ b/config/base.yaml @@ -80,6 +80,10 @@ MetadataConfig: Consistency: "one" ClusterName: "base" NumConns: 1 + Authentication: + Enabled: true + Username: cassandra + Password: cassandra # ReplicatorConfig specifies ReplicatorConfig: diff --git a/config/local.yaml b/config/local.yaml index 20241740..5cd91fcf 100644 --- a/config/local.yaml +++ b/config/local.yaml @@ -26,6 +26,10 @@ DefaultDestinationConfig: MetadataConfig: CassandraHosts: "127.0.0.1" + Authentication: + Enabled: false + Username: + Password: StorageConfig: BaseDir: /tmp/cherami-store @@ -33,4 +37,4 @@ StorageConfig: logging: level: debug - stdout: true \ No newline at end of file + stdout: true diff --git a/test/integration/base.go b/test/integration/base.go index a7d66f2c..931dffa9 100644 --- a/test/integration/base.go +++ b/test/integration/base.go @@ -159,14 +159,21 @@ func (tb *testBase) setupSuiteImpl(t *testing.T) { tb.keyspace = "integration_test" tb.Assertions = require.New(tb.T()) + auth := configure.Authentication{ + Enabled: true, + Username: "cassandra", + Password: "cassandra", + } + // create the keyspace first - err := metadata.CreateKeyspaceNoSession("127.0.0.1", tb.keyspace, 1, true) + err := metadata.CreateKeyspaceNoSession("127.0.0.1", tb.keyspace, 1, true, auth) tb.NoError(err) tb.mClient, _ = metadata.NewCassandraMetadataService(&configure.MetadataConfig{ CassandraHosts: "127.0.0.1", Keyspace: tb.keyspace, Consistency: "One", + Authentication: auth, }) tb.NotNil(tb.mClient)