]> source.dussan.org Git - rspamd.git/commitdiff
Added support for Redis 6 ACL (username/password)
authorlaodc <github@laodc.com>
Mon, 21 Aug 2023 08:45:58 +0000 (15:45 +0700)
committerlaodc <github@laodc.com>
Mon, 21 Aug 2023 08:45:58 +0000 (15:45 +0700)
13 files changed:
conf/modules.d/redis.conf
lualib/lua_redis.lua
lualib/rspamadm/configwizard.lua
lualib/rspamadm/fuzzy_convert.lua
src/libserver/fuzzy_backend/fuzzy_backend_redis.c
src/libserver/redis_pool.cxx
src/libserver/redis_pool.h
src/libstat/backends/redis_backend.c
src/libstat/learn_cache/redis_cache.c
src/lua/lua_redis.c
src/plugins/lua/bimi.lua
src/rspamadm/fuzzy_convert.c
src/rspamadm/stat_convert.c

index eb430cbb185d27b31473487082744ef4433a9025..24948b1509e295fe4a7d6d0de8114fbcd1151c4f 100644 (file)
@@ -19,6 +19,7 @@ redis {
   #disabled_modules = ["ratelimit"]; # List of modules that should not use redis from this section
   #timeout = 1s;
   #db = "0";
+  #username = "some_username";
   #password = "some_password";
   .include(try=true,priority=5) "${DBDIR}/dynamic/redis.conf"
   .include(try=true,priority=1,duplicate=merge) "$LOCAL_CONFDIR/local.d/redis.conf"
index b03160bb01f494bef0939be4a1322f036cf1b284..377541f878f6f55ed669fb7444fb27a4b7d57f5c 100644 (file)
@@ -30,12 +30,14 @@ local common_schema = {
   database = ts.string:is_optional():describe("Database number"),
   dbname = ts.string:is_optional():describe("Database number"),
   prefix = ts.string:is_optional():describe("Key prefix"),
+  username = ts.string:is_optional():describe("Username"),
   password = ts.string:is_optional():describe("Password"),
   expand_keys = ts.boolean:is_optional():describe("Expand keys"),
   sentinels = (ts.string + ts.array_of(ts.string)):is_optional():describe("Sentinel servers"),
   sentinel_watch_time = (ts.number + ts.string / lutil.parse_time_interval):is_optional():describe("Sentinel watch time"),
   sentinel_masters_pattern = ts.string:is_optional():describe("Sentinel masters pattern"),
   sentinel_master_maxerrors = (ts.number + ts.string / tonumber):is_optional():describe("Sentinel master max errors"),
+  sentinel_username = ts.string:is_optional():describe("sentinel username"),
   sentinel_password = ts.string:is_optional():describe("Sentinel password"),
 }
 
@@ -153,6 +155,7 @@ local function redis_query_sentinel(ev_base, params, initialised)
         local ret = rspamd_redis.make_request {
           host = addr:get_addr(),
           timeout = params.timeout,
+          username = params.sentinel_username,
           password = params.sentinel_password,
           config = rspamd_config,
           ev_base = ev_base,
@@ -184,6 +187,7 @@ local function redis_query_sentinel(ev_base, params, initialised)
     timeout = params.timeout,
     config = rspamd_config,
     ev_base = ev_base,
+    username = params.sentinel_username,
     password = params.sentinel_password,
     cmd = 'SENTINEL',
     args = { 'masters' },
@@ -366,6 +370,9 @@ local function process_redis_opts(options, redis_params)
       redis_params['db'] = tostring(options['database'])
     end
   end
+  if options['username'] and not redis_params['username'] then
+    redis_params['username'] = options['username']
+  end
   if options['password'] and not redis_params['password'] then
     redis_params['password'] = options['password']
   end
@@ -996,6 +1003,10 @@ local function rspamd_redis_make_request(task, redis_params, key, is_write,
     end
   end
 
+  if redis_params['username'] then
+    options['username'] = redis_params['username']
+  end
+
   if redis_params['password'] then
     options['password'] = redis_params['password']
   end
@@ -1086,6 +1097,10 @@ local function redis_make_request_taskless(ev_base, cfg, redis_params, key,
     end
   end
 
+  if redis_params['username'] then
+    options['username'] = redis_params['username']
+  end
+
   if redis_params['password'] then
     options['password'] = redis_params['password']
   end
@@ -1157,6 +1172,10 @@ local function prepare_redis_call(script)
       upstream = s
     }
 
+    if script.redis_params['username'] then
+      cur_opts['username'] = script.redis_params['username']
+    end
+
     if script.redis_params['password'] then
       cur_opts['password'] = script.redis_params['password']
     end
@@ -1497,7 +1516,15 @@ local function redis_connect_sync(redis_params, is_write, key, cfg, ev_base)
 
   if conn then
     local need_exec = false
-    if redis_params['password'] then
+    if redis_params['username'] then
+      if redis_params['password'] then
+        conn:add_cmd('AUTH', { redis_params['username'], redis_params['password'] })
+        need_exec = true
+      else
+        logger.errx('Redis requires a password when username is supplied')
+        return false, nil, addr
+      end
+    elseif redis_params['password'] then
       conn:add_cmd('AUTH', { redis_params['password'] })
       need_exec = true
     end
@@ -1602,6 +1629,10 @@ exports.request = function(redis_params, attrs, req)
     opts.args = req
   end
 
+  if redis_params.username then
+    opts.username = redis_params.username
+  end
+
   if redis_params.password then
     opts.password = redis_params.password
   end
@@ -1701,6 +1732,10 @@ exports.connect = function(redis_params, attrs)
   opts.host = addr:get_addr()
   opts.timeout = redis_params.timeout
 
+  if redis_params.username then
+    opts.username = redis_params.username
+  end
+
   if redis_params.password then
     opts.password = redis_params.password
   end
index 27c358e3b7e7fafb7958f1ee55e3bf2ac01b3e9a..7bcda5a018bc78f68a622e0f203d464bc1510374 100644 (file)
@@ -249,7 +249,21 @@ local function setup_redis(cfg, changes)
       redis_params['write_servers'] = ws
     end
 
-    if ask_yes_no('Do you have any password set for your Redis?') then
+    if ask_yes_no('Do you have any username set for your Redis?') then
+      local usernm = readline_default("Enter Redis username:", nil)
+
+      if usernm then
+        changes.l['redis.conf']['username'] = usernm
+        redis_params['username'] = usernm
+      end
+
+      local passwd = readline_default("Enter Redis password:", nil)
+
+      if passwd then
+        changes.l['redis.conf']['password'] = passwd
+        redis_params['password'] = passwd
+      end
+    elseif ask_yes_no('Do you have any password set for your Redis?') then
       local passwd = readline_default("Enter Redis password:", nil)
 
       if passwd then
index a31baa4e2af36b0b3a77d0735c5fd4a9a3dfd353..67a2664bcea359d292c22c9419dc76b0d5db5e5f 100644 (file)
@@ -12,7 +12,16 @@ local function connect_redis(server, password, db)
     return nil, 'Cannot connect: ' .. err
   end
 
-  if password then
+  if username then
+    if password then
+      ret = conn:add_cmd('AUTH', { username, password })
+      if not ret then
+        return nil, 'Cannot queue command'
+      end
+    else
+      return nil, 'Redis requires a password when username is supplied'
+    end
+  else if password then
     ret = conn:add_cmd('AUTH', { password })
     if not ret then
       return nil, 'Cannot queue command'
@@ -28,8 +37,8 @@ local function connect_redis(server, password, db)
   return conn, nil
 end
 
-local function send_digests(digests, redis_host, redis_password, redis_db)
-  local conn, err = connect_redis(redis_host, redis_password, redis_db)
+local function send_digests(digests, redis_host, redis_username, redis_password, redis_db)
+  local conn, err = connect_redis(redis_host, redis_username, redis_password, redis_db)
   if err then
     print(err)
     return false
@@ -62,8 +71,8 @@ local function send_digests(digests, redis_host, redis_password, redis_db)
   return true
 end
 
-local function send_shingles(shingles, redis_host, redis_password, redis_db)
-  local conn, err = connect_redis(redis_host, redis_password, redis_db)
+local function send_shingles(shingles, redis_host, redis_username, redis_password, redis_db)
+  local conn, err = connect_redis(redis_host, redis_username, redis_password, redis_db)
   if err then
     print("Redis error: " .. err)
     return false
@@ -95,8 +104,8 @@ local function send_shingles(shingles, redis_host, redis_password, redis_db)
   return true
 end
 
-local function update_counters(total, redis_host, redis_password, redis_db)
-  local conn, err = connect_redis(redis_host, redis_password, redis_db)
+local function update_counters(total, redis_host, redis_username, redis_password, redis_db)
+  local conn, err = connect_redis(redis_host, redis_username, redis_password, redis_db)
   if err then
     print(err)
     return false
@@ -135,6 +144,7 @@ return function(_, res)
   local total_digests = 0
   local total_shingles = 0
   local lim_batch = 1000 -- Update each 1000 entries
+  local redis_username = res['redis_username']
   local redis_password = res['redis_password']
   local redis_db = nil
 
@@ -162,14 +172,14 @@ return function(_, res)
       end
     end
     if num_batch_digests >= lim_batch then
-      if not send_digests(digests, res['redis_host'], redis_password, redis_db) then
+      if not send_digests(digests, res['redis_host'], redis_username, redis_password, redis_db) then
         return
       end
       num_batch_digests = 0
       digests = {}
     end
     if num_batch_shingles >= lim_batch then
-      if not send_shingles(shingles, res['redis_host'], redis_password, redis_db) then
+      if not send_shingles(shingles, res['redis_host'], redis_username, redis_password, redis_db) then
         return
       end
       num_batch_shingles = 0
@@ -177,12 +187,12 @@ return function(_, res)
     end
   end
   if digests[1] then
-    if not send_digests(digests, res['redis_host'], redis_password, redis_db) then
+    if not send_digests(digests, res['redis_host'], redis_username, redis_password, redis_db) then
       return
     end
   end
   if shingles[1] then
-    if not send_shingles(shingles, res['redis_host'], redis_password, redis_db) then
+    if not send_shingles(shingles, res['redis_host'], redis_username, redis_password, redis_db) then
       return
     end
   end
@@ -191,7 +201,7 @@ return function(_, res)
       'Migrated %d digests and %d shingles',
       total_digests, total_shingles
   )
-  if not update_counters(total_digests, res['redis_host'], redis_password, redis_db) then
+  if not update_counters(total_digests, res['redis_host'], redis_username, redis_password, redis_db) then
     message = message .. ' but failed to update counters'
   end
   print(message)
index 9b5b3bc02ad64c990142822f943cb7bb2886ea9e..7ab7ca63e1c9ad3138624e1bb6f93b61eab1e8ee 100644 (file)
@@ -52,6 +52,7 @@ INIT_LOG_MODULE(fuzzy_redis)
 struct rspamd_fuzzy_backend_redis {
        lua_State *L;
        const gchar *redis_object;
+       const gchar *username;
        const gchar *password;
        const gchar *dbname;
        gchar *id;
@@ -256,6 +257,14 @@ rspamd_fuzzy_backend_init_redis(struct rspamd_fuzzy_backend *bk,
        }
        lua_pop(L, 1);
 
+       lua_pushstring(L, "username");
+       lua_gettable(L, -2);
+       if (lua_type(L, -1) == LUA_TSTRING) {
+               backend->username = rspamd_mempool_strdup(cfg->cfg_pool,
+                                                                                                 lua_tostring(L, -1));
+       }
+       lua_pop(L, 1);
+
        lua_pushstring(L, "password");
        lua_gettable(L, -2);
        if (lua_type(L, -1) == LUA_TSTRING) {
@@ -277,6 +286,11 @@ rspamd_fuzzy_backend_init_redis(struct rspamd_fuzzy_backend *bk,
                                                                         strlen(backend->dbname));
        }
 
+       if (backend->username) {
+               rspamd_cryptobox_hash_update(&st, backend->username,
+                                                                        strlen(backend->username));
+       }
+
        if (backend->password) {
                rspamd_cryptobox_hash_update(&st, backend->password,
                                                                         strlen(backend->password));
@@ -681,7 +695,8 @@ void rspamd_fuzzy_backend_check_redis(struct rspamd_fuzzy_backend *bk,
        addr = rspamd_upstream_addr_next(up);
        g_assert(addr != NULL);
        session->ctx = rspamd_redis_pool_connect(backend->pool,
-                                                                                        backend->dbname, backend->password,
+                                                                                        backend->dbname,
+                                                                                        backend->username, backend->password,
                                                                                         rspamd_inet_address_to_string(addr),
                                                                                         rspamd_inet_address_get_port(addr));
 
@@ -819,7 +834,8 @@ void rspamd_fuzzy_backend_count_redis(struct rspamd_fuzzy_backend *bk,
        addr = rspamd_upstream_addr_next(up);
        g_assert(addr != NULL);
        session->ctx = rspamd_redis_pool_connect(backend->pool,
-                                                                                        backend->dbname, backend->password,
+                                                                                        backend->dbname,
+                                                                                        backend->username, backend->password,
                                                                                         rspamd_inet_address_to_string(addr),
                                                                                         rspamd_inet_address_get_port(addr));
 
@@ -956,7 +972,8 @@ void rspamd_fuzzy_backend_version_redis(struct rspamd_fuzzy_backend *bk,
        addr = rspamd_upstream_addr_next(up);
        g_assert(addr != NULL);
        session->ctx = rspamd_redis_pool_connect(backend->pool,
-                                                                                        backend->dbname, backend->password,
+                                                                                        backend->dbname,
+                                                                                        backend->username, backend->password,
                                                                                         rspamd_inet_address_to_string(addr),
                                                                                         rspamd_inet_address_get_port(addr));
 
@@ -1527,7 +1544,8 @@ void rspamd_fuzzy_backend_update_redis(struct rspamd_fuzzy_backend *bk,
        addr = rspamd_upstream_addr_next(up);
        g_assert(addr != NULL);
        session->ctx = rspamd_redis_pool_connect(backend->pool,
-                                                                                        backend->dbname, backend->password,
+                                                                                        backend->dbname,
+                                                                                        backend->username, backend->password,
                                                                                         rspamd_inet_address_to_string(addr),
                                                                                         rspamd_inet_address_get_port(addr));
 
index 86ff2adb289bbbd33bbfa524013ca17381a81397..34c09d055f306bd49f388c4fd55bbbf9e1513133 100644 (file)
@@ -62,6 +62,7 @@ struct redis_pool_connection {
        explicit redis_pool_connection(redis_pool *_pool,
                                                                   redis_pool_elt *_elt,
                                                                   const std::string &db,
+                                                                  const std::string &username,
                                                                   const std::string &password,
                                                                   struct redisAsyncContext *_ctx);
 
@@ -87,6 +88,7 @@ class redis_pool_elt {
        std::list<redis_pool_connection_ptr> terminating;
        std::string ip;
        std::string db;
+       std::string username;
        std::string password;
        int port;
        redis_pool_key_t key;
@@ -100,16 +102,20 @@ public:
        redis_pool_elt(redis_pool_elt &&other) = default;
 
        explicit redis_pool_elt(redis_pool *_pool,
-                                                       const gchar *_db, const gchar *_password,
+                                                       const gchar *_db, const gchar *_username,
+                                                       const gchar *_password,
                                                        const char *_ip, int _port)
                : pool(_pool), ip(_ip), port(_port),
-                 key(redis_pool_elt::make_key(_db, _password, _ip, _port))
+                 key(redis_pool_elt::make_key(_db, _username, _password, _ip, _port))
        {
                is_unix = ip[0] == '.' || ip[0] == '/';
 
                if (_db) {
                        db = _db;
                }
+               if( _username ) {
+                       username = _username;
+               }
                if (_password) {
                        password = _password;
                }
@@ -144,8 +150,8 @@ public:
                conn->elt_pos = std::prev(std::end(terminating));
        }
 
-       inline static auto make_key(const gchar *db, const gchar *password,
-                                                               const char *ip, int port) -> redis_pool_key_t
+       inline static auto make_key(const gchar *db, const gchar *username,
+                                                               const gchar *password, const char *ip, int port) -> redis_pool_key_t
        {
                rspamd_cryptobox_fast_hash_state_t st;
 
@@ -154,6 +160,9 @@ public:
                if (db) {
                        rspamd_cryptobox_fast_hash_update(&st, db, strlen(db));
                }
+               if (username) {
+                       rspamd_cryptobox_fast_hash_update(&st, username, strlen(username));
+               }
                if (password) {
                        rspamd_cryptobox_fast_hash_update(&st, password, strlen(password));
                }
@@ -232,8 +241,8 @@ public:
                cfg = _cfg;
        }
 
-       auto new_connection(const gchar *db, const gchar *password,
-                                               const char *ip, int port) -> redisAsyncContext *;
+       auto new_connection(const gchar *db, const gchar *username,
+                                               const gchar *password, const char *ip, int port) -> redisAsyncContext *;
 
        auto release_connection(redisAsyncContext *ctx,
                                                        enum rspamd_redis_pool_release_type how) -> void;
@@ -398,6 +407,7 @@ auto redis_pool_connection::schedule_timeout() -> void
 redis_pool_connection::redis_pool_connection(redis_pool *_pool,
                                                                                         redis_pool_elt *_elt,
                                                                                         const std::string &db,
+                                                                                        const std::string &username,
                                                                                         const std::string &password,
                                                                                         struct redisAsyncContext *_ctx)
        : ctx(_ctx), elt(_elt), pool(_pool)
@@ -413,7 +423,18 @@ redis_pool_connection::redis_pool_connection(redis_pool *_pool,
        redisLibevAttach(pool->event_loop, ctx);
        redisAsyncSetDisconnectCallback(ctx, redis_pool_connection::redis_on_disconnect);
 
-       if (!password.empty()) {
+       if (!username.empty()) {
+               if (!password.empty()) {
+                       redisAsyncCommand(ctx, nullptr, nullptr,
+                                                 "AUTH %s %s", username.c_str(), password.c_str());
+               }
+               else {
+                       msg_err("Redis requires a password when username is supplied");
+                       redisAsyncFree(ctx);
+                       return nullptr;
+               }
+       }
+       else if (!password.empty()) {
                redisAsyncCommand(ctx, nullptr, nullptr,
                                                  "AUTH %s", password.c_str());
        }
@@ -464,7 +485,7 @@ auto redis_pool_elt::new_connection() -> redisAsyncContext *
                        auto *nctx = redis_async_new();
                        if (nctx) {
                                active.emplace_front(std::make_unique<redis_pool_connection>(pool, this,
-                                                                                                                                                        db.c_str(), password.c_str(), nctx));
+                                                                                                                                                        db.c_str(), username.c_str(), password.c_str(), nctx));
                                active.front()->elt_pos = active.begin();
                        }
 
@@ -475,7 +496,7 @@ auto redis_pool_elt::new_connection() -> redisAsyncContext *
                auto *nctx = redis_async_new();
                if (nctx) {
                        active.emplace_front(std::make_unique<redis_pool_connection>(pool, this,
-                                                                                                                                                db.c_str(), password.c_str(), nctx));
+                                                                                                                                                db.c_str(), username.c_str(), password.c_str(), nctx));
                        active.front()->elt_pos = active.begin();
                }
 
@@ -485,12 +506,12 @@ auto redis_pool_elt::new_connection() -> redisAsyncContext *
        RSPAMD_UNREACHABLE;
 }
 
-auto redis_pool::new_connection(const gchar *db, const gchar *password,
-                                                               const char *ip, int port) -> redisAsyncContext *
+auto redis_pool::new_connection(const gchar *db, const gchar *username,
+                                                               const gchar *password, const char *ip, int port) -> redisAsyncContext *
 {
 
        if (!wanna_die) {
-               auto key = redis_pool_elt::make_key(db, password, ip, port);
+               auto key = redis_pool_elt::make_key(db, username, password, ip, port);
                auto found_elt = elts_by_key.find(key);
 
                if (found_elt != elts_by_key.end()) {
@@ -501,7 +522,7 @@ auto redis_pool::new_connection(const gchar *db, const gchar *password,
                else {
                        /* Need to create a pool */
                        auto nelt = elts_by_key.try_emplace(key,
-                                                                                               this, db, password, ip, port);
+                                                                                               this, db, username, password, ip, port);
 
                        return nelt.first->second.new_connection();
                }
@@ -583,13 +604,13 @@ void rspamd_redis_pool_config(void *p,
 
 struct redisAsyncContext *
 rspamd_redis_pool_connect(void *p,
-                                                 const gchar *db, const gchar *password,
-                                                 const char *ip, int port)
+                                                 const gchar *db, const gchar *username,
+                                                 const gchar *password, const char *ip, int port)
 {
        g_assert(p != NULL);
        auto *pool = reinterpret_cast<class rspamd::redis_pool *>(p);
 
-       return pool->new_connection(db, password, ip, port);
+       return pool->new_connection(db, username, password, ip, port);
 }
 
 
index 339bf5f5310ae6cee8e92c2e1976202eb64f32dc..ecdaa0f856d1dc352e46dc6c254a6851c805691a 100644 (file)
@@ -45,6 +45,7 @@ void rspamd_redis_pool_config(void *pool,
  * Create or reuse the specific redis connection
  * @param pool
  * @param db
+ * @param username
  * @param password
  * @param ip
  * @param port
@@ -52,7 +53,7 @@ void rspamd_redis_pool_config(void *pool,
  */
 struct redisAsyncContext *rspamd_redis_pool_connect(
        void *pool,
-       const gchar *db, const gchar *password,
+       const gchar *db, const gchar *username, const gchar *password,
        const char *ip, int port);
 
 enum rspamd_redis_pool_release_type {
index a0d11bb0dcfc08892bc02ebfea630b4387c06282..72ffd6c44152d43d401b976f737402f306e8ca94 100644 (file)
@@ -45,6 +45,7 @@ struct redis_stat_ctx {
        gint conf_ref;
        struct rspamd_stat_async_elt *stat_elt;
        const gchar *redis_object;
+       const gchar *username;
        const gchar *password;
        const gchar *dbname;
        gdouble timeout;
@@ -363,7 +364,17 @@ gsize rspamd_redis_expand_object(const gchar *pattern,
 static void
 rspamd_redis_maybe_auth(struct redis_stat_ctx *ctx, redisAsyncContext *redis)
 {
-       if (ctx->password) {
+       if (ctx->username) {
+               if (ctx->password) {
+                       redisAsyncCommand(redis, NULL, NULL, "AUTH %s %s", ctx->username, ctx->password);
+               }
+               else {
+                       msg_err("Redis requires a password when username is supplied");
+                       redisAsyncFree(ctx);
+                       return NULL;
+               }
+       }
+       else if (ctx->password) {
                redisAsyncCommand(redis, NULL, NULL, "AUTH %s", ctx->password);
        }
        if (ctx->dbname) {
@@ -1603,6 +1614,14 @@ rspamd_redis_init(struct rspamd_stat_ctx *ctx,
        }
        lua_pop(L, 1);
 
+       lua_pushstring(L, "username");
+       lua_gettable(L, -2);
+       if (lua_type(L, -1) == LUA_TSTRING) {
+               backend->username = rspamd_mempool_strdup(cfg->cfg_pool,
+                                                                                                 lua_tostring(L, -1));
+       }
+       lua_pop(L, 1);
+
        lua_pushstring(L, "password");
        lua_gettable(L, -2);
        if (lua_type(L, -1) == LUA_TSTRING) {
index 3026009bcdfce414405b636ce5aa1769ced108ca..0bbae8560e8f185a19908c020aa289ecea44a42b 100644 (file)
@@ -35,6 +35,7 @@ static const gchar *M = "redis learn cache";
 struct rspamd_redis_cache_ctx {
        lua_State *L;
        struct rspamd_statfile_config *stcf;
+       const gchar *username;
        const gchar *password;
        const gchar *dbname;
        const gchar *redis_object;
@@ -77,7 +78,17 @@ static void
 rspamd_redis_cache_maybe_auth(struct rspamd_redis_cache_ctx *ctx,
                                                          redisAsyncContext *redis)
 {
-       if (ctx->password) {
+       if (ctx->username) {
+               if (ctx->password) {
+                       redisAsyncCommand(redis, NULL, NULL, "AUTH %s %s", ctx->username, ctx->password);
+               }
+               else {
+                       msg_err("Redis requires a password when username is supplied");
+                       redisAsyncFree(ctx);
+                       return NULL;
+               }
+       }
+       else if (ctx->password) {
                redisAsyncCommand(redis, NULL, NULL, "AUTH %s", ctx->password);
        }
        if (ctx->dbname) {
@@ -328,6 +339,14 @@ rspamd_stat_cache_redis_init(struct rspamd_stat_ctx *ctx,
        }
        lua_pop(L, 1);
 
+       lua_pushstring(L, "username");
+       lua_gettable(L, -2);
+       if (lua_type(L, -1) == LUA_TSTRING) {
+               cache_ctx->username = rspamd_mempool_strdup(cfg->cfg_pool,
+                                                                                                       lua_tostring(L, -1));
+       }
+       lua_pop(L, 1);
+
        lua_pushstring(L, "password");
        lua_gettable(L, -2);
        if (lua_type(L, -1) == LUA_TSTRING) {
index 2ac5a47b7efa0aedde529826fb46f474ddecc672..1ad3b3d170f064ab8db08d3bedf891e7e10e7f61 100644 (file)
@@ -110,9 +110,9 @@ struct lua_redis_userdata {
 };
 
 #define msg_debug_lua_redis(...) rspamd_conditional_debug_fast(NULL, NULL,                                        \
-                                                                                                                          rspamd_lua_redis_log_id, "lua_redis", ud->log_tag, \
-                                                                                                                          G_STRFUNC,                                         \
-                                                                                                                          __VA_ARGS__)
+                                                                                                                                rspamd_lua_redis_log_id, "lua_redis", ud->log_tag, \
+                                                                                                                                G_STRFUNC,                                         \
+                                                                                                                                __VA_ARGS__)
 INIT_LOG_MODULE(lua_redis)
 
 #define LUA_REDIS_SPECIFIC_REPLIED (1 << 0)
@@ -875,7 +875,7 @@ rspamd_lua_redis_prepare_connection(lua_State *L, gint *pcbref, gboolean is_asyn
        struct rspamd_lua_ip *addr = NULL;
        struct rspamd_task *task = NULL;
        const gchar *host = NULL;
-       const gchar *password = NULL, *dbname = NULL, *log_tag = NULL;
+       const gchar *username = NULL, *password = NULL, *dbname = NULL, *log_tag = NULL;
        gint cbref = -1;
        struct rspamd_config *cfg = NULL;
        struct rspamd_async_session *session = NULL;
@@ -970,6 +970,13 @@ rspamd_lua_redis_prepare_connection(lua_State *L, gint *pcbref, gboolean is_asyn
                }
                lua_pop(L, 1);
 
+               lua_pushstring(L, "username");
+               lua_gettable(L, -2);
+               if (lua_type(L, -1) == LUA_TSTRING) {
+                       username = lua_tostring(L, -1);
+               }
+               lua_pop(L, 1);
+
                lua_pushstring(L, "password");
                lua_gettable(L, -2);
                if (lua_type(L, -1) == LUA_TSTRING) {
@@ -1053,7 +1060,7 @@ rspamd_lua_redis_prepare_connection(lua_State *L, gint *pcbref, gboolean is_asyn
        if (ret) {
                ud->terminated = 0;
                ud->ctx = rspamd_redis_pool_connect(ud->pool,
-                                                                                       dbname, password,
+                                                                                       dbname, username, password,
                                                                                        rspamd_inet_address_to_string(addr->addr),
                                                                                        rspamd_inet_address_get_port(addr->addr));
 
index 9144845438030166d33606502bda90e196c01264..5053cc94108bcecd13696d4d0c7da1ecc4d7c28d 100644 (file)
@@ -263,7 +263,14 @@ local function check_bimi_vmc(task, domain, record)
         if redis_params.db then
           db = string.format('/%s', redis_params.db)
         end
-        if redis_params.password then
+        if redis_params.username then
+          if redis_params.password then
+            password = string.format( '%s:%s@', redis_params.username, redis_params.password)
+          else
+            rspamd_logger.errx(task, "Redis requires a password when username is supplied")
+            return
+          end
+        elseif redis_params.password then
           password = string.format(':%s@', redis_params.password)
         end
         local redis_server = string.format('redis://%s%s:%s%s',
index 1b2866b594502bec64698a1d1321cb6b56b06928..5d967a64cdb2fd2995be4c0fcbcee4edcd3cf1c2 100644 (file)
@@ -21,6 +21,7 @@
 static gchar *source_db = NULL;
 static gchar *redis_host = NULL;
 static gchar *redis_db = NULL;
+static gchar *redis_username = NULL;
 static gchar *redis_password = NULL;
 static int64_t fuzzy_expiry = 0;
 
@@ -46,6 +47,8 @@ static GOptionEntry entries[] = {
         "Output redis ip (in format ip:port)", NULL},
        {"dbname", 'D', 0, G_OPTION_ARG_STRING, &redis_db,
         "Database in redis (should be numeric)", NULL},
+       {"username", 'u', 0, G_OPTION_ARG_STRING, &redis_username,
+        "Username to connect to redis", NULL},
        {"password", 'p', 0, G_OPTION_ARG_STRING, &redis_password,
         "Password to connect to redis", NULL},
        {NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL}};
@@ -63,6 +66,7 @@ rspamadm_fuzzyconvert_help(gboolean full_help, const struct rspamadm_command *cm
                                   "-d: input sqlite\n"
                                   "-h: output redis ip (in format ip:port)\n"
                                   "-D: output redis database\n"
+                                  "-u: redis username\n";
                                   "-p: redis password\n";
        }
        else {
@@ -117,6 +121,10 @@ rspamadm_fuzzyconvert(gint argc, gchar **argv, const struct rspamadm_command *cm
        ucl_object_insert_key(obj, ucl_object_fromint(fuzzy_expiry),
                                                  "expiry", 0, false);
 
+       if (redis_username) {
+               ucl_object_insert_key(obj, ucl_object_fromstring(redis_username),
+                                                         "redis_username", 0, false);
+       }
        if (redis_password) {
                ucl_object_insert_key(obj, ucl_object_fromstring(redis_password),
                                                          "redis_password", 0, false);
index ba2c4efb9b263f4f0ac4874bb56aba94bc619924..0741279aa9b826fcff438d3456b388ea3ac88195 100644 (file)
@@ -34,6 +34,7 @@ static gchar *cache_db = NULL;
 /* Outputs */
 static gchar *redis_host = NULL;
 static gchar *redis_db = NULL;
+static gchar *redis_username = NULL;
 static gchar *redis_password = NULL;
 static gboolean reset_previous = FALSE;
 
@@ -70,6 +71,8 @@ static GOptionEntry entries[] = {
         "Input learn cache", NULL},
        {"redis-host", 'h', 0, G_OPTION_ARG_STRING, &redis_host,
         "Output redis ip (in format ip:port)", NULL},
+       {"redis-username", 'u', 0, G_OPTION_ARG_STRING, &redis_username,
+        "Username to connect to redis", NULL},
        {"redis-password", 'p', 0, G_OPTION_ARG_STRING, &redis_password,
         "Password to connect to redis", NULL},
        {"redis-db", 'd', 0, G_OPTION_ARG_STRING, &redis_db,
@@ -92,6 +95,7 @@ rspamadm_statconvert_help(gboolean full_help, const struct rspamadm_command *cmd
                                   "** Or specify options directly **\n"
                                   "--redis-host: output redis ip (in format ip:port)\n"
                                   "--redis-db: output redis database\n"
+                                  "--redis-username: redis username\n"
                                   "--redis-password: redis password\n"
                                   "--cache: sqlite3 file for learn cache\n"
                                   "--spam-db: sqlite3 input file for spam data\n"
@@ -229,6 +233,11 @@ rspamadm_statconvert(gint argc, gchar **argv, const struct rspamadm_command *cmd
                                                                  "dbname", 0, false);
                }
 
+               if (redis_username) {
+                       ucl_object_insert_key(redis, ucl_object_fromstring(redis_username),
+                                                                 "username", 0, false);
+               }
+
                if (redis_password) {
                        ucl_object_insert_key(redis, ucl_object_fromstring(redis_password),
                                                                  "password", 0, false);