Skip to content

Commit 8774841

Browse files
Add remote auth start (terminusdb#392)
* Add remote auth start * Fix linting * Use remote_auth dict for Authorization * Fix set_db * Fix incorrect authentication when using tokens * Don't check db_connection on clone and fix ref * Repeating load of object with key causes failure. (terminusdb#389) * Fix repeated key change behaviour * Defeat the linter * Upgrade actions to newer versions (terminusdb#390) They use an older Node version which gives a lot of deprecation warnings in the CI. * Fix typo (terminusdb#391) Fixes terminusdb#365 * Remove eval (terminusdb#381) * Remove eval * Remove trailing # * Add new release for 10.2.2 (terminusdb#393) * Fix syntax of requirement * Fix ref --------- Co-authored-by: Robin de Rooij <[email protected]> Co-authored-by: Robin de Rooij <[email protected]>
1 parent a519d4c commit 8774841

File tree

2 files changed

+52
-18
lines changed

2 files changed

+52
-18
lines changed

terminusdb_client/client/Client.py

+51-17
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Client.py
22
Client is the Python public API for TerminusDB"""
3+
import base64
34
import copy
45
import gzip
56
import json
@@ -269,19 +270,16 @@ def ref(self):
269270
return self._ref
270271

271272
@ref.setter
272-
def ref(self, value):
273-
if isinstance(value, str):
273+
def ref(self, value: Optional[str]):
274+
if value is not None:
274275
value = value.lower()
275-
if value in ["local", "remote", None]:
276-
self._ref = value
277-
else:
278-
raise ValueError("ref can only be 'local' or 'remote'")
276+
self._ref = value
279277

280278
def connect(
281279
self,
282280
team: str = "admin",
283281
db: Optional[str] = None,
284-
remote_auth: str = None,
282+
remote_auth: Optional[dict] = None,
285283
use_token: bool = False,
286284
jwt_token: Optional[str] = None,
287285
api_token: Optional[str] = None,
@@ -302,7 +300,7 @@ def connect(
302300
Name of the team, default to be "admin"
303301
db: optional, str
304302
Name of the database connected
305-
remote_auth: optional, str
303+
remote_auth: optional, dict
306304
Remote Auth setting
307305
key: optional, str
308306
API key for connecting, default to be "root"
@@ -331,10 +329,13 @@ def connect(
331329

332330
self.team = team
333331
self.db = db
334-
self._remote_auth = remote_auth
332+
self._remote_auth_dict = remote_auth
335333
self._key = key
336334
self.user = user
337-
self._use_token = use_token
335+
if api_token:
336+
self._use_token = True
337+
else:
338+
self._use_token = use_token
338339
self._jwt_token = jwt_token
339340
self._api_token = api_token
340341
self.branch = branch
@@ -623,7 +624,7 @@ def set_db(self, dbid: str, team: Optional[str] = None) -> str:
623624
return self.connect(
624625
team=team,
625626
db=dbid,
626-
remote_auth=self._remote_auth,
627+
remote_auth=self._remote_auth_dict,
627628
key=self._key,
628629
user=self.user,
629630
branch=self.branch,
@@ -1674,7 +1675,9 @@ def pull(
16741675

16751676
return json.loads(_finish_response(result))
16761677

1677-
def fetch(self, remote_id: str) -> dict:
1678+
def fetch(self, remote_id: str,
1679+
remote_auth: Optional[dict] = None,
1680+
) -> dict:
16781681
"""Fatch the brach from a remote
16791682
16801683
Parameters
@@ -1702,6 +1705,7 @@ def push(
17021705
remote_branch: Optional[str] = None,
17031706
message: Optional[str] = None,
17041707
author: Optional[str] = None,
1708+
remote_auth: Optional[dict] = None,
17051709
) -> dict:
17061710
"""Push changes from a branch to a remote repo
17071711
@@ -1715,6 +1719,8 @@ def push(
17151719
optional commit message
17161720
author: str, optional
17171721
option to overide the author of the operation
1722+
remote_auth: dict, optional
1723+
optional remote authorization (uses client remote auth otherwise)
17181724
17191725
Raises
17201726
------
@@ -1744,10 +1750,13 @@ def push(
17441750
"author": author,
17451751
"message": message,
17461752
}
1753+
if self._remote_auth_dict or remote_auth:
1754+
headers = {'Authorization-Remote' : self._generate_remote_header(remote_auth) if remote_auth else self._remote_auth()}
1755+
headers.update(self._default_headers)
17471756

17481757
result = self._session.post(
17491758
self._push_url(),
1750-
headers=self._default_headers,
1759+
headers=headers,
17511760
json=rc_args,
17521761
auth=self._auth(),
17531762
)
@@ -2232,7 +2241,8 @@ def patch_resource(
22322241
return json.loads(result)
22332242

22342243
def clonedb(
2235-
self, clone_source: str, newid: str, description: Optional[str] = None
2244+
self, clone_source: str, newid: str, description: Optional[str] = None,
2245+
remote_auth: Optional[dict] = None
22362246
) -> None:
22372247
"""Clone a remote repository and create a local copy.
22382248
@@ -2244,6 +2254,8 @@ def clonedb(
22442254
Identifier of the new repository to create.
22452255
Description : str, optional
22462256
Optional description about the cloned database.
2257+
remote_auth : str, optional
2258+
Optional remote authorization (uses client remote auth otherwise)
22472259
22482260
Raises
22492261
------
@@ -2255,15 +2267,19 @@ def clonedb(
22552267
>>> client = Client("http://127.0.0.1:6363/")
22562268
>>> client.clonedb("http://terminusdb.com/some_user/test_db", "my_test_db")
22572269
"""
2258-
self._check_connection()
2270+
self._check_connection(check_db=False)
22592271
if description is None:
22602272
description = f"New database {newid}"
2273+
2274+
if self._remote_auth_dict or remote_auth:
2275+
headers = {'Authorization-Remote' : self._generate_remote_header(remote_auth) if remote_auth else self._remote_auth()}
2276+
headers.update(self._default_headers)
22612277
rc_args = {"remote_url": clone_source, "label": newid, "comment": description}
22622278

22632279
_finish_response(
22642280
self._session.post(
22652281
self._clone_url(newid),
2266-
headers=self._default_headers,
2282+
headers=headers,
22672283
json=rc_args,
22682284
auth=self._auth(),
22692285
)
@@ -2312,7 +2328,25 @@ def _auth(self):
23122328
return APITokenAuth(os.environ["TERMINUSDB_ACCESS_TOKEN"])
23132329
else:
23142330
raise RuntimeError("Client not connected.")
2315-
# TODO: remote_auth
2331+
2332+
def _remote_auth(self):
2333+
if self._remote_auth_dict:
2334+
return self._generate_remote_header(self._remote_auth_dict)
2335+
elif "TERMINUSDB_REMOTE_ACCESS_TOKEN" in os.environ:
2336+
token = os.environ["TERMINUSDB_REMOTE_ACCESS_TOKEN"]
2337+
return f"Token {token}"
2338+
2339+
def _generate_remote_header(self, remote_auth: dict):
2340+
key_type = remote_auth['type']
2341+
key = remote_auth['key']
2342+
if key_type == 'http_basic':
2343+
username = remote_auth['username']
2344+
http_basic_creds = base64.b64encode(f"{username}:{key}".encode('utf-8'))
2345+
return f"Basic {http_basic_creds}"
2346+
elif key_type == 'token':
2347+
return f"Token {key}"
2348+
# JWT is the only key type remaining
2349+
return f"Bearer {key}"
23162350

23172351
def create_organization(self, org: str) -> Optional[dict]:
23182352
"""

terminusdb_client/tests/test_Client.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ def test_remote_auth(mocked_requests):
303303
client.connect(
304304
user="admin", team="admin", key="root", remote_auth=auth_setting
305305
)
306-
result = client._remote_auth
306+
result = client._remote_auth_dict
307307
assert result == auth_setting
308308

309309

0 commit comments

Comments
 (0)