summaryrefslogtreecommitdiff
path: root/redis/connection.py
diff options
context:
space:
mode:
authorBar Shaul <88437685+barshaul@users.noreply.github.com>2022-11-10 12:38:47 +0200
committerGitHub <noreply@github.com>2022-11-10 12:38:47 +0200
commitbb06ccd52924800ac501d17c8a42038c8e5c5770 (patch)
treedf9fa0ae2c2553ecc3779b3f7166d6cad4855c03 /redis/connection.py
parentfb647430f00cc7bb67c978e75f2dabc661567779 (diff)
downloadredis-py-bb06ccd52924800ac501d17c8a42038c8e5c5770.tar.gz
CredentialsProvider class added to support password rotation (#2261)
* A CredentialsProvider class has been added to allow the user to add his own provider for password rotation * Moved CredentialsProvider to a separate file, added type hints * Changed username and password to properties * Added: StaticCredentialProvider, examples, tests Changed: CredentialsProvider to CredentialProvider Fixed: calling AUTH only with password * Changed private members' prefix to __ * fixed linters * fixed auth test * fixed credential test * Raise an error if username or password are passed along with credential_provider * fixing linters * fixing test * Changed dundered to single per side underscore * Changed Connection class members username and password to properties to enable backward compatibility with changing the members value on existing connection. * Reverting last commit and adding backward compatibility to 'username' and 'password' inside on_connect function * Refactored CredentialProvider class * Fixing tuple type to Tuple * Fixing optional string members in UsernamePasswordCredentialProvider * Fixed credential test * Added credential provider support to AsyncRedis * linters * linters * linters * linters - black Co-authored-by: dvora-h <67596500+dvora-h@users.noreply.github.com> Co-authored-by: dvora-h <dvora.heller@redis.com>
Diffstat (limited to 'redis/connection.py')
-rwxr-xr-xredis/connection.py39
1 files changed, 30 insertions, 9 deletions
diff --git a/redis/connection.py b/redis/connection.py
index fecb06b..a2b0074 100755
--- a/redis/connection.py
+++ b/redis/connection.py
@@ -8,9 +8,11 @@ import weakref
from itertools import chain
from queue import Empty, Full, LifoQueue
from time import time
+from typing import Optional
from urllib.parse import parse_qs, unquote, urlparse
from redis.backoff import NoBackoff
+from redis.credentials import CredentialProvider, UsernamePasswordCredentialProvider
from redis.exceptions import (
AuthenticationError,
AuthenticationWrongNumberOfArgsError,
@@ -502,6 +504,7 @@ class Connection:
username=None,
retry=None,
redis_connect_func=None,
+ credential_provider: Optional[CredentialProvider] = None,
):
"""
Initialize a new Connection.
@@ -510,13 +513,21 @@ class Connection:
`retry` to a valid `Retry` object.
To retry on TimeoutError, `retry_on_timeout` can also be set to `True`.
"""
+ if (username or password) and credential_provider is not None:
+ raise DataError(
+ "'username' and 'password' cannot be passed along with 'credential_"
+ "provider'. Please provide only one of the following arguments: \n"
+ "1. 'password' and (optional) 'username'\n"
+ "2. 'credential_provider'"
+ )
self.pid = os.getpid()
self.host = host
self.port = int(port)
self.db = db
- self.username = username
self.client_name = client_name
+ self.credential_provider = credential_provider
self.password = password
+ self.username = username
self.socket_timeout = socket_timeout
self.socket_connect_timeout = socket_connect_timeout or socket_timeout
self.socket_keepalive = socket_keepalive
@@ -675,12 +686,13 @@ class Connection:
"Initialize the connection, authenticate and select a database"
self._parser.on_connect(self)
- # if username and/or password are set, authenticate
- if self.username or self.password:
- if self.username:
- auth_args = (self.username, self.password or "")
- else:
- auth_args = (self.password,)
+ # if credential provider or username and/or password are set, authenticate
+ if self.credential_provider or (self.username or self.password):
+ cred_provider = (
+ self.credential_provider
+ or UsernamePasswordCredentialProvider(self.username, self.password)
+ )
+ auth_args = cred_provider.get_credentials()
# avoid checking health here -- PING will fail if we try
# to check the health prior to the AUTH
self.send_command("AUTH", *auth_args, check_health=False)
@@ -692,7 +704,7 @@ class Connection:
# server seems to be < 6.0.0 which expects a single password
# arg. retry auth with just the password.
# https://github.com/andymccurdy/redis-py/issues/1274
- self.send_command("AUTH", self.password, check_health=False)
+ self.send_command("AUTH", auth_args[-1], check_health=False)
auth_response = self.read_response()
if str_if_bytes(auth_response) != "OK":
@@ -1050,6 +1062,7 @@ class UnixDomainSocketConnection(Connection):
client_name=None,
retry=None,
redis_connect_func=None,
+ credential_provider: Optional[CredentialProvider] = None,
):
"""
Initialize a new UnixDomainSocketConnection.
@@ -1058,12 +1071,20 @@ class UnixDomainSocketConnection(Connection):
`retry` to a valid `Retry` object.
To retry on TimeoutError, `retry_on_timeout` can also be set to `True`.
"""
+ if (username or password) and credential_provider is not None:
+ raise DataError(
+ "'username' and 'password' cannot be passed along with 'credential_"
+ "provider'. Please provide only one of the following arguments: \n"
+ "1. 'password' and (optional) 'username'\n"
+ "2. 'credential_provider'"
+ )
self.pid = os.getpid()
self.path = path
self.db = db
- self.username = username
self.client_name = client_name
+ self.credential_provider = credential_provider
self.password = password
+ self.username = username
self.socket_timeout = socket_timeout
self.retry_on_timeout = retry_on_timeout
if retry_on_error is SENTINEL: