Skip to content

Commit

Permalink
add get user tenants
Browse files Browse the repository at this point in the history
  • Loading branch information
omer9564 committed Oct 15, 2024
1 parent 43f299b commit 7e04f77
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 36 deletions.
45 changes: 33 additions & 12 deletions horizon/enforcer/api.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import asyncio
import json
import re
from typing import cast, Optional, Union, Dict, List
from typing import cast, Optional, Union, Dict, List, Callable

import aiohttp
from fastapi import APIRouter, Depends, Header
Expand Down Expand Up @@ -276,32 +276,46 @@ async def conditional_is_allowed(
*,
policy_package: str = MAIN_POLICY_PACKAGE,
external_data_manager_path: str = "/check",
external_data_manager_method: str = "POST",
external_data_manager_params: dict | None = None,
legacy_parse_func: Callable[[dict | list], dict] | None = None
) -> dict:
if sidecar_config.ENABLE_EXTERNAL_DATA_MANAGER:
response = await _is_allowed_data_manager(query, request, path=external_data_manager_path)
response = await _is_allowed_data_manager(
query if external_data_manager_method != "GET" else None,
request,
path=external_data_manager_path,
method=external_data_manager_method,
params=external_data_manager_params,
)
raw_result = json.loads(response.body)
log_query_result(query, response, is_inner=True)
else:
response = await _is_allowed(query, request, policy_package)
raw_result = json.loads(response.body).get("result", {})
log_query_result(query, response)
if legacy_parse_func:
raw_result = legacy_parse_func(raw_result)
return raw_result


async def _is_allowed_data_manager(
query: BaseSchema, request: Request, *, path: str = "/check"
query: BaseSchema | None, request: Request, *, path: str = "/check", method: str = "POST",
params: dict | None = None
):
headers = transform_headers(request)
url = f"{sidecar_config.DATA_MANAGER_SERVICE_URL}/v1/authz{path}"
payload = {"input": query.dict()}
payload = None if query is None else {"input": query.dict()}
exc = None
_set_use_debugger(payload)
try:
logger.info(f"calling Data Manager at '{url}' with input: {payload}")
async with aiohttp.ClientSession() as session:
async with session.post(
async with session.request(
method,
url,
data=json.dumps(payload["input"]) if payload is not None else None,
params=params,
headers=headers,
timeout=sidecar_config.OPA_CLIENT_QUERY_TIMEOUT,
raise_for_status=True,
Expand Down Expand Up @@ -490,19 +504,26 @@ async def user_tenants(
query: UserTenantsQuery,
x_permit_sdk_language: Optional[str] = Depends(notify_seen_sdk),
):
response = await _is_allowed(query, request, USER_TENANTS_POLICY_PACKAGE)
log_query_result(query, response)
try:
raw_result = json.loads(response.body).get("result", {})
def parse_func(result: dict | list) -> dict | list:
if isinstance(raw_result, dict):
tenants = raw_result.get("tenants", {})
tenants = result.get("tenants", [])
elif isinstance(raw_result, list):
tenants = raw_result
tenants = result
else:
raise TypeError(
f"Expected raw result to be dict or list, got {type(raw_result)}"
)
result = parse_obj_as(UserTenantsResult, tenants)
return tenants
raw_result = await conditional_is_allowed(
query,
request,
policy_package=USER_TENANTS_POLICY_PACKAGE,
external_data_manager_path=f"/users/{query.user.key}/tenants",
external_data_manager_method="GET",
legacy_parse_func=parse_func,
)
try:
result = parse_obj_as(UserTenantsResult, raw_result)
except:
result = parse_obj_as(UserTenantsResult, [])
logger.warning(
Expand Down
86 changes: 62 additions & 24 deletions horizon/tests/test_enforcer_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,35 @@ async def pdp_api_client() -> TestClient:
{"allow": [{"allow": True, "result": True}]},
{"allow": [{"allow": True, "result": True}]},
),
(
"/user-tenants",
"/users/user1/tenants",
UserTenantsQuery(
user=User(key="user1"),
),
None,
[
{
"key": "default-2",
"attributes": {}
},
{
"key": "default",
"attributes": {}
}
],
[
{
"key": "default-2",
"attributes": {}
},
{
"key": "default",
"attributes": {}
}
],
),

]


Expand Down Expand Up @@ -455,33 +484,39 @@ def post_endpoint():
f"{sidecar_config.DATA_MANAGER_SERVICE_URL}/v1/authz{datasync_endpoint}"
)

method = "POST"

match endpoint:
case "/allowed_url":
# allowed_url gonna first call the mapping rules endpoint then the normal OPA allow endpoint
m.post(
url=f"{opal_client_config.POLICY_STORE_URL}/v1/data/mapping_rules",
status=200,
payload={
"result": {
"all": [
{
"url": "https://some.url/important_resource",
"http_method": "delete",
"action": "delete",
"resource": "resource1",
}
]
}
},
repeat=True,
)
case "/user-tenants":
method = "GET"

# Test valid response from OPA
m.post(
m.add(
datasync_url,
method=method,
status=200,
payload=datasync_response,
)

if endpoint == "/allowed_url":
# allowed_url gonna first call the mapping rules endpoint then the normal OPA allow endpoint
m.post(
url=f"{opal_client_config.POLICY_STORE_URL}/v1/data/mapping_rules",
status=200,
payload={
"result": {
"all": [
{
"url": "https://some.url/important_resource",
"http_method": "delete",
"action": "delete",
"resource": "resource1",
}
]
}
},
repeat=True,
)

response = post_endpoint()
assert response.status_code == 200
print(response.json())
Expand All @@ -499,8 +534,9 @@ def post_endpoint():

# Test bad status from OPA
bad_status = random.choice([401, 404, 400, 500, 503])
m.post(
m.add(
datasync_url,
method=method,
status=bad_status,
payload=datasync_response,
)
Expand All @@ -510,8 +546,9 @@ def post_endpoint():
assert f"status: {bad_status}" in response.text

# Test connection error
m.post(
m.add(
datasync_url,
method=method,
exception=aiohttp.ClientConnectionError("don't want to connect"),
)
response = post_endpoint()
Expand All @@ -520,8 +557,9 @@ def post_endpoint():
assert "don't want to connect" in response.text

# Test timeout - not working yet
m.post(
m.add(
datasync_url,
method=method,
exception=asyncio.exceptions.TimeoutError(),
)
response = post_endpoint()
Expand Down

0 comments on commit 7e04f77

Please sign in to comment.