Skip to content

Commit 7f07af2

Browse files
Merge pull request #8 from bitovi/namespace-permissions
authorizing users based on namespace permissions when they are not a global admin
2 parents 610fa12 + a123dc9 commit 7f07af2

2 files changed

Lines changed: 19 additions & 14 deletions

File tree

encryption_jwt/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ poetry install --with encryption,bedrock
2525
### Key management
2626

2727
This example uses the [AWS Key Management Service](https://aws.amazon.com/kms/) (KMS). You will need
28-
to create a "Customer managed key" then provide the ARN ID as the value of the `AWS_KMS_CMK_ARN`
29-
environment variable. Alternately replace the key management portion with your own implementation.
28+
to create a "Customer managed key" with its Alias set to your Temporal Namespace (replace `.`s with `_`s).
29+
Alternately replace the key management portion with your own implementation.
3030

3131
### Self-signed certificates
3232

encryption_jwt/codec_server.py

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@
1010
from google.protobuf import json_format
1111
from encryption_jwt.codec import EncryptionCodec
1212

13-
DECRYPT_ROLES = ["admin"]
13+
AUTHORIZED_ACCOUNT_ACCESS_ROLES = ["admin"]
14+
AUTHORIZED_NAMESPACE_ACCESS_ROLES = ["read", "write", "admin"]
1415

1516
temporal_ops_address = "saas-api.tmprl.cloud:443"
1617
if os.environ.get("TEMPORAL_OPS_ADDRESS"):
17-
os.environ.get("TEMPORAL_OPS_ADDRESS")
18+
temporal_ops_address = os.environ.get("TEMPORAL_OPS_ADDRESS")
1819

1920

2021
def build_codec_server() -> web.Application:
@@ -41,7 +42,7 @@ async def cors_options(req: web.Request) -> web.Response:
4142

4243
return resp
4344

44-
def request_user_role(email: str) -> str:
45+
def decryption_authorized(email: str, namespace: str) -> bool:
4546
credentials = grpc.composite_channel_credentials(grpc.ssl_channel_credentials(
4647
), grpc.access_token_call_credentials(os.environ.get("TEMPORAL_API_KEY")))
4748

@@ -52,11 +53,17 @@ def request_user_role(email: str) -> str:
5253
response = client.GetUsers(request, metadata=(
5354
("temporal-cloud-api-version", os.environ.get("TEMPORAL_OPS_API_VERSION")),))
5455

56+
authorized = False
5557
for user in response.users:
56-
if user.spec.email == email:
57-
return user.spec.access.account_access.role
58+
if user.spec.email.lower() == email.lower():
59+
if user.spec.access.account_access in AUTHORIZED_ACCOUNT_ACCESS_ROLES:
60+
authorized = True
61+
else:
62+
if namespace in user.spec.access.namespace_accesses:
63+
if user.spec.access.namespace_accesses[namespace].permission in AUTHORIZED_NAMESPACE_ACCESS_ROLES:
64+
authorized = True
5865

59-
return ""
66+
return authorized
6067

6168
def make_handler(fn: str):
6269
async def handler(req: web.Request):
@@ -71,11 +78,10 @@ async def handler(req: web.Request):
7178
decoded = jwt.decode(encoded, options={"verify_signature": False})
7279

7380
# Use the email to determine if the payload should be decrypted.
74-
role = request_user_role(
75-
decoded["https://saas-api.tmprl.cloud/user/email"])
76-
if role.lower() in DECRYPT_ROLES:
77-
codec = EncryptionCodec(namespace)
78-
payloads = Payloads(payloads=await getattr(codec, fn)(payloads.payloads))
81+
authorized = decryption_authorized(decoded["https://saas-api.tmprl.cloud/user/email"], namespace)
82+
if authorized:
83+
encryptionCodec = EncryptionCodec(namespace)
84+
payloads = Payloads(payloads=await getattr(encryptionCodec, fn)(payloads.payloads))
7985

8086
# Apply CORS and return JSON
8187
resp = await cors_options(req)
@@ -85,7 +91,6 @@ async def handler(req: web.Request):
8591
return handler
8692

8793
# Build app
88-
# codec = EncryptionCodec(namespace)
8994
app = web.Application()
9095
# set up logger
9196
logging.basicConfig(level=logging.DEBUG)

0 commit comments

Comments
 (0)