Browse Source

feat(redis): add support for `username` on AUTH command

Fixes https://emqx.atlassian.net/browse/EMQX-9911
Paulo Zulato 2 năm trước cách đây
mục cha
commit
2c458b62f5

+ 3 - 4
.ci/docker-compose-file/docker-compose-redis-single-tcp.yaml

@@ -4,12 +4,11 @@ services:
   redis_server:
     container_name: redis
     image: redis:${REDIS_TAG}
+    volumes:
+      - ./redis/single-tcp:/usr/local/etc/redis/
     ports:
       - "6379:6379"
-    command:
-      - redis-server
-      - "--bind 0.0.0.0 ::"
-      - --requirepass public
+    command: redis-server /usr/local/etc/redis/redis.conf
     restart: always
     networks:
       - emqx_bridge

+ 2 - 10
.ci/docker-compose-file/docker-compose-redis-single-tls.yaml

@@ -8,18 +8,10 @@ services:
       - ./certs/server.crt:/etc/certs/redis.crt
       - ./certs/server.key:/etc/certs/redis.key
       - ./certs/ca.crt:/etc/certs/ca.crt
+      - ./redis/single-tls:/usr/local/etc/redis
     ports:
       - "6380:6380"
-    command:
-      - redis-server
-      - "--bind 0.0.0.0 ::"
-      - --requirepass public
-      - --tls-port 6380
-      - --tls-cert-file /etc/certs/redis.crt
-      - --tls-key-file /etc/certs/redis.key
-      - --tls-ca-cert-file /etc/certs/ca.crt
-      - --tls-protocols "TLSv1.3"
-      - --tls-ciphersuites "TLS_CHACHA20_POLY1305_SHA256"
+    command: redis-server /usr/local/etc/redis/redis.conf
     restart: always
     networks:
       emqx_bridge:

+ 2 - 1
.ci/docker-compose-file/redis/cluster-tcp/redis.conf

@@ -1,10 +1,11 @@
 bind :: 0.0.0.0
 port 6379
-requirepass public
 
 cluster-enabled yes
 
+masteruser default
 masterauth public
+aclfile /usr/local/etc/redis/users.acl
 
 protected-mode no
 daemonize no

+ 2 - 0
.ci/docker-compose-file/redis/cluster-tcp/users.acl

@@ -0,0 +1,2 @@
+user default on >public ~* &* +@all
+user test_user on >test_passwd ~* &* +@all

+ 2 - 1
.ci/docker-compose-file/redis/cluster-tls/redis.conf

@@ -1,10 +1,11 @@
 bind :: 0.0.0.0
 port 6379
-requirepass public
 
 cluster-enabled yes
 
+masteruser default
 masterauth public
+aclfile /usr/local/etc/redis/users.acl
 
 tls-port 6389
 tls-cert-file /etc/certs/cert.pem

+ 2 - 0
.ci/docker-compose-file/redis/cluster-tls/users.acl

@@ -0,0 +1,2 @@
+user default on >public ~* &* +@all
+user test_user on >test_passwd ~* &* +@all

+ 1 - 1
.ci/docker-compose-file/redis/sentinel-tcp/master.conf

@@ -1,6 +1,6 @@
 bind :: 0.0.0.0
 port 6379
-requirepass public
+aclfile /usr/local/etc/redis/users.acl
 
 protected-mode no
 daemonize no

+ 2 - 1
.ci/docker-compose-file/redis/sentinel-tcp/slave.conf

@@ -1,9 +1,10 @@
 bind :: 0.0.0.0
 port 6379
-requirepass public
 
 replicaof redis-sentinel-master 6379
+masteruser default
 masterauth public
+aclfile /usr/local/etc/redis/users.acl
 
 protected-mode no
 daemonize no

+ 2 - 0
.ci/docker-compose-file/redis/sentinel-tcp/users.acl

@@ -0,0 +1,2 @@
+user default on >public ~* &* +@all
+user test_user on >test_passwd ~* &* +@all

+ 1 - 1
.ci/docker-compose-file/redis/sentinel-tls/master.conf

@@ -1,6 +1,6 @@
 bind :: 0.0.0.0
 port 6379
-requirepass public
+aclfile /usr/local/etc/redis/users.acl
 
 tls-port 6389
 tls-cert-file /etc/certs/cert.pem

