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

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


The following commit(s) were added to refs/heads/main by this push:
     new 9797360  Rest Catalog Support for a Separate OAuth Server URI (#233)
9797360 is described below

commit 979736045f440c91020990106572ef9fc25c0f9f
Author: Sung Yun <[email protected]>
AuthorDate: Tue Jan 16 07:30:24 2024 -0500

    Rest Catalog Support for a Separate OAuth Server URI (#233)
    
    * support separate auth url
    
    * Remove debug line
    
    ---------
    
    Co-authored-by: Fokko Driesprong <[email protected]>
---
 mkdocs/docs/configuration.md | 17 +++++++++--------
 pyiceberg/catalog/rest.py    | 11 +++++++++--
 tests/catalog/test_rest.py   | 25 ++++++++++++++++++++++++-
 3 files changed, 42 insertions(+), 11 deletions(-)

diff --git a/mkdocs/docs/configuration.md b/mkdocs/docs/configuration.md
index 801bb8f..12bb351 100644
--- a/mkdocs/docs/configuration.md
+++ b/mkdocs/docs/configuration.md
@@ -130,14 +130,15 @@ catalog:
       cabundle: /absolute/path/to/cabundle.pem
 ```
 
-| Key                 | Example                 | Description                  
                                              |
-| ------------------- | ----------------------- | 
-------------------------------------------------------------------------- |
-| uri                 | https://rest-catalog/ws | URI identifying the REST 
Server                                            |
-| credential          | t-1234:secret           | Credential to use for OAuth2 
credential flow when initializing the catalog |
-| token               | FEW23.DFSDF.FSDF        | Bearer token value to use 
for `Authorization` header                       |
-| rest.sigv4-enabled  | true                    | Sign requests to the REST 
Server using AWS SigV4 protocol                  |
-| rest.signing-region | us-east-1               | The region to use when SigV4 
signing a request                             |
-| rest.signing-name   | execute-api             | The service signing name to 
use when SigV4 signing a request               |
+| Key                    | Example                 | Description               
                                                                         |
+| ---------------------- | ----------------------- | 
--------------------------------------------------------------------------------------------------
 |
+| uri                    | https://rest-catalog/ws | URI identifying the REST 
Server                                                                    |
+| credential             | t-1234:secret           | Credential to use for 
OAuth2 credential flow when initializing the catalog                         |
+| token                  | FEW23.DFSDF.FSDF        | Bearer token value to use 
for `Authorization` header                                               |
+| rest.sigv4-enabled     | true                    | Sign requests to the REST 
Server using AWS SigV4 protocol                                          |
+| rest.signing-region    | us-east-1               | The region to use when 
SigV4 signing a request                                                     |
+| rest.signing-name      | execute-api             | The service signing name 
to use when SigV4 signing a request                                       |
+| rest.authorization-url | https://auth-service/cc | Authentication URL to use 
for client credentials authentication (default: uri + 'v1/oauth/tokens') |
 
 ## SQL Catalog
 
diff --git a/pyiceberg/catalog/rest.py b/pyiceberg/catalog/rest.py
index 3dbb5b7..de192a9 100644
--- a/pyiceberg/catalog/rest.py
+++ b/pyiceberg/catalog/rest.py
@@ -109,6 +109,7 @@ SSL = "ssl"
 SIGV4 = "rest.sigv4-enabled"
 SIGV4_REGION = "rest.signing-region"
 SIGV4_SERVICE = "rest.signing-name"
+AUTH_URL = "rest.authorization-url"
 
 NAMESPACE_SEPARATOR = b"\x1F".decode(UTF8)
 
@@ -265,15 +266,21 @@ class RestCatalog(Catalog):
 
         return url + endpoint.format(**kwargs)
 
+    @property
+    def auth_url(self) -> str:
+        if url := self.properties.get(AUTH_URL):
+            return url
+        else:
+            return self.url(Endpoints.get_token, prefixed=False)
+
     def _fetch_access_token(self, session: Session, credential: str) -> str:
         if SEMICOLON in credential:
             client_id, client_secret = credential.split(SEMICOLON)
         else:
             client_id, client_secret = None, credential
         data = {GRANT_TYPE: CLIENT_CREDENTIALS, CLIENT_ID: client_id, 
CLIENT_SECRET: client_secret, SCOPE: CATALOG_SCOPE}
-        url = self.url(Endpoints.get_token, prefixed=False)
         # Uses application/x-www-form-urlencoded by default
-        response = session.post(url=url, data=data)
+        response = session.post(url=self.auth_url, data=data)
         try:
             response.raise_for_status()
         except HTTPError as exc:
diff --git a/tests/catalog/test_rest.py b/tests/catalog/test_rest.py
index 79cf25f..248cc14 100644
--- a/tests/catalog/test_rest.py
+++ b/tests/catalog/test_rest.py
@@ -24,7 +24,7 @@ from requests_mock import Mocker
 
 import pyiceberg
 from pyiceberg.catalog import PropertiesUpdateSummary, Table, load_catalog
-from pyiceberg.catalog.rest import RestCatalog
+from pyiceberg.catalog.rest import AUTH_URL, RestCatalog
 from pyiceberg.exceptions import (
     NamespaceAlreadyExistsError,
     NoSuchNamespaceError,
@@ -43,6 +43,7 @@ from pyiceberg.utils.config import Config
 
 TEST_URI = "https://iceberg-test-catalog/";
 TEST_CREDENTIALS = "client:secret"
+TEST_AUTH_URL = "https://auth-endpoint/";
 TEST_TOKEN = "some_jwt_token"
 TEST_HEADERS = {
     "Content-type": "application/json",
@@ -116,6 +117,28 @@ def test_token_200(rest_mock: Mocker) -> None:
     )
 
 
+def test_token_200_w_auth_url(rest_mock: Mocker) -> None:
+    rest_mock.post(
+        TEST_AUTH_URL,
+        json={
+            "access_token": TEST_TOKEN,
+            "token_type": "Bearer",
+            "expires_in": 86400,
+            "issued_token_type": 
"urn:ietf:params:oauth:token-type:access_token",
+        },
+        status_code=200,
+        request_headers=OAUTH_TEST_HEADERS,
+    )
+    # pylint: disable=W0212
+    assert (
+        RestCatalog("rest", uri=TEST_URI, credential=TEST_CREDENTIALS, 
**{AUTH_URL: TEST_AUTH_URL})._session.headers[
+            "Authorization"
+        ]
+        == f"Bearer {TEST_TOKEN}"
+    )
+    # pylint: enable=W0212
+
+
 def test_config_200(requests_mock: Mocker) -> None:
     requests_mock.get(
         f"{TEST_URI}v1/config",

Reply via email to