You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pulsar.apache.org by mm...@apache.org on 2022/10/13 16:58:30 UTC

[pulsar-client-python] branch main updated: Support auth param string for Basic authentication (#15)

This is an automated email from the ASF dual-hosted git repository.

mmerli pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/pulsar-client-python.git


The following commit(s) were added to refs/heads/main by this push:
     new 51d3846  Support auth param string for Basic authentication (#15)
51d3846 is described below

commit 51d3846cad82a140929df725f03eb2edbb2e4e02
Author: Yunze Xu <xy...@163.com>
AuthorDate: Fri Oct 14 00:58:25 2022 +0800

    Support auth param string for Basic authentication (#15)
    
    * Support auth param string for Basic authentication
    
    ### Motivation
    
    https://github.com/apache/pulsar/pull/17482 supported basic
    authentication for Python client, but the `AuthenticationBasic` class
    accepts two positional arguments as the username and password. It's not
    good for extension. We should accept an auth param string like
    `AuthenticationOauth2` so that no changes are needed if the upstream C++
    client's implementation changed, like
    https://github.com/apache/pulsar-client-cpp/pull/37.
    
    ### Modifications
    
    To be compatible with the existing API, change the first two arguments
    to keyword arguments. Then, add the 3rd keyword argument to represent
    the auth param string.
    
    ### Verifications
    
    `test_basic_auth` and `test_invalid_basic_auth` are extended for this
    change.
    
    * Add method argument and related tests
    
    * Add type check for method arg
---
 pulsar/__init__.py    | 37 +++++++++++++++++++++++++++++--------
 src/authentication.cc | 12 +++++++++---
 tests/pulsar_test.py  | 37 ++++++++++++++++++++++++++++++++-----
 3 files changed, 70 insertions(+), 16 deletions(-)

diff --git a/pulsar/__init__.py b/pulsar/__init__.py
index ef17844..1d29d90 100644
--- a/pulsar/__init__.py
+++ b/pulsar/__init__.py
@@ -347,18 +347,39 @@ class AuthenticationBasic(Authentication):
     """
     Basic Authentication implementation
     """
-    def __init__(self, username, password):
+    def __init__(self, username=None, password=None, method='basic', auth_params_string=None):
         """
         Create the Basic authentication provider instance.
 
-        **Args**
+        For example, if you want to create a basic authentication instance whose
+        username is "my-user" and password is "my-pass", there are two ways:
 
-        * `username`: Used to authentication as username
-        * `password`: Used to authentication as password
-        """
-        _check_type(str, username, 'username')
-        _check_type(str, password, 'password')
-        self.auth = _pulsar.AuthenticationBasic(username, password)
+        ```
+        auth = AuthenticationBasic('my-user', 'my-pass')
+        auth = AuthenticationBasic(auth_params_string='{"username": "my-user", "password": "my-pass"}')
+        ```
+
+        **Args**
+        * username : str, optional
+        * password : str, optional
+        * method : str, optional
+            The authentication method name (default is 'basic')
+        * auth_params_string : str, optional
+            The JSON presentation of all fields above (default is None)
+            If it's not None, the other parameters will be ignored.
+            Here is an example JSON presentation:
+              {"username": "my-user", "password": "my-pass", "method": "oms3.0"}
+            The `username` and `password` fields are required. If the "method" field is not set,
+            it will be "basic" by default.
+        """
+        if auth_params_string is not None:
+            _check_type(str, auth_params_string, 'auth_params_string')
+            self.auth = _pulsar.AuthenticationBasic('', '', '', auth_params_string)
+        else:
+            _check_type(str, username, 'username')
+            _check_type(str, password, 'password')
+            _check_type(str, method, 'method')
+            self.auth = _pulsar.AuthenticationBasic(username, password, method, '')
 
 class Client:
     """
diff --git a/src/authentication.cc b/src/authentication.cc
index 7917498..1bec468 100644
--- a/src/authentication.cc
+++ b/src/authentication.cc
@@ -91,9 +91,14 @@ struct AuthenticationOauth2Wrapper : public AuthenticationWrapper {
 };
 
 struct AuthenticationBasicWrapper : public AuthenticationWrapper {
-    AuthenticationBasicWrapper(const std::string& username, const std::string& password)
+    AuthenticationBasicWrapper(const std::string& username, const std::string& password,
+                               const std::string& method, const std::string& authParamsString)
         : AuthenticationWrapper() {
-        this->auth = AuthBasic::create(username, password);
+        if (authParamsString.empty()) {
+            this->auth = AuthBasic::create(username, password, method);
+        } else {
+            this->auth = AuthBasic::create(authParamsString);
+        }
     }
 };
 
@@ -115,5 +120,6 @@ void export_authentication() {
                                                                        init<const std::string&>());
 
     class_<AuthenticationBasicWrapper, bases<AuthenticationWrapper> >(
-        "AuthenticationBasic", init<const std::string&, const std::string&>());
+        "AuthenticationBasic",
+        init<const std::string&, const std::string&, const std::string&, const std::string&>());
 }
diff --git a/tests/pulsar_test.py b/tests/pulsar_test.py
index 86abbfe..8cc2c55 100755
--- a/tests/pulsar_test.py
+++ b/tests/pulsar_test.py
@@ -1301,12 +1301,10 @@ class PulsarTest(TestCase):
         with self.assertRaises(TypeError):
             fun()
 
-    def test_basic_auth(self):
-        username = "admin"
-        password = "123456"
-        client = Client(self.adminUrl, authentication=AuthenticationBasic(username, password))
+    def _test_basic_auth(self, id, auth):
+        client = Client(self.adminUrl, authentication=auth)
 
-        topic = "persistent://private/auth/my-python-topic-basic-auth"
+        topic = "persistent://private/auth/my-python-topic-basic-auth-" + str(id)
         consumer = client.subscribe(topic, "my-sub", consumer_type=ConsumerType.Shared)
         producer = client.create_producer(topic)
         producer.send(b"hello")
@@ -1316,6 +1314,28 @@ class PulsarTest(TestCase):
         self.assertEqual(msg.data(), b"hello")
         client.close()
 
+    def test_basic_auth(self):
+        username = "admin"
+        password = "123456"
+        self._test_basic_auth(0, AuthenticationBasic(username, password))
+        self._test_basic_auth(1, AuthenticationBasic(
+            auth_params_string='{{"username": "{}","password": "{}"}}'.format(username, password)
+        ))
+
+    def test_basic_auth_method(self):
+        username = "admin"
+        password = "123456"
+        self._test_basic_auth(2, AuthenticationBasic(username, password, 'basic'))
+        with self.assertRaises(pulsar.AuthorizationError):
+            self._test_basic_auth(3, AuthenticationBasic(username, password, 'unknown'))
+        self._test_basic_auth(4, AuthenticationBasic(
+            auth_params_string='{{"username": "{}","password": "{}", "method": "basic"}}'.format(username, password)
+        ))
+        with self.assertRaises(pulsar.AuthorizationError):
+            self._test_basic_auth(5, AuthenticationBasic(
+                auth_params_string='{{"username": "{}","password": "{}", "method": "unknown"}}'.format(username, password)
+            ))
+
     def test_invalid_basic_auth(self):
         username = "invalid"
         password = "123456"
@@ -1323,6 +1343,13 @@ class PulsarTest(TestCase):
         topic = "persistent://private/auth/my-python-topic-invalid-basic-auth"
         with self.assertRaises(pulsar.ConnectError):
             client.subscribe(topic, "my-sub", consumer_type=ConsumerType.Shared)
+        client = Client(self.adminUrl, authentication=AuthenticationBasic(
+            auth_params_string='{{"username": "{}","password": "{}"}}'.format(username, password)
+        ))
+        with self.assertRaises(pulsar.ConnectError):
+            client.subscribe(topic, "my-sub", consumer_type=ConsumerType.Shared)
+        with self.assertRaises(RuntimeError):
+            AuthenticationBasic(auth_params_string='invalid auth params')
 
 if __name__ == "__main__":
     main()