+ 2 - 1
.ci/docker-compose-file/redis/sentinel-tls/slave.conf

@@ -1,9 +1,10 @@
 bind :: 0.0.0.0
 port 6379
-requirepass public
 
 replicaof redis-sentinel-tls-master 6389
+masteruser default
 masterauth public
+aclfile /usr/local/etc/redis/users.acl
 
 tls-port 6389
 tls-replication yes

+ 2 - 0
.ci/docker-compose-file/redis/sentinel-tls/users.acl

@@ -0,0 +1,2 @@
+user default on >public ~* &* +@all
+user test_user on >test_passwd ~* &* +@all

+ 3 - 0
.ci/docker-compose-file/redis/single-tcp/redis.conf

@@ -0,0 +1,3 @@
+bind :: 0.0.0.0
+port 6379
+aclfile /usr/local/etc/redis/users.acl

+ 2 - 0
.ci/docker-compose-file/redis/single-tcp/users.acl

@@ -0,0 +1,2 @@
+user default on >public ~* &* +@all
+user test_user on >test_passwd ~* &* +@all

+ 9 - 0
.ci/docker-compose-file/redis/single-tls/redis.conf

@@ -0,0 +1,9 @@
+bind :: 0.0.0.0
+aclfile /usr/local/etc/redis/users.acl
+
+tls-port 6380
+tls-cert-file /etc/certs/redis.crt
+tls-key-file /etc/certs/redis.key
+tls-ca-cert-file /etc/certs/ca.crt
+tls-protocols "TLSv1.3"
+tls-ciphersuites "TLS_CHACHA20_POLY1305_SHA256"

+ 2 - 0
.ci/docker-compose-file/redis/single-tls/users.acl

@@ -0,0 +1,2 @@
+user default on >public ~* &* +@all
+user test_user on >test_passwd ~* &* +@all

+ 1 - 1
apps/emqx_bridge_redis/src/emqx_bridge_redis.app.src

@@ -1,6 +1,6 @@
 {application, emqx_bridge_redis, [
     {description, "EMQX Enterprise Redis Bridge"},
-    {vsn, "0.1.2"},
+    {vsn, "0.1.3"},
     {registered, []},
     {applications, [
         kernel,

+ 34 - 0
apps/emqx_bridge_redis/test/emqx_bridge_redis_SUITE.erl

@@ -30,6 +30,11 @@
     <<"local_topic">> => <<"local_topic/#">>
 }).
 
+-define(USERNAME_PASSWORD_AUTH_OPTS, #{
+    <<"username">> => <<"test_user">>,
+    <<"password">> => <<"test_passwd">>
+}).
+
 -define(BATCH_SIZE, 5).
 
 -define(PROXY_HOST, "toxiproxy").
@@ -319,6 +324,22 @@ t_permanent_error(_Config) ->
     ),
     {ok, _} = emqx_bridge:remove(Type, Name).
 
+t_auth_username_password(_Config) ->
+    Name = <<"mybridge">>,
+    Type = <<"redis_single">>,
+    ResourceId = emqx_bridge_resource:resource_id(Type, Name),
+    BridgeConfig = username_password_redis_bridge_config(),
+    ?assertMatch(
+        {ok, _},
+        emqx_bridge:create(Type, Name, BridgeConfig)
+    ),
+    ?WAIT(
+        {ok, connected},
+        emqx_resource:health_check(ResourceId),
+        5
+    ),
+    {ok, _} = emqx_bridge:remove(Type, Name).
+
 t_create_disconnected(Config) ->
     Name = <<"toxic_bridge">>,
     Type = <<"redis_single">>,
@@ -528,6 +549,19 @@ toxiproxy_redis_bridge_config() ->
     },
     maps:merge(Conf0, ?COMMON_REDIS_OPTS).
 
+username_password_redis_bridge_config() ->
+    Conf0 = ?REDIS_TOXYPROXY_CONNECT_CONFIG#{
+        <<"resource_opts">> => #{
+            <<"query_mode">> => <<"sync">>,
+            <<"worker_pool_size">> => <<"1">>,
+            <<"batch_size">> => integer_to_binary(?BATCH_SIZE),
+            <<"health_check_interval">> => <<"1s">>,
+            <<"start_timeout">> => <<"15s">>
+        }
+    },
+    Conf1 = maps:merge(Conf0, ?COMMON_REDIS_OPTS),
+    maps:merge(Conf1, ?USERNAME_PASSWORD_AUTH_OPTS).
+
 invalid_command_bridge_config() ->
     #{redis_single := #{tcp := Conf0}} = redis_connect_configs(),
     Conf1 = maps:merge(Conf0, ?COMMON_REDIS_OPTS),

