Skip to content

Commit 27083d1

Browse files
authored
Merge pull request #484 from meilisearch/generate_token
Add uid to the generateTenantToken method
2 parents 8015bf8 + 20d3106 commit 27083d1

File tree

2 files changed

+31
-10
lines changed

2 files changed

+31
-10
lines changed

meilisearch/client.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
import re
12
import base64
23
import hashlib
34
import hmac
45
import json
56
import datetime
67
from urllib import parse
78
from typing import Any, Dict, List, Optional, Union
9+
from xmlrpc.client import Boolean
810
from meilisearch.index import Index
911
from meilisearch.config import Config
1012
from meilisearch.task import get_task, get_tasks, wait_for_task
@@ -473,6 +475,7 @@ def wait_for_task(
473475

474476
def generate_tenant_token(
475477
self,
478+
api_key_uid: str,
476479
search_rules: Union[Dict[str, Any], List[str]],
477480
*,
478481
expires_at: Optional[datetime.datetime] = None,
@@ -482,6 +485,8 @@ def generate_tenant_token(
482485
483486
Parameters
484487
----------
488+
api_key_uid:
489+
The uid of the API key used as issuer of the token.
485490
search_rules:
486491
A Dictionary or list of string which contains the rules to be enforced at search time for all or specific
487492
accessible indexes for the signing API Key.
@@ -501,6 +506,8 @@ def generate_tenant_token(
501506
# Validate all fields
502507
if api_key == '' or api_key is None and self.config.api_key is None:
503508
raise Exception('An api key is required in the client or should be passed as an argument.')
509+
if api_key_uid == '' or api_key_uid is None or self._valid_uuid(api_key_uid) is False:
510+
raise Exception('An uid is required and must comply to the uuid4 format.')
504511
if not search_rules or search_rules == ['']:
505512
raise Exception('The search_rules field is mandatory and should be defined.')
506513
if expires_at and expires_at < datetime.datetime.utcnow():
@@ -516,7 +523,7 @@ def generate_tenant_token(
516523

517524
# Add the required fields to the payload
518525
payload = {
519-
'apiKeyPrefix': api_key[0:8],
526+
'apiKeyUid': api_key_uid,
520527
'searchRules': search_rules,
521528
'exp': int(datetime.datetime.timestamp(expires_at)) if expires_at is not None else None
522529
}
@@ -542,3 +549,11 @@ def _base64url_encode(
542549
data: bytes
543550
) -> str:
544551
return base64.urlsafe_b64encode(data).decode('utf-8').replace('=','')
552+
553+
@staticmethod
554+
def _valid_uuid(
555+
uuid: str
556+
) -> bool:
557+
uuid4hex = re.compile(r'^[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}', re.I)
558+
match = uuid4hex.match(uuid)
559+
return bool(match)

tests/client/test_client_tenant_token.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def test_generate_tenant_token_with_search_rules(get_private_key, index_with_doc
1212
index_with_documents()
1313
client = meilisearch.Client(BASE_URL, get_private_key['key'])
1414

15-
token = client.generate_tenant_token(search_rules=["*"])
15+
token = client.generate_tenant_token(api_key_uid=get_private_key['uid'], search_rules=["*"])
1616

1717
token_client = meilisearch.Client(BASE_URL, token)
1818
response = token_client.index('indexUID').search('', {
@@ -28,7 +28,7 @@ def test_generate_tenant_token_with_search_rules_on_one_index(get_private_key, e
2828
empty_index('tenant_token')
2929
client = meilisearch.Client(BASE_URL, get_private_key['key'])
3030

31-
token = client.generate_tenant_token(search_rules=['indexUID'])
31+
token = client.generate_tenant_token(api_key_uid=get_private_key['uid'], search_rules=['indexUID'])
3232

3333
token_client = meilisearch.Client(BASE_URL, token)
3434
response = token_client.index('indexUID').search('')
@@ -40,7 +40,7 @@ def test_generate_tenant_token_with_search_rules_on_one_index(get_private_key, e
4040
def test_generate_tenant_token_with_api_key(client, get_private_key, empty_index):
4141
"""Tests create a tenant token with search rules and an api key."""
4242
empty_index()
43-
token = client.generate_tenant_token(search_rules=["*"], api_key=get_private_key['key'])
43+
token = client.generate_tenant_token(api_key_uid=get_private_key['uid'], search_rules=["*"], api_key=get_private_key['key'])
4444

4545
token_client = meilisearch.Client(BASE_URL, token)
4646
response = token_client.index('indexUID').search('')
@@ -53,7 +53,7 @@ def test_generate_tenant_token_with_expires_at(client, get_private_key, empty_in
5353
client = meilisearch.Client(BASE_URL, get_private_key['key'])
5454
tomorrow = datetime.datetime.utcnow() + datetime.timedelta(days=1)
5555

56-
token = client.generate_tenant_token(search_rules=["*"], expires_at=tomorrow)
56+
token = client.generate_tenant_token(api_key_uid=get_private_key['uid'], search_rules=["*"], expires_at=tomorrow)
5757

5858
token_client = meilisearch.Client(BASE_URL, token)
5959
response = token_client.index('indexUID').search('')
@@ -65,28 +65,28 @@ def test_generate_tenant_token_with_empty_search_rules_in_list(get_private_key):
6565
client = meilisearch.Client(BASE_URL, get_private_key['key'])
6666

6767
with pytest.raises(Exception):
68-
client.generate_tenant_token(search_rules=[''])
68+
client.generate_tenant_token(api_key_uid=get_private_key['uid'], search_rules=[''])
6969

7070
def test_generate_tenant_token_without_search_rules_in_list(get_private_key):
7171
"""Tests create a tenant token without search rules."""
7272
client = meilisearch.Client(BASE_URL, get_private_key['key'])
7373

7474
with pytest.raises(Exception):
75-
client.generate_tenant_token(search_rules=[])
75+
client.generate_tenant_token(api_key_uid=get_private_key['uid'], search_rules=[])
7676

7777
def test_generate_tenant_token_without_search_rules_in_dict(get_private_key):
7878
"""Tests create a tenant token without search rules."""
7979
client = meilisearch.Client(BASE_URL, get_private_key['key'])
8080

8181
with pytest.raises(Exception):
82-
client.generate_tenant_token(search_rules={})
82+
client.generate_tenant_token(api_key_uid=get_private_key['uid'], search_rules={})
8383

8484
def test_generate_tenant_token_with_empty_search_rules_in_dict(get_private_key):
8585
"""Tests create a tenant token without search rules."""
8686
client = meilisearch.Client(BASE_URL, get_private_key['key'])
8787

8888
with pytest.raises(Exception):
89-
client.generate_tenant_token(search_rules={''})
89+
client.generate_tenant_token(api_key_uid=get_private_key['uid'], search_rules={''})
9090

9191
def test_generate_tenant_token_with_bad_expires_at(client, get_private_key):
9292
"""Tests create a tenant token with a bad expires at."""
@@ -95,7 +95,7 @@ def test_generate_tenant_token_with_bad_expires_at(client, get_private_key):
9595
yesterday = datetime.datetime.utcnow() + datetime.timedelta(days=-1)
9696

9797
with pytest.raises(Exception):
98-
client.generate_tenant_token(search_rules=["*"], expires_at=yesterday)
98+
client.generate_tenant_token(api_key_uid=get_private_key['uid'], search_rules=["*"], expires_at=yesterday)
9999

100100
def test_generate_tenant_token_with_no_api_key(client):
101101
"""Tests create a tenant token with no api key."""
@@ -104,3 +104,9 @@ def test_generate_tenant_token_with_no_api_key(client):
104104
with pytest.raises(Exception):
105105
client.generate_tenant_token(search_rules=["*"])
106106

107+
def test_generate_tenant_token_with_no_uid(client, get_private_key):
108+
"""Tests create a tenant token with no uid."""
109+
client = meilisearch.Client(BASE_URL, get_private_key['key'])
110+
111+
with pytest.raises(Exception):
112+
client.generate_tenant_token(api_key_uid=None, search_rules=["*"])

0 commit comments

Comments
 (0)