Skip to content

Commit

Permalink
Merge pull request #4 from getdozer/feat-Authorization
Browse files Browse the repository at this point in the history
feat: Authorization
  • Loading branch information
mediuminvader committed Apr 20, 2023
2 parents ae8ed8f + 1dd3209 commit bf654e1
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 10 deletions.
16 changes: 16 additions & 0 deletions example/authorization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from pydozer.auth import AuthClient
from pydozer.api import ApiClient

master_token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJjYWNoZV91c2VyIiwic3ViIjoiYXBpQGRvemVyLmNvbSIsImV4cCI6MTY4MTI4NzcwNDAyNywiYWNjZXNzIjoiQWxsIn0.aD5L6XURIr3hrUp0LzfUQWKHairjK6DDkMlzvnVvzHA'

client = AuthClient(token=master_token, url='0.0.0.0:50051')

restricted_token = client.get_auth_token()

print(f"Token: {restricted_token}")

api = ApiClient("pickup", url='0.0.0.0:50051', token=restricted_token)

count = api.count()

print(f"Count: {count}")
17 changes: 11 additions & 6 deletions pydozer/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ class ApiClient:
url (str, optional): Dozer gRPC URL. Defaults to Env variable DOZER_API_URL or `0.0.0.0:50051`.
secure (bool, optional): Intialize a secure channel. Defaults to False.
"""
def __init__(self, endpoint, url=DOZER_API_URL, secure=False):
def __init__(self, endpoint, url=DOZER_API_URL, secure=False, token=None):

self.metadata = [('authorization', f'Bearer {token}')] if token else None

if secure:
channel = grpc.secure_channel(url)
else:
Expand Down Expand Up @@ -48,7 +51,7 @@ def health(self, service: str = None) -> HealthCheckResponse:
"""

health_client = HealthGrpcServiceStub(self.channel)
return health_client.healthCheck(HealthCheckRequest(service=service))
return health_client.healthCheck(HealthCheckRequest(service=service), metadata=self.metadata)

def count(self, query: QueryRequest = {}) -> CountResponse:
"""Counts the number of records in Dozer cache.
Expand All @@ -69,8 +72,7 @@ def count(self, query: QueryRequest = {}) -> CountResponse:
"""

req = self.get_query_request(query)

return self.client.count(req)
return self.client.count(req, metadata=self.metadata)

def query(self, query: dict = {}) -> QueryResponse:
"""Queries the Dozer cache for records. Response is in the common format.
Expand All @@ -93,7 +95,8 @@ def query(self, query: dict = {}) -> QueryResponse:
"""

req = self.get_query_request(query)
return self.client.query(req)

return self.client.query(req, metadata=self.metadata)

def on_event(self, request={}):
"""Subscribes to events from Dozer.
Expand All @@ -104,7 +107,8 @@ def on_event(self, request={}):
_req = OnEventRequest(endpoint=self.endpoint)
for key, value in request.items():
setattr(_req, key, value)
return self.client.OnEvent(_req)

return self.client.OnEvent(_req, metadata=self.metadata)

def get_query_request(self, query: dict = {}) -> QueryRequest:
"""Returns a QueryRequest object
Expand All @@ -121,6 +125,7 @@ def get_query_request(self, query: dict = {}) -> QueryRequest:
Returns:
QueryRequest: QueryRequest object
"""

if query is None or len(query) == 0:
query = {}

Expand Down
71 changes: 71 additions & 0 deletions pydozer/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import json
import os
import grpc
from pydozer.helper import describe_services
from pydozer.auth_pb2_grpc import AuthGrpcServiceStub
import pydozer.auth_pb2 as auth__pb2


DOZER_API_URL = os.getenv("DOZER_API_URL", "0.0.0.0:50051")


class AuthClient:
"""Common Client for Dozer Authorization Service
Args:
token: A valid token to generate restricted tokens
url (str, optional): Dozer gRPC URL. Defaults to Env variable DOZER_API_URL or `0.0.0.0:50051`.
"""
def __init__(self, token, url=DOZER_API_URL, secure=False):

self.metadata = [('authorization', f'Bearer {token}')]

if secure:
channel = grpc.secure_channel(url)
else:
channel = grpc.insecure_channel(url)

self.channel = channel

self.client = AuthGrpcServiceStub(channel)

def describe(self) -> dict:
"""Describe the available gRPC services and methods
Returns:
dict: dictionary of available services and methods
"""

return describe_services(self.channel)

def get_auth_token(self, query: dict = None) -> auth__pb2.GetAuthTokenResponse:
"""Get a token for restricted access. Response is in the common format.
Args:
query (dict, optional): Accepts a filter
to query only a subset of records.
Keys could be
`$filter`: `dict` eg: `{"name": "John"}` or `{"id": { "$gt": 1}}`
`$limit`: `int`
`$skip`: `int`,
'$after`: `int`, cursor to start from. `$skip` and `$after` cannot be used in the same query
`$order_by`: `dict` eg: `{"name": "asc"}` or `{"id": "desc"}`
Defaults to {}.
Returns:
GetAuthTokenResponse: {"token": token}
token: A token with restricted access
"""

if query is None or len(query) == 0:
query_str = '"All"'
else:
data = {}
for key, value in query.items():
data[key] = value
query_str = json.dumps(data)

req = auth__pb2.GetAuthTokenRequest(access_filter=query_str)
response = self.client.getAuthToken(req, metadata=self.metadata)
return response.token

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[tool.poetry]
name = "pydozer"
version = "0.1.16"
version = "0.1.18"
description = "Python wrapper for the Dozer API"
authors = ["Dozer Team <api@getdozer.io>"]
license = "MIT"
license = "Apache 2.0"
readme = "README.md"

[tool.poetry.dependencies]
Expand Down
7 changes: 7 additions & 0 deletions tests/dozer-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,20 @@ connections:
cache_max_map_size: 1073741824
app_max_map_size: 1073741824


flags:
grpc_web: true

api:
rest:
port: 8080
grpc:
port: 10003
app_grpc:
port: 10004
api_security: !Jwt
DOZER1337

sources:
- name: trips
table_name: trips
Expand Down
10 changes: 9 additions & 1 deletion tests/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@

from time import sleep

from pydozer.auth import AuthClient
from pydozer.api import ApiClient
from pydozer.ingest import IngestClient

import pytest


Expand Down Expand Up @@ -32,7 +34,13 @@ def dozer_server():

@pytest.fixture
def api_client() -> ApiClient:
return ApiClient("users", url=DOZER_API_URL)
master_token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJjYWNoZV91c2VyIiwic3ViIjoiYXBpQGRvemVyLmNvbSIsImV4cCI6MTY4MTI4NzcwNDAyNywiYWNjZXNzIjoiQWxsIn0.aD5L6XURIr3hrUp0LzfUQWKHairjK6DDkMlzvnVvzHA'

client = AuthClient(token=master_token, url=DOZER_API_URL)

restricted_token = client.get_auth_token()

return ApiClient("users", url=DOZER_API_URL, token=restricted_token)


@pytest.fixture
Expand Down
3 changes: 2 additions & 1 deletion tests/test_dozer.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,5 @@ def test_ingest_query(ingestion_client: IngestClient, api_client: ApiClient):

res = api_client.query({'$limit': 1})
assert res is not None
assert len(res.records) >= 1
assert len(res.records) >= 1

0 comments on commit bf654e1

Please sign in to comment.