Skip to content

Commit

Permalink
Merge pull request #392 from TeskaLabs/feature/tenant-authorization-e…
Browse files Browse the repository at this point in the history
…rror-responses

Custom response codes for tenant-related authorization errors
  • Loading branch information
byewokko authored Jun 12, 2024
2 parents 6112998 + 93dc419 commit f2a3435
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 10 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## v24.20

### Pre-releases
- `v24.20-alpha10`
- `v24.20-alpha9`
- `v24.20-alpha8`
- `v24.20-alpha7`
Expand All @@ -23,6 +24,7 @@
- Properly handle Argon2 verification error in login call (#378, `v24.20-alpha3`)

### Features
- Custom response codes for tenant-related authorization errors (#392, `v24.20-alpha10`)
- Implement OAuth refresh tokens (#358, `v24.20-alpha2`)
- Configurable password criteria (#372, `v24.20-alpha1`)

Expand Down
19 changes: 15 additions & 4 deletions seacatauth/openidconnect/handler/authorize.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,12 +454,17 @@ async def authorization_code_flow(
has_access_to_all_tenants=self.OpenIdConnectService.RBACService.can_access_all_tenants(
root_session.Authorization.Authz)
)
except exceptions.NoTenantsError:
raise OAuthAuthorizeError(
AuthErrorResponseCode.NoTenants, client_id,
redirect_uri=redirect_uri,
state=state,
)
except exceptions.AccessDeniedError:
raise OAuthAuthorizeError(
AuthErrorResponseCode.AccessDenied, client_id,
AuthErrorResponseCode.TenantAccessDenied, client_id,
redirect_uri=redirect_uri,
state=state,
struct_data={"reason": "tenant_not_found"}
)

if auth_token_type == "openid":
Expand Down Expand Up @@ -516,12 +521,18 @@ async def authorization_code_flow(
requested_scope, anonymous_cid,
has_access_to_all_tenants=self.OpenIdConnectService.RBACService.can_access_all_tenants(authz)
)
except exceptions.NoTenantsError:
raise OAuthAuthorizeError(
AuthErrorResponseCode.NoTenants, client_id,
redirect_uri=redirect_uri,
state=state,
)
except exceptions.AccessDeniedError:
raise OAuthAuthorizeError(
AuthErrorResponseCode.AccessDenied, client_id,
AuthErrorResponseCode.TenantAccessDenied, client_id,
redirect_uri=redirect_uri,
state=state,
struct_data={"reason": "tenant_not_found"})
)

if auth_token_type == "openid":
new_session = await self.OpenIdConnectService.create_anonymous_oidc_session(
Expand Down
9 changes: 3 additions & 6 deletions seacatauth/openidconnect/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -427,21 +427,18 @@ async def get_accessible_tenant_from_scope(
scope: typing.Iterable,
credentials_id: str,
has_access_to_all_tenants: bool = False
):
) -> typing.Optional[str]:
"""
Extract tenants from requested scope and return the first accessible one.
"""
try:
tenants: set = await self.TenantService.get_tenants_by_scope(
scope, credentials_id, has_access_to_all_tenants)
except exceptions.TenantNotFoundError as e:
L.error("Tenant not found", struct_data={"tenant": e.Tenant})
L.error("Tenant not found.", struct_data={"tenant": e.Tenant})
raise exceptions.AccessDeniedError(subject=credentials_id)
except exceptions.TenantAccessDeniedError as e:
L.error("Tenant access denied", struct_data={"tenant": e.Tenant, "cid": credentials_id})
raise exceptions.AccessDeniedError(subject=credentials_id)
except exceptions.NoTenantsError:
L.error("Tenant access denied", struct_data={"cid": credentials_id})
L.log(asab.LOG_NOTICE, "Tenant access denied.", struct_data={"tenant": e.Tenant, "cid": credentials_id})
raise exceptions.AccessDeniedError(subject=credentials_id)

if tenants:
Expand Down
4 changes: 4 additions & 0 deletions seacatauth/openidconnect/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ class AuthErrorResponseCode:
RequestUriNotSupported = "request_uri_not_supported"
RegistrationNotSupported = "registration_not_supported"

# Custom response codes
TenantAccessDenied = "tenant_access_denied"
NoTenants = "no_tenants"


class TokenRequestErrorResponseCode:
# OAuth2.0 token request error response codes defined in RFC6749
Expand Down
2 changes: 2 additions & 0 deletions seacatauth/tenant/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,8 @@ async def get_tenants_by_scope(self, scope: list, credential_id: str, has_access
elif has_access_to_all_tenants:
await self.get_tenant(tenant)
tenants.add(tenant)
elif not user_tenants:
raise exceptions.NoTenantsError(credential_id)
else:
raise exceptions.TenantAccessDeniedError(tenant, credential_id)

Expand Down

0 comments on commit f2a3435

Please sign in to comment.