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 87a3506  Add docs and tests for AuthenticationOauth2 (#120)
87a3506 is described below

commit 87a3506d38ea1a0dd15743e34cf2b3ca9d538164
Author: Yunze Xu <[email protected]>
AuthorDate: Wed May 24 02:30:00 2023 +0800

    Add docs and tests for AuthenticationOauth2 (#120)
    
    ### Modifications
    
    Add tests to verify the changes of
    https://github.com/apache/pulsar-client-cpp/pull/249 work for the Python
    client.
    
    Add docs to describe valid JSON fields used to create an
    `AuthenticationOauth2` instance.
---
 .github/workflows/ci-pr-validation.yaml        |  8 +++
 build-support/docker-compose-pulsar-oauth2.yml | 46 +++++++++++++
 pulsar/__init__.py                             | 35 +++++++++-
 tests/oauth2_test.py                           | 90 ++++++++++++++++++++++++++
 4 files changed, 176 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/ci-pr-validation.yaml 
b/.github/workflows/ci-pr-validation.yaml
index aae8551..098e342 100644
--- a/.github/workflows/ci-pr-validation.yaml
+++ b/.github/workflows/ci-pr-validation.yaml
@@ -70,6 +70,14 @@ jobs:
             WHEEL=$(find dist -name '*.whl')
             pip3 install ${WHEEL}[avro]
 
+      - name: Run Oauth2 tests
+        run: |
+          docker compose -f ./build-support/docker-compose-pulsar-oauth2.yml 
up -d
+          # Wait until the namespace is created, currently there is no good 
way to check it via CLI
+          sleep 10
+          python3 tests/oauth2_test.py
+          docker compose -f ./build-support/docker-compose-pulsar-oauth2.yml 
down
+
       - name: Start Pulsar service
         run: ./build-support/pulsar-test-service-start.sh
 
diff --git a/build-support/docker-compose-pulsar-oauth2.yml 
b/build-support/docker-compose-pulsar-oauth2.yml
new file mode 100644
index 0000000..0ab818e
--- /dev/null
+++ b/build-support/docker-compose-pulsar-oauth2.yml
@@ -0,0 +1,46 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+version: '3'
+networks:
+  pulsar:
+    driver: bridge
+services:
+  standalone:
+    image: apachepulsar/pulsar:latest
+    container_name: standalone
+    hostname: local
+    restart: "no"
+    networks:
+      - pulsar
+    environment:
+      - metadataStoreUrl=zk:localhost:2181
+      - clusterName=standalone-oauth2
+      - advertisedAddress=localhost
+      - advertisedListeners=external:pulsar://localhost:6650
+      - PULSAR_MEM=-Xms512m -Xmx512m -XX:MaxDirectMemorySize=256m
+      - PULSAR_PREFIX_authenticationEnabled=true
+      - 
PULSAR_PREFIX_authenticationProviders=org.apache.pulsar.broker.authentication.AuthenticationProviderToken
+      - 
PULSAR_PREFIX_tokenPublicKey=data:;base64,MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2tZd/4gJda3U2Pc3tpgRAN7JPGWx/Gn17v/0IiZlNNRbP/Mmf0Vc6G1qsnaRaWNWOR+t6/a6ekFHJMikQ1N2X6yfz4UjMc8/G2FDPRmWjA+GURzARjVhxc/BBEYGoD0Kwvbq/u9CZm2QjlKrYaLfg3AeB09j0btNrDJ8rBsNzU6AuzChRvXj9IdcE/A/4N/UQ+S9cJ4UXP6NJbToLwajQ5km+CnxdGE6nfB7LWHvOFHjn9C2Rb9e37CFlmeKmIVFkagFM0gbmGOb6bnGI8Bp/VNGV0APef4YaBvBTqwoZ1Z4aDHy5eRxXfAMdtBkBupmBXqL6bpd15XRYUbu/7ck9QIDAQAB
+      - 
PULSAR_PREFIX_brokerClientAuthenticationPlugin=org.apache.pulsar.client.impl.auth.oauth2.AuthenticationOAuth2
+      - 
PULSAR_PREFIX_brokerClientAuthenticationParameters={"issuerUrl":"https://dev-kt-aa9ne.us.auth0.com","audience":"https://dev-kt-aa9ne.us.auth0.com/api/v2/","privateKey":"data:application/json;base64,ewogICAgICAgICAgICAiY2xpZW50X2lkIjoiWGQyM1JIc1VudlVsUDd3Y2hqTllPYUlmYXpnZUhkOXgiLAogICAgICAgICAgICAiY2xpZW50X3NlY3JldCI6InJUN3BzN1dZOHVoZFZ1QlRLV1prdHR3TGRRb3RtZEVsaWFNNXJMZm1nTmlidnF6aVotZzA3Wkg1Mk5fcG9HQWIiCiAgICAgICAgfQ=="}
+    ports:
+      - "6650:6650"
+      - "8080:8080"
+    command: bash -c "bin/apply-config-from-env.py conf/standalone.conf && 
exec bin/pulsar standalone -nss -nfw"
diff --git a/pulsar/__init__.py b/pulsar/__init__.py
index b1b8a9d..f7c05e2 100644
--- a/pulsar/__init__.py
+++ b/pulsar/__init__.py
@@ -289,15 +289,44 @@ class AuthenticationOauth2(Authentication):
     """
     Oauth2 Authentication implementation
     """
-    def __init__(self, auth_params_string):
+    def __init__(self, auth_params_string: str):
         """
         Create the Oauth2 authentication provider instance.
 
+        You can create the instance by setting the necessary fields in the 
JSON string.
+
+        .. code-block:: python
+
+            auth = AuthenticationOauth2('{"issuer_url": "xxx", "private_key": 
"yyy"}')
+
+        The valid JSON fields are:
+
+        * issuer_url (required)
+            The URL of the authentication provider which allows the Pulsar 
client to obtain an
+            access token.
+        * private_key (required)
+            The URL to the JSON credentials file. It supports the following 
pattern formats:
+
+            * ``/path/to/file``
+            * ``file:///path/to/file``
+            * ``file:/path/to/file``
+            * ``data:application/json;base64,<base64-encoded-value>``
+
+            The file content or the based64 encoded value is the encoded JSON 
string that contains
+            the following fields:
+
+            * ``client_id``
+            * ``client_secret``
+        * audience
+            The OAuth 2.0 "resource server" identifier for a Pulsar cluster.
+        * scope
+            The scope of an access request.
+
         Parameters
         ----------
-
-        auth_params_string: str
+        auth_params_string : str
             JSON encoded configuration for Oauth2 client
+
         """
         _check_type(str, auth_params_string, 'auth_params_string')
         self.auth = _pulsar.AuthenticationOauth2.create(auth_params_string)
diff --git a/tests/oauth2_test.py b/tests/oauth2_test.py
new file mode 100644
index 0000000..1411ebc
--- /dev/null
+++ b/tests/oauth2_test.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python3
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from unittest import TestCase, main
+from pulsar import AuthenticationOauth2, AuthenticationError, Client
+import base64
+import os
+
+# This test should run against the standalone that is set up with
+# build-support/docker-compose-pulsar-oauth2.yml
+class Oauth2Test(TestCase):
+
+    service_url = 'pulsar://localhost:6650'
+
+    def test_invalid_private_key(self):
+        def test_create_client(auth_params_string):
+            client = Client(self.service_url, 
authentication=AuthenticationOauth2(auth_params_string))
+            with self.assertRaises(AuthenticationError):
+                client.create_producer('oauth2-test-base64')
+            client.close()
+
+        test_create_client('{"private_key":"xxx:yyy"}')
+        test_create_client('{"private_key":"data:"}')
+        test_create_client('{"private_key":"data:application/x-pem"}')
+        test_create_client('{"private_key":"data:application/json;xxx"}')
+
+    def test_key_file(self):
+        path = (os.path.dirname(os.path.abspath(__file__))
+                + '/test-conf/cpp_credentials_file.json')
+        auth = AuthenticationOauth2(f'''{{
+            "issuer_url": "https://dev-kt-aa9ne.us.auth0.com";,
+            "private_key": "{path}",
+            "audience": "https://dev-kt-aa9ne.us.auth0.com/api/v2/";
+        }}''')
+        client = Client(self.service_url, authentication=auth)
+        producer = client.create_producer('oauth2-test-base64')
+        producer.close()
+        client.close()
+
+    def test_base64(self):
+        credentials = '''{
+            "client_id":"Xd23RHsUnvUlP7wchjNYOaIfazgeHd9x",
+            
"client_secret":"rT7ps7WY8uhdVuBTKWZkttwLdQotmdEliaM5rLfmgNibvqziZ-g07ZH52N_poGAb"
+        }'''
+        base64_credentials = base64.b64encode(credentials.encode()).decode()
+        auth = AuthenticationOauth2(f'''{{
+            "issuer_url": "https://dev-kt-aa9ne.us.auth0.com";,
+            "private_key": "data:application/json;base64,{base64_credentials}",
+            "audience": "https://dev-kt-aa9ne.us.auth0.com/api/v2/";
+        }}''')
+        client = Client(self.service_url, authentication=auth)
+        producer = client.create_producer('oauth2-test-base64')
+        producer.close()
+        client.close()
+
+    def test_wrong_secret(self):
+        credentials = '''{
+            "client_id": "my-id",
+            "client_secret":"my-secret"
+        }'''
+        base64_credentials = base64.b64encode(credentials.encode()).decode()
+        auth = AuthenticationOauth2(f'''{{
+            "issuer_url": "https://dev-kt-aa9ne.us.auth0.com";,
+            "private_key": "data:application/json;base64,{base64_credentials}",
+            "audience": "https://dev-kt-aa9ne.us.auth0.com/api/v2/";
+        }}''')
+        client = Client(self.service_url, authentication=auth)
+        with self.assertRaises(AuthenticationError):
+            client.create_producer('oauth2-test-base64')
+        client.close()
+
+if __name__ == '__main__':
+    main()

Reply via email to