tba-app-backend-tenant-administration 0.4.0.dev2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tba_app_backend_tenant_administration-0.4.0.dev2/PKG-INFO +59 -0
- tba_app_backend_tenant_administration-0.4.0.dev2/README.md +38 -0
- tba_app_backend_tenant_administration-0.4.0.dev2/pyproject.toml +24 -0
- tba_app_backend_tenant_administration-0.4.0.dev2/src/tba_app_backend_tenant_administration/__init__.py +14 -0
- tba_app_backend_tenant_administration-0.4.0.dev2/src/tba_app_backend_tenant_administration/app.py +130 -0
- tba_app_backend_tenant_administration-0.4.0.dev2/src/tba_app_backend_tenant_administration/contract.py +73 -0
- tba_app_backend_tenant_administration-0.4.0.dev2/src/tba_app_backend_tenant_administration/py.typed +0 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tba-app-backend-tenant-administration
|
|
3
|
+
Version: 0.4.0.dev2
|
|
4
|
+
Summary: Tenant-scoped administration backend application for TBA.
|
|
5
|
+
License-Expression: Apache-2.0
|
|
6
|
+
Requires-Python: >=3.10,<3.15
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
13
|
+
Requires-Dist: tba-app-backend-core (==0.4.0.dev2)
|
|
14
|
+
Requires-Dist: tba-auth (==0.4.0.dev2)
|
|
15
|
+
Requires-Dist: tba-router-administration-gate (==0.4.0.dev2)
|
|
16
|
+
Project-URL: Homepage, https://github.com/tigrbl/tigrbl_auth
|
|
17
|
+
Project-URL: Repository, https://github.com/tigrbl/tigrbl_auth
|
|
18
|
+
Project-URL: Source, https://github.com/tigrbl/tigrbl_auth/tree/master/pkgs/90-backend-apps/tba-app-backend-tenant-administration
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# tba-app-backend-tenant-administration
|
|
22
|
+
|
|
23
|
+
Tenant-scoped identity, admin delegation, JWKS, and local policy API front door.
|
|
24
|
+
|
|
25
|
+
## Surface
|
|
26
|
+
|
|
27
|
+
| Property | Value |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
| Product surface | `tenant-admin-app` |
|
|
30
|
+
| Intended UIX | `@tba/ui-tenant-administration` |
|
|
31
|
+
| Exposes | Tenant identities, clients, consents, sessions, tenant keys/JWKS, tenant-local audit |
|
|
32
|
+
| Excludes | Platform tenant creation/deletion and cross-tenant authority assignment |
|
|
33
|
+
|
|
34
|
+
## Entrypoint
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from tba_app_backend_tenant_administration import app, build_app
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Local Dev Deployment
|
|
41
|
+
|
|
42
|
+
The Docker dev surface listens on `http://localhost:8016` and uses the
|
|
43
|
+
admin API key `dev-tenant-admin-key` unless overridden.
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
docker compose -f docker/docker-compose.tenant-admin-app.yml up -d --build
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Useful checks:
|
|
50
|
+
|
|
51
|
+
- `GET /openapi.json`
|
|
52
|
+
- `GET /openrpc.json`
|
|
53
|
+
- `POST /rpc` with `X-API-Key: dev-tenant-admin-key`
|
|
54
|
+
- `GET /user`, `/client`, `/clientregistration`, `/consent`
|
|
55
|
+
|
|
56
|
+
The tenant-admin surface intentionally does not expose `/tenant`, public
|
|
57
|
+
OAuth/OIDC routes, platform tenant lifecycle RPC, or service/workload admin
|
|
58
|
+
resources.
|
|
59
|
+
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# tba-app-backend-tenant-administration
|
|
2
|
+
|
|
3
|
+
Tenant-scoped identity, admin delegation, JWKS, and local policy API front door.
|
|
4
|
+
|
|
5
|
+
## Surface
|
|
6
|
+
|
|
7
|
+
| Property | Value |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| Product surface | `tenant-admin-app` |
|
|
10
|
+
| Intended UIX | `@tba/ui-tenant-administration` |
|
|
11
|
+
| Exposes | Tenant identities, clients, consents, sessions, tenant keys/JWKS, tenant-local audit |
|
|
12
|
+
| Excludes | Platform tenant creation/deletion and cross-tenant authority assignment |
|
|
13
|
+
|
|
14
|
+
## Entrypoint
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
from tba_app_backend_tenant_administration import app, build_app
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Local Dev Deployment
|
|
21
|
+
|
|
22
|
+
The Docker dev surface listens on `http://localhost:8016` and uses the
|
|
23
|
+
admin API key `dev-tenant-admin-key` unless overridden.
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
docker compose -f docker/docker-compose.tenant-admin-app.yml up -d --build
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Useful checks:
|
|
30
|
+
|
|
31
|
+
- `GET /openapi.json`
|
|
32
|
+
- `GET /openrpc.json`
|
|
33
|
+
- `POST /rpc` with `X-API-Key: dev-tenant-admin-key`
|
|
34
|
+
- `GET /user`, `/client`, `/clientregistration`, `/consent`
|
|
35
|
+
|
|
36
|
+
The tenant-admin surface intentionally does not expose `/tenant`, public
|
|
37
|
+
OAuth/OIDC routes, platform tenant lifecycle RPC, or service/workload admin
|
|
38
|
+
resources.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "tba-app-backend-tenant-administration"
|
|
3
|
+
version = "0.4.0.dev2"
|
|
4
|
+
description = "Tenant-scoped administration backend application for TBA."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10,<3.15"
|
|
7
|
+
license = "Apache-2.0"
|
|
8
|
+
dependencies = [
|
|
9
|
+
"tba-auth==0.4.0.dev2",
|
|
10
|
+
"tba-app-backend-core==0.4.0.dev2",
|
|
11
|
+
"tba-router-administration-gate==0.4.0.dev2",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[project.urls]
|
|
15
|
+
Homepage = "https://github.com/tigrbl/tigrbl_auth"
|
|
16
|
+
Repository = "https://github.com/tigrbl/tigrbl_auth"
|
|
17
|
+
Source = "https://github.com/tigrbl/tigrbl_auth/tree/master/pkgs/90-backend-apps/tba-app-backend-tenant-administration"
|
|
18
|
+
|
|
19
|
+
[build-system]
|
|
20
|
+
requires = ["poetry-core>=1.0.0"]
|
|
21
|
+
build-backend = "poetry.core.masonry.api"
|
|
22
|
+
|
|
23
|
+
[tool.poetry]
|
|
24
|
+
packages = [{ include = "tba_app_backend_tenant_administration", from = "src" }]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Tenant admin backend application package for TBA."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from .app import PRODUCT_SURFACE, app, build_app
|
|
6
|
+
from .contract import TENANT_ADMIN_BACKEND_APP_CONTRACT, TenantAdminBackendAppContract
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"PRODUCT_SURFACE",
|
|
10
|
+
"TENANT_ADMIN_BACKEND_APP_CONTRACT",
|
|
11
|
+
"TenantAdminBackendAppContract",
|
|
12
|
+
"app",
|
|
13
|
+
"build_app",
|
|
14
|
+
]
|
tba_app_backend_tenant_administration-0.4.0.dev2/src/tba_app_backend_tenant_administration/app.py
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"""ASGI entrypoint for the tenant admin TBA backend application."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Awaitable, Callable
|
|
7
|
+
|
|
8
|
+
from tba_app_backend_core import build_product_app
|
|
9
|
+
from tba_app_backend_tenant_administration.contract import (
|
|
10
|
+
TENANT_ADMIN_BACKEND_APP_CONTRACT,
|
|
11
|
+
)
|
|
12
|
+
from tba_auth.runtime import LazyASGIApplication
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from tigrbl import TigrblApp
|
|
16
|
+
|
|
17
|
+
PRODUCT_SURFACE = "tenant-admin-app"
|
|
18
|
+
DEFAULT_CORS_ORIGINS = ("http://localhost:3012", "http://127.0.0.1:3012")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TenantAdminCors:
|
|
22
|
+
"""Small ASGI CORS wrapper for the standalone tenant admin UIX demo."""
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self, app: Any, origins: tuple[str, ...] = DEFAULT_CORS_ORIGINS
|
|
26
|
+
) -> None:
|
|
27
|
+
self.app = app
|
|
28
|
+
self.origins = origins
|
|
29
|
+
|
|
30
|
+
def __getattr__(self, name: str) -> Any:
|
|
31
|
+
return getattr(self.app, name)
|
|
32
|
+
|
|
33
|
+
async def __call__(
|
|
34
|
+
self,
|
|
35
|
+
scope: dict[str, Any],
|
|
36
|
+
receive: Callable[[], Awaitable[dict[str, Any]]],
|
|
37
|
+
send: Callable[[dict[str, Any]], Awaitable[None]],
|
|
38
|
+
) -> None:
|
|
39
|
+
if scope.get("type") != "http":
|
|
40
|
+
await self.app(scope, receive, send)
|
|
41
|
+
return
|
|
42
|
+
|
|
43
|
+
headers = {
|
|
44
|
+
key.decode("latin-1").lower(): value.decode("latin-1")
|
|
45
|
+
for key, value in scope.get("headers", [])
|
|
46
|
+
}
|
|
47
|
+
origin = headers.get("origin")
|
|
48
|
+
allowed_origin = origin if origin in self.origins else None
|
|
49
|
+
|
|
50
|
+
if str(scope.get("method", "")).upper() == "OPTIONS" and allowed_origin:
|
|
51
|
+
await send(
|
|
52
|
+
{
|
|
53
|
+
"type": "http.response.start",
|
|
54
|
+
"status": 204,
|
|
55
|
+
"headers": self._cors_headers(allowed_origin)
|
|
56
|
+
+ [
|
|
57
|
+
(
|
|
58
|
+
b"access-control-allow-methods",
|
|
59
|
+
b"GET,POST,PATCH,DELETE,OPTIONS",
|
|
60
|
+
),
|
|
61
|
+
(
|
|
62
|
+
b"access-control-allow-headers",
|
|
63
|
+
headers.get(
|
|
64
|
+
"access-control-request-headers",
|
|
65
|
+
"content-type,authorization,x-api-key",
|
|
66
|
+
).encode("latin-1"),
|
|
67
|
+
),
|
|
68
|
+
(b"content-length", b"0"),
|
|
69
|
+
],
|
|
70
|
+
}
|
|
71
|
+
)
|
|
72
|
+
await send({"type": "http.response.body", "body": b""})
|
|
73
|
+
return
|
|
74
|
+
|
|
75
|
+
async def cors_send(message: dict[str, Any]) -> None:
|
|
76
|
+
if message.get("type") == "http.response.start" and allowed_origin:
|
|
77
|
+
message = dict(message)
|
|
78
|
+
response_headers = list(message.get("headers", []))
|
|
79
|
+
response_headers.extend(self._cors_headers(allowed_origin))
|
|
80
|
+
message["headers"] = response_headers
|
|
81
|
+
await send(message)
|
|
82
|
+
|
|
83
|
+
await self.app(scope, receive, cors_send)
|
|
84
|
+
|
|
85
|
+
@staticmethod
|
|
86
|
+
def _cors_headers(origin: str) -> list[tuple[bytes, bytes]]:
|
|
87
|
+
return [
|
|
88
|
+
(b"access-control-allow-origin", origin.encode("latin-1")),
|
|
89
|
+
(b"access-control-allow-credentials", b"true"),
|
|
90
|
+
(b"vary", b"Origin"),
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _default_settings() -> object:
|
|
95
|
+
from tba_auth.config.settings import Settings
|
|
96
|
+
|
|
97
|
+
settings = Settings()
|
|
98
|
+
env_overrides = {
|
|
99
|
+
"issuer": os.environ.get("AUTHN_ISSUER"),
|
|
100
|
+
"protected_resource_identifier": os.environ.get(
|
|
101
|
+
"TBA_AUTH_PROTECTED_RESOURCE_IDENTIFIER"
|
|
102
|
+
),
|
|
103
|
+
"deployment_profile": os.environ.get("TBA_AUTH_PROFILE"),
|
|
104
|
+
"require_tls": os.environ.get("TBA_AUTH_REQUIRE_TLS"),
|
|
105
|
+
"admin_api_key": os.environ.get("TBA_AUTH_ADMIN_API_KEY"),
|
|
106
|
+
"admin_api_key_dir": os.environ.get("TBA_AUTH_ADMIN_API_KEY_DIR"),
|
|
107
|
+
}
|
|
108
|
+
for name, value in env_overrides.items():
|
|
109
|
+
if value in {None, ""}:
|
|
110
|
+
continue
|
|
111
|
+
current = getattr(settings, name, None)
|
|
112
|
+
if isinstance(current, bool):
|
|
113
|
+
value = str(value).lower() in {"1", "true", "yes", "on"}
|
|
114
|
+
setattr(settings, name, value)
|
|
115
|
+
return settings
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def build_app(settings_obj: object | None = None) -> "TigrblApp":
|
|
119
|
+
if settings_obj is None:
|
|
120
|
+
settings_obj = _default_settings()
|
|
121
|
+
return TenantAdminCors(
|
|
122
|
+
build_product_app(
|
|
123
|
+
PRODUCT_SURFACE, settings_obj, contract=TENANT_ADMIN_BACKEND_APP_CONTRACT
|
|
124
|
+
)
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
app = LazyASGIApplication(build_app)
|
|
129
|
+
|
|
130
|
+
__all__ = ["PRODUCT_SURFACE", "app", "build_app"]
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Tenant-admin backend-app contract for TBA."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass(frozen=True, slots=True)
|
|
9
|
+
class TenantAdminBackendAppContract:
|
|
10
|
+
"""Machine-readable boundary for the tenant control-plane backend app."""
|
|
11
|
+
|
|
12
|
+
product_surface: str
|
|
13
|
+
intended_uix: str
|
|
14
|
+
admin_resources: tuple[str, ...]
|
|
15
|
+
admin_rest_groups: tuple[str, ...]
|
|
16
|
+
forbidden_route_prefixes: tuple[str, ...]
|
|
17
|
+
forbidden_exact_routes: tuple[str, ...]
|
|
18
|
+
consumed_packages: tuple[str, ...]
|
|
19
|
+
mounted_router_packages: tuple[str, ...]
|
|
20
|
+
app_local_route_groups: tuple[str, ...]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
TENANT_ADMIN_BACKEND_APP_CONTRACT = TenantAdminBackendAppContract(
|
|
24
|
+
product_surface="tenant-admin-app",
|
|
25
|
+
intended_uix="@tba/ui-tenant-administration",
|
|
26
|
+
admin_resources=(
|
|
27
|
+
"User",
|
|
28
|
+
"Client",
|
|
29
|
+
"ClientRegistration",
|
|
30
|
+
"Consent",
|
|
31
|
+
"AuditEvent",
|
|
32
|
+
"CryptoKey",
|
|
33
|
+
"CryptoKeyVersion",
|
|
34
|
+
"PrincipalKeyBinding",
|
|
35
|
+
"KeyEnvelope",
|
|
36
|
+
"KeyAttestationEvidence",
|
|
37
|
+
"KeyRotationEvent",
|
|
38
|
+
),
|
|
39
|
+
admin_rest_groups=("admin_auth", "admin_identities"),
|
|
40
|
+
forbidden_route_prefixes=(
|
|
41
|
+
"/tenant",
|
|
42
|
+
"/serviceidentity",
|
|
43
|
+
"/credentialservicekey",
|
|
44
|
+
"/credentialapikey",
|
|
45
|
+
"/tokenrecord",
|
|
46
|
+
"/revokedtoken",
|
|
47
|
+
"/authsession",
|
|
48
|
+
),
|
|
49
|
+
forbidden_exact_routes=(
|
|
50
|
+
"/login",
|
|
51
|
+
"/authorize",
|
|
52
|
+
"/token",
|
|
53
|
+
"/register",
|
|
54
|
+
"/logout",
|
|
55
|
+
"/revoke",
|
|
56
|
+
"/userinfo",
|
|
57
|
+
"/introspect",
|
|
58
|
+
"/.well-known/jwks.json",
|
|
59
|
+
"/.well-known/openid-configuration",
|
|
60
|
+
),
|
|
61
|
+
consumed_packages=(
|
|
62
|
+
"tba-auth",
|
|
63
|
+
"tba-server-identity",
|
|
64
|
+
"tba-runtime-identity",
|
|
65
|
+
"tba-runtime-identity-administration",
|
|
66
|
+
"tba-concrete-identity-principals",
|
|
67
|
+
"tba-runtime-authorization-policy",
|
|
68
|
+
),
|
|
69
|
+
mounted_router_packages=("tba-router-administration-gate",),
|
|
70
|
+
app_local_route_groups=(),
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
__all__ = ["TENANT_ADMIN_BACKEND_APP_CONTRACT", "TenantAdminBackendAppContract"]
|
tba_app_backend_tenant_administration-0.4.0.dev2/src/tba_app_backend_tenant_administration/py.typed
ADDED
|
File without changes
|