+ 1 - 1
apps/emqx_redis/rebar.config

@@ -3,7 +3,7 @@
 {erl_opts, [debug_info]}.
 {deps, [
         %% NOTE: mind ecpool version when updating eredis_cluster version
-        {eredis_cluster, {git, "https://github.com/emqx/eredis_cluster", {tag, "0.8.1"}}},
+        {eredis_cluster, {git, "https://github.com/emqx/eredis_cluster", {tag, "0.8.2"}}},
         {emqx_connector, {path, "../../apps/emqx_connector"}},
         {emqx_resource, {path, "../../apps/emqx_resource"}}
 ]}.

+ 1 - 1
apps/emqx_redis/src/emqx_redis.app.src

@@ -1,6 +1,6 @@
 {application, emqx_redis, [
     {description, "EMQX Redis Database Connector"},
-    {vsn, "0.1.0"},
+    {vsn, "0.1.1"},
     {registered, []},
     {applications, [
         kernel,

+ 2 - 0
apps/emqx_redis/src/emqx_redis.erl

@@ -146,6 +146,7 @@ on_start(
     Opts =
         [
             {pool_size, PoolSize},
+            {username, maps:get(username, Config, undefined)},
             {password, maps:get(password, Config, "")},
             {auto_reconnect, ?AUTO_RECONNECT_INTERVAL}
         ] ++ Database ++ Servers,
@@ -292,6 +293,7 @@ connect(Opts) ->
 redis_fields() ->
     [
         {pool_size, fun emqx_connector_schema_lib:pool_size/1},
+        {username, fun emqx_connector_schema_lib:username/1},
         {password, fun emqx_connector_schema_lib:password/1},
         {database, #{
             type => non_neg_integer(),

+ 27 - 1
apps/emqx_redis/test/emqx_redis_SUITE.erl

@@ -137,6 +137,31 @@ perform_lifecycle_check(ResourceId, InitialConfig, RedisCommand) ->
             #{timeout => 500}
         )
     ),
+    % check authentication methods
+    ?assertEqual(
+        {ok, <<"OK">>},
+        emqx_resource:query(ResourceId, {cmd, ["AUTH", "public"]})
+    ),
+    ?assertEqual(
+        {error, <<"WRONGPASS invalid username-password pair or user is disabled.">>},
+        emqx_resource:query(ResourceId, {cmd, ["AUTH", "test_passwd"]})
+    ),
+    ?assertEqual(
+        {ok, <<"OK">>},
+        emqx_resource:query(ResourceId, {cmd, ["AUTH", "test_user", "test_passwd"]})
+    ),
+    ?assertEqual(
+        {error, <<"WRONGPASS invalid username-password pair or user is disabled.">>},
+        emqx_resource:query(ResourceId, {cmd, ["AUTH", "test_user", "public"]})
+    ),
+    ?assertEqual(
+        {error, <<"WRONGPASS invalid username-password pair or user is disabled.">>},
+        emqx_resource:query(ResourceId, {cmd, ["AUTH", "wrong_user", "test_passwd"]})
+    ),
+    ?assertEqual(
+        {error, <<"WRONGPASS invalid username-password pair or user is disabled.">>},
+        emqx_resource:query(ResourceId, {cmd, ["AUTH", "wrong_user", "public"]})
+    ),
     ?assertEqual(ok, emqx_resource:stop(ResourceId)),
     % Resource will be listed still, but state will be changed and healthcheck will fail
     % as the worker no longer exists.
@@ -186,7 +211,8 @@ redis_config_sentinel() ->
         "    redis_type = ~s\n" ++
         MaybeSentinel ++
         MaybeDatabase ++
-        "    password = public\n" ++
+        "    username = test_user\n" ++
+        "    password = test_passwd\n" ++
         "    ~s = \"~s:~b\"\n" ++
         "    " ++
         ""

+ 1 - 0
changes/ce/feat-11469.en.md

@@ -0,0 +1 @@
+Added support for specifying username in Redis authentication.