From 69f7a61009a2d98c303e9ff469c4c54eadc9f1b2 Mon Sep 17 00:00:00 2001 From: hsshss Date: Mon, 12 Sep 2022 16:28:26 +0900 Subject: [PATCH 1/3] Add support username and password authentication --- acceptance-tests/acceptance.bats | 5 ++++ acceptance-tests/redis-confs/users.acl | 2 ++ .../redis-confs/with_password.conf | 2 +- .../tests/select-db-with-username-password.sh | 29 +++++++++++++++++++ main.go | 1 + pkg/config/config.go | 2 ++ pkg/redisdump/redisdump.go | 11 +++++-- pkg/redisdump/redisdump_test.go | 12 +++++++- 8 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 acceptance-tests/redis-confs/users.acl create mode 100755 acceptance-tests/tests/select-db-with-username-password.sh diff --git a/acceptance-tests/acceptance.bats b/acceptance-tests/acceptance.bats index 48b170d..dff0aec 100644 --- a/acceptance-tests/acceptance.bats +++ b/acceptance-tests/acceptance.bats @@ -21,6 +21,11 @@ [ "$status" -eq 0 ] } +@test "Pass when using a non-default db, and a password with username" { + run tests/select-db-with-username-password.sh + [ "$status" -eq 0 ] +} + @test "Dumping / restoring all databases" { run tests/multiple-dbs.sh [ "$status" -eq 0 ] diff --git a/acceptance-tests/redis-confs/users.acl b/acceptance-tests/redis-confs/users.acl new file mode 100644 index 0000000..5a97261 --- /dev/null +++ b/acceptance-tests/redis-confs/users.acl @@ -0,0 +1,2 @@ +user default on >somepassword allkeys allchannels +@all +user test on >testpassword allkeys allchannels +@all diff --git a/acceptance-tests/redis-confs/with_password.conf b/acceptance-tests/redis-confs/with_password.conf index 5a1a9c8..f31f61a 100644 --- a/acceptance-tests/redis-confs/with_password.conf +++ b/acceptance-tests/redis-confs/with_password.conf @@ -1,2 +1,2 @@ port 6380 -requirepass somepassword \ No newline at end of file +aclfile /usr/local/etc/redis/users.acl \ No newline at end of file diff --git a/acceptance-tests/tests/select-db-with-username-password.sh b/acceptance-tests/tests/select-db-with-username-password.sh new file mode 100755 index 0000000..a3ba201 --- /dev/null +++ b/acceptance-tests/tests/select-db-with-username-password.sh @@ -0,0 +1,29 @@ +#!/bin/sh -e + +export DB=2 +export REDIS_PORT=6380 +export REDIS_USER=test +export REDISDUMPGO_AUTH=testpassword +export REDISCMD="redis-cli -h redis_secure -p $REDIS_PORT --user $REDIS_USER --pass $REDISDUMPGO_AUTH -n 2" +echo $REDISCMD +echo "-> Filling Redis with Mock Data..." +$REDISCMD FLUSHDB +/generator -output resp -type strings -n 100 | $REDISCMD --pipe +DBSIZE=`$REDISCMD dbsize` + +echo "-> Dumping DB..." +time /redis-dump-go -host redis_secure -n 250 -port $REDIS_PORT -db $DB -user $REDIS_USER -output resp >backup + +echo "-> Flushing DB and restoring dump..." +$REDISCMD FLUSHDB +$REDISCMD --pipe Comparing DB sizes..." +if [ $DBSIZE -ne $NEWDBSIZE ]; then + echo "ERROR - restored DB has $NEWDBSIZE elements, expected $DBSIZE" + exit 1 +else + echo "OK - $NEWDBSIZE elements" + exit 0 +fi diff --git a/main.go b/main.go index 7b57e1c..e0d625a 100644 --- a/main.go +++ b/main.go @@ -108,6 +108,7 @@ func realMain() int { s := redisdump.Host{ Host: c.Host, Port: c.Port, + Username: c.Username, Password: redisPassword, TlsHandler: tlshandler, } diff --git a/pkg/config/config.go b/pkg/config/config.go index b507b12..221c38a 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -10,6 +10,7 @@ type Config struct { Host string Port int Db int + Username string Filter string Noscan bool BatchSize int @@ -44,6 +45,7 @@ func FromFlags(progName string, args []string) (Config, string, error) { flags.StringVar(&c.Host, "host", "127.0.0.1", "Server host") flags.IntVar(&c.Port, "port", 6379, "Server port") flags.IntVar(&c.Db, "db", -1, "only dump this database (default: all databases)") + flags.StringVar(&c.Username, "user", "", "Username") flags.StringVar(&c.Filter, "filter", "*", "Key filter to use") flags.BoolVar(&c.Noscan, "noscan", false, "Use KEYS * instead of SCAN - for Redis <=2.8") flags.IntVar(&c.BatchSize, "batchSize", 1000, "HSET/RPUSH/SADD/ZADD only add 'batchSize' items at a time") diff --git a/pkg/redisdump/redisdump.go b/pkg/redisdump/redisdump.go index 4bf6197..d889342 100644 --- a/pkg/redisdump/redisdump.go +++ b/pkg/redisdump/redisdump.go @@ -327,12 +327,16 @@ func RedisURL(redisHost string, redisPort string) string { return fmt.Sprintf("redis://%s:%s", redisHost, redisPort) } -func redisDialOpts(redisPassword string, tlsHandler *TlsHandler, db *uint8) ([]radix.DialOpt, error) { +func redisDialOpts(redisUsername string, redisPassword string, tlsHandler *TlsHandler, db *uint8) ([]radix.DialOpt, error) { dialOpts := []radix.DialOpt{ radix.DialTimeout(5 * time.Minute), } if redisPassword != "" { - dialOpts = append(dialOpts, radix.DialAuthPass(redisPassword)) + if redisUsername != "" { + dialOpts = append(dialOpts, radix.DialAuthUser(redisUsername, redisPassword)) + } else { + dialOpts = append(dialOpts, radix.DialAuthPass(redisPassword)) + } } if tlsHandler != nil { tlsCfg, err := tlsConfig(tlsHandler) @@ -385,6 +389,7 @@ func dumpDB(client radix.Client, db *uint8, filter string, nWorkers int, withTTL type Host struct { Host string Port int + Username string Password string TlsHandler *TlsHandler } @@ -396,7 +401,7 @@ func DumpServer(s Host, db *uint8, filter string, nWorkers int, withTTL bool, ba redisURL := RedisURL(s.Host, fmt.Sprint(s.Port)) getConnFunc := func(db *uint8) func(network, addr string) (radix.Conn, error) { return func(network, addr string) (radix.Conn, error) { - dialOpts, err := redisDialOpts(s.Password, s.TlsHandler, db) + dialOpts, err := redisDialOpts(s.Username, s.Password, s.TlsHandler, db) if err != nil { return nil, err } diff --git a/pkg/redisdump/redisdump_test.go b/pkg/redisdump/redisdump_test.go index 8b4863f..1300fc3 100644 --- a/pkg/redisdump/redisdump_test.go +++ b/pkg/redisdump/redisdump_test.go @@ -241,6 +241,7 @@ func TestParseKeyspaceInfo(t *testing.T) { func TestRedisDialOpts(t *testing.T) { for i, testCase := range []struct { + redisUsername string redisPassword string tlsHandler *TlsHandler db uint8 @@ -248,12 +249,21 @@ func TestRedisDialOpts(t *testing.T) { err error }{ { + "", "", nil, 1, 2, nil, }, { + "", + "test", + &TlsHandler{}, + 1, + 4, + nil, + }, { + "test", "test", &TlsHandler{}, 1, @@ -261,7 +271,7 @@ func TestRedisDialOpts(t *testing.T) { nil, }, } { - dOpts, err := redisDialOpts(testCase.redisPassword, testCase.tlsHandler, &testCase.db) + dOpts, err := redisDialOpts(testCase.redisUsername, testCase.redisPassword, testCase.tlsHandler, &testCase.db) if err != testCase.err { t.Errorf("expected error to be %+v, got %+v", testCase.err, err) } From ed203e705aa9516594ff9710580ed75ca27becb4 Mon Sep 17 00:00:00 2001 From: Yann Hamon Date: Sat, 17 Sep 2022 12:30:01 +0200 Subject: [PATCH 2/3] Start multiple redis servers for acceptance tests of auth --- acceptance-tests/redis-confs/with_password.conf | 2 +- .../redis-confs/with_username_and_password.conf | 2 ++ .../tests/select-db-with-password.sh | 4 ++-- .../tests/select-db-with-username-password.sh | 4 ++-- docker-compose.yml | 17 ++++++++++++++--- 5 files changed, 21 insertions(+), 8 deletions(-) create mode 100644 acceptance-tests/redis-confs/with_username_and_password.conf diff --git a/acceptance-tests/redis-confs/with_password.conf b/acceptance-tests/redis-confs/with_password.conf index f31f61a..280ebc0 100644 --- a/acceptance-tests/redis-confs/with_password.conf +++ b/acceptance-tests/redis-confs/with_password.conf @@ -1,2 +1,2 @@ port 6380 -aclfile /usr/local/etc/redis/users.acl \ No newline at end of file +requirepass somepassword diff --git a/acceptance-tests/redis-confs/with_username_and_password.conf b/acceptance-tests/redis-confs/with_username_and_password.conf new file mode 100644 index 0000000..f31f61a --- /dev/null +++ b/acceptance-tests/redis-confs/with_username_and_password.conf @@ -0,0 +1,2 @@ +port 6380 +aclfile /usr/local/etc/redis/users.acl \ No newline at end of file diff --git a/acceptance-tests/tests/select-db-with-password.sh b/acceptance-tests/tests/select-db-with-password.sh index 7fdd7aa..0ca98ba 100755 --- a/acceptance-tests/tests/select-db-with-password.sh +++ b/acceptance-tests/tests/select-db-with-password.sh @@ -3,7 +3,7 @@ export DB=2 export REDIS_PORT=6380 export REDISDUMPGO_AUTH=somepassword -export REDISCMD="redis-cli -h redis_secure -p $REDIS_PORT --pass $REDISDUMPGO_AUTH -n 2" +export REDISCMD="redis-cli -h redis_with_password -p $REDIS_PORT --pass $REDISDUMPGO_AUTH -n 2" echo "-> Filling Redis with Mock Data..." $REDISCMD FLUSHDB @@ -11,7 +11,7 @@ $REDISCMD FLUSHDB DBSIZE=`$REDISCMD dbsize` echo "-> Dumping DB..." -time /redis-dump-go -host redis_secure -n 250 -port $REDIS_PORT -db $DB -output resp >backup +time /redis-dump-go -host redis_with_password -n 250 -port $REDIS_PORT -db $DB -output resp >backup echo "-> Flushing DB and restoring dump..." $REDISCMD FLUSHDB diff --git a/acceptance-tests/tests/select-db-with-username-password.sh b/acceptance-tests/tests/select-db-with-username-password.sh index a3ba201..d9022b6 100755 --- a/acceptance-tests/tests/select-db-with-username-password.sh +++ b/acceptance-tests/tests/select-db-with-username-password.sh @@ -4,7 +4,7 @@ export DB=2 export REDIS_PORT=6380 export REDIS_USER=test export REDISDUMPGO_AUTH=testpassword -export REDISCMD="redis-cli -h redis_secure -p $REDIS_PORT --user $REDIS_USER --pass $REDISDUMPGO_AUTH -n 2" +export REDISCMD="redis-cli -h redis_with_username_and_password -p $REDIS_PORT --user $REDIS_USER --pass $REDISDUMPGO_AUTH -n 2" echo $REDISCMD echo "-> Filling Redis with Mock Data..." $REDISCMD FLUSHDB @@ -12,7 +12,7 @@ $REDISCMD FLUSHDB DBSIZE=`$REDISCMD dbsize` echo "-> Dumping DB..." -time /redis-dump-go -host redis_secure -n 250 -port $REDIS_PORT -db $DB -user $REDIS_USER -output resp >backup +time /redis-dump-go -host redis_with_username_and_password -n 250 -port $REDIS_PORT -db $DB -user $REDIS_USER -output resp >backup echo "-> Flushing DB and restoring dump..." $REDISCMD FLUSHDB diff --git a/docker-compose.yml b/docker-compose.yml index 650cf0f..5b26f05 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,7 +5,7 @@ services: image: "redis:alpine" ports: - "6379:6379" - redis_secure: + redis_with_password: image: "redis:alpine" volumes: - ./acceptance-tests/redis-confs:/usr/local/etc/redis @@ -15,6 +15,16 @@ services: protocol: tcp mode: host entrypoint: ["/usr/local/bin/redis-server", "/usr/local/etc/redis/with_password.conf"] + redis_with_username_and_password: + image: "redis:alpine" + volumes: + - ./acceptance-tests/redis-confs:/usr/local/etc/redis + ports: + - target: 6381 + published: 6381 + protocol: tcp + mode: host + entrypoint: ["/usr/local/bin/redis-server", "/usr/local/etc/redis/with_username_and_password.conf"] tests: image: "alpine:latest" volumes: @@ -23,6 +33,7 @@ services: - ./bin/redis-dump-go:/redis-dump-go depends_on: - "redis" - - "redis_secure" + - "redis_with_password" + - "redis_with_username_and_password" working_dir: /acceptance-tests - entrypoint: ["/acceptance-tests/entrypoint.sh"] \ No newline at end of file + entrypoint: ["/acceptance-tests/entrypoint.sh"] From a169cf768125cf3d46a0515b9e8283d99821d07a Mon Sep 17 00:00:00 2001 From: Yann Hamon Date: Sat, 17 Sep 2022 12:34:11 +0200 Subject: [PATCH 3/3] Add unit test case for passing username --- pkg/config/config_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index b6ed098..967e864 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -62,6 +62,20 @@ func TestFromFlags(t *testing.T) { Output: "commands", }, }, + { + []string{"-host", "redis", "-port", "1234", "-batchSize", "10", "-user", "test"}, + Config{ + Db: -1, + Host: "redis", + Port: 1234, + Filter: "*", + BatchSize: 10, + NWorkers: 10, + WithTTL: true, + Output: "resp", + Username: "test", + }, + }, { []string{"-db", "1"}, Config{