hexastack-auth 0.1.0__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.
- hexastack_auth-0.1.0/PKG-INFO +208 -0
- hexastack_auth-0.1.0/README.md +182 -0
- hexastack_auth-0.1.0/pyproject.toml +75 -0
- hexastack_auth-0.1.0/pyproject.toml.orig +78 -0
- hexastack_auth-0.1.0/src/hexastack_auth/__init__.py +8 -0
- hexastack_auth-0.1.0/src/hexastack_auth/adapters/__init__.py +21 -0
- hexastack_auth-0.1.0/src/hexastack_auth/adapters/fastapi.py +136 -0
- hexastack_auth-0.1.0/src/hexastack_auth/adapters/grpc.py +100 -0
- hexastack_auth-0.1.0/src/hexastack_auth/adapters/in_memory.py +101 -0
- hexastack_auth-0.1.0/src/hexastack_auth/adapters/jwt.py +159 -0
- hexastack_auth-0.1.0/src/hexastack_auth/adapters/opa/__init__.py +5 -0
- hexastack_auth-0.1.0/src/hexastack_auth/adapters/opa/policy.py +88 -0
- hexastack_auth-0.1.0/src/hexastack_auth/adapters/openfga/__init__.py +5 -0
- hexastack_auth-0.1.0/src/hexastack_auth/adapters/openfga/policy.py +72 -0
- hexastack_auth-0.1.0/src/hexastack_auth/adapters/password.py +106 -0
- hexastack_auth-0.1.0/src/hexastack_auth/adapters/spiffe/__init__.py +5 -0
- hexastack_auth-0.1.0/src/hexastack_auth/adapters/spiffe/workload.py +50 -0
- hexastack_auth-0.1.0/src/hexastack_auth/domain/__init__.py +25 -0
- hexastack_auth-0.1.0/src/hexastack_auth/domain/exceptions.py +65 -0
- hexastack_auth-0.1.0/src/hexastack_auth/domain/models.py +129 -0
- hexastack_auth-0.1.0/src/hexastack_auth/infra/__init__.py +31 -0
- hexastack_auth-0.1.0/src/hexastack_auth/infra/bootstrap.py +122 -0
- hexastack_auth-0.1.0/src/hexastack_auth/infra/config.py +96 -0
- hexastack_auth-0.1.0/src/hexastack_auth/infra/decorators.py +144 -0
- hexastack_auth-0.1.0/src/hexastack_auth/infra/middleware.py +228 -0
- hexastack_auth-0.1.0/src/hexastack_auth/ports/__init__.py +11 -0
- hexastack_auth-0.1.0/src/hexastack_auth/ports/password.py +47 -0
- hexastack_auth-0.1.0/src/hexastack_auth/ports/policy.py +41 -0
- hexastack_auth-0.1.0/src/hexastack_auth/ports/security.py +57 -0
- hexastack_auth-0.1.0/src/hexastack_auth/ports/workload.py +44 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hexastack-auth
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Authentication, authorization, RBAC, JWT token services, and @authorize CQRS pipeline security for Hexastack
|
|
5
|
+
Author: Richard West
|
|
6
|
+
Author-email: Richard West <dopplereffect.us@gmail.com>
|
|
7
|
+
License-Expression: Apache-2.0
|
|
8
|
+
Requires-Dist: hexastack-core
|
|
9
|
+
Requires-Dist: hexastack-cqrs
|
|
10
|
+
Requires-Dist: pydantic>=2.10.0
|
|
11
|
+
Requires-Dist: pyjwt>=2.8.0
|
|
12
|
+
Requires-Dist: fastapi>=0.115.0 ; extra == 'fastapi'
|
|
13
|
+
Requires-Dist: grpcio>=1.62.0 ; extra == 'grpc'
|
|
14
|
+
Requires-Dist: httpx>=0.27.0 ; extra == 'opa'
|
|
15
|
+
Requires-Dist: httpx>=0.27.0 ; extra == 'openfga'
|
|
16
|
+
Requires-Dist: openfga-sdk>=0.6.0 ; extra == 'openfga'
|
|
17
|
+
Requires-Dist: cryptography>=43.0.0 ; extra == 'spiffe'
|
|
18
|
+
Requires-Dist: spiffe>=0.3.0 ; extra == 'spiffe'
|
|
19
|
+
Requires-Python: >=3.13
|
|
20
|
+
Provides-Extra: fastapi
|
|
21
|
+
Provides-Extra: grpc
|
|
22
|
+
Provides-Extra: opa
|
|
23
|
+
Provides-Extra: openfga
|
|
24
|
+
Provides-Extra: spiffe
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+

|
|
28
|
+
|
|
29
|
+
# Hexastack Auth
|
|
30
|
+
|
|
31
|
+
**`hexastack-auth`** is the security, identity, and authorization engine for the Hexastack framework. It provides protocol-agnostic identity primitives, JWT token creation/verification, PBKDF2 password hashing, and declarative `@authorize` access control across CQRS pipelines (RBAC, OPA Policy-as-Code, OpenFGA ReBAC, and SPIFFE Workload Identity).
|
|
32
|
+
|
|
33
|
+
[](https://pypi.org/project/hexastack-auth/)
|
|
34
|
+
[](https://www.python.org/downloads/)
|
|
35
|
+
[](https://codecov.io/github/TheTrueSCU/hexastack)
|
|
36
|
+
[](../../LICENSE)
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 🏛️ Architectural Overview
|
|
41
|
+
|
|
42
|
+
`hexastack-auth` adheres strictly to Hexagonal Architecture by maintaining zero dependencies on HTTP web frameworks or transport libraries. Presentation adapters (FastAPI, gRPC, GraphQL, MCP, CLI) populate the `Identity` context, and the CQRS `AuthorizationMiddleware` enforces permissions, policies, relationship checks, and workload identity uniformly.
|
|
43
|
+
|
|
44
|
+
```mermaid
|
|
45
|
+
graph TD
|
|
46
|
+
subgraph DrivingTransports ["Inbound Transports (Extract Credentials)"]
|
|
47
|
+
HTTP["FastAPI (Bearer Header)"]
|
|
48
|
+
GRPC["gRPC (Metadata Header)"]
|
|
49
|
+
GQL["GraphQL (Context Header)"]
|
|
50
|
+
CLI["CLI (Token Flag / Session)"]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
subgraph SecurityKernel ["hexastack-auth (Zero Web Dependencies)"]
|
|
54
|
+
SEC_PORT["SecurityPort (JWT / Token Service)"]
|
|
55
|
+
HASH_PORT["PasswordHasherPort (PBKDF2 / Bcrypt)"]
|
|
56
|
+
POLICY_PORT["AuthorizationPolicyPort (OPA / OpenFGA)"]
|
|
57
|
+
WORKLOAD_PORT["WorkloadIdentityPort (SPIFFE / SPIRE)"]
|
|
58
|
+
ID_MODEL["Identity (user_id, roles, permissions, claims)"]
|
|
59
|
+
MID["AuthorizationMiddleware (@authorize / RBAC / Policies)"]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
subgraph PolicyEngines ["External Policy Engines (Optional Extras)"]
|
|
63
|
+
OPA["Open Policy Agent (OPA REST API)"]
|
|
64
|
+
OPENFGA["OpenFGA (ReBAC Check API)"]
|
|
65
|
+
SPIFFE["SPIRE Agent (Workload API mTLS / SVID)"]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
HTTP -.->|verifies token via| SEC_PORT
|
|
69
|
+
GRPC -.->|verifies token via| SEC_PORT
|
|
70
|
+
GQL -.->|verifies token via| SEC_PORT
|
|
71
|
+
CLI -.->|verifies token via| SEC_PORT
|
|
72
|
+
|
|
73
|
+
POLICY_PORT -.-> OPA
|
|
74
|
+
POLICY_PORT -.-> OPENFGA
|
|
75
|
+
WORKLOAD_PORT -.-> SPIFFE
|
|
76
|
+
|
|
77
|
+
MID -->|evaluates @authorize against Identity & Policies| ID_MODEL
|
|
78
|
+
MID --> POLICY_PORT
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 📦 Features & Optional Extras
|
|
84
|
+
|
|
85
|
+
| Feature / Engine | Scoped Extra | Key Components | Description |
|
|
86
|
+
|---|---|---|---|
|
|
87
|
+
| **Core RBAC & JWT** | *(Included by default)* | `JwtSecurityAdapter`, `Pbkdf2PasswordHasher` | Role/permission-based access control, cryptographic token issuance. |
|
|
88
|
+
| **FastAPI Route Guards** | `hexastack-auth[fastapi]` | `require_policy`, `require_relation` | HTTP endpoint dependencies enforcing OPA policies and OpenFGA relationships. |
|
|
89
|
+
| **gRPC Auth Interceptor** | `hexastack-auth[grpc]` | `AuthServerInterceptor` | Server interceptor extracting metadata credentials and SPIFFE IDs into `UserContext`. |
|
|
90
|
+
| **Open Policy Agent** | `hexastack-auth[opa]` | `OpaPolicyAdapter` | Policy-as-Code evaluation querying OPA Rego decision endpoints. |
|
|
91
|
+
| **OpenFGA ReBAC** | `hexastack-auth[openfga]` | `OpenFgaPolicyAdapter` | Fine-grained relationship-based access control (user can_edit document). |
|
|
92
|
+
| **SPIFFE / SPIRE** | `hexastack-auth[spiffe]` | `SpiffeWorkloadAdapter` | Zero-Trust workload identity and service-to-service SVID attestation. |
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 🚀 Quickstart
|
|
97
|
+
|
|
98
|
+
### 1. Configuration (`pyproject.toml` or `hexastack.toml`)
|
|
99
|
+
|
|
100
|
+
```toml
|
|
101
|
+
[hexastack.auth]
|
|
102
|
+
secret_key = "your-production-secret-key"
|
|
103
|
+
algorithm = "HS256"
|
|
104
|
+
token_expire_minutes = 120
|
|
105
|
+
provider = "jwt"
|
|
106
|
+
hasher = "pbkdf2"
|
|
107
|
+
|
|
108
|
+
# Open Policy Agent (OPA)
|
|
109
|
+
[hexastack.auth.opa]
|
|
110
|
+
enabled = true
|
|
111
|
+
url = "http://localhost:8181"
|
|
112
|
+
policy_path = "v1/data/authz/allow"
|
|
113
|
+
|
|
114
|
+
# OpenFGA ReBAC
|
|
115
|
+
[hexastack.auth.openfga]
|
|
116
|
+
enabled = true
|
|
117
|
+
api_url = "http://localhost:8080"
|
|
118
|
+
store_id = "01HN7K2M9V..."
|
|
119
|
+
|
|
120
|
+
# SPIFFE / SPIRE Workload Identity
|
|
121
|
+
[hexastack.auth.spiffe]
|
|
122
|
+
enabled = true
|
|
123
|
+
socket_path = "unix:///tmp/spire-agent/public/api.sock"
|
|
124
|
+
trust_domain = "example.org"
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 2. Protecting CQRS Messages with `@authorize`
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
from hexastack_core.domain import Command
|
|
131
|
+
from hexastack_auth import authorize, requires_role
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
# 1. Standard RBAC
|
|
135
|
+
@authorize(roles=["admin"], permissions=["users:ban"])
|
|
136
|
+
class BanUserCommand(Command):
|
|
137
|
+
user_id: str
|
|
138
|
+
reason: str
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
# 2. OPA Policy-as-Code
|
|
142
|
+
@authorize(policy="policies.finance.approve_invoice")
|
|
143
|
+
class ApproveInvoiceCommand(Command):
|
|
144
|
+
invoice_id: str
|
|
145
|
+
amount: float
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
# 3. OpenFGA Relationship Check (ReBAC)
|
|
149
|
+
@authorize(relation="editor", object_type="document", object_id_field="doc_id")
|
|
150
|
+
class EditDocumentCommand(Command):
|
|
151
|
+
doc_id: str
|
|
152
|
+
content: str
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
# 4. SPIFFE Workload Trust (Service-to-Service)
|
|
156
|
+
@authorize(spiffe_ids=["spiffe://example.org/ns/prod/sa/billing-service"])
|
|
157
|
+
class SyncBillingCommand(Command):
|
|
158
|
+
tx_id: str
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### 3. FastAPI Route-Level Policy & Relationship Guards
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
from fastapi import Depends, FastAPI
|
|
165
|
+
from hexastack_auth.adapters.fastapi import require_policy, require_relation
|
|
166
|
+
|
|
167
|
+
app = FastAPI()
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
# Guard endpoint with OPA Rego policy
|
|
171
|
+
@app.get(
|
|
172
|
+
"/reports/confidential",
|
|
173
|
+
dependencies=[Depends(require_policy("v1/data/reports/view"))],
|
|
174
|
+
)
|
|
175
|
+
async def get_confidential_reports():
|
|
176
|
+
return {"data": "classified"}
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
# Guard endpoint with OpenFGA ReBAC relation
|
|
180
|
+
@app.post(
|
|
181
|
+
"/documents/{doc_id}",
|
|
182
|
+
dependencies=[Depends(require_relation("editor", "document", "doc_id"))],
|
|
183
|
+
)
|
|
184
|
+
async def update_document(doc_id: str):
|
|
185
|
+
return {"status": "updated", "doc_id": doc_id}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### 4. gRPC Server Authentication Interceptor
|
|
189
|
+
|
|
190
|
+
```python
|
|
191
|
+
import grpc
|
|
192
|
+
from hexastack_auth.adapters.grpc import AuthServerInterceptor
|
|
193
|
+
from hexastack_auth.ports import SecurityPort, WorkloadIdentityPort
|
|
194
|
+
|
|
195
|
+
security_port = runtime.container.resolve(SecurityPort)
|
|
196
|
+
workload_port = runtime.container.resolve(WorkloadIdentityPort)
|
|
197
|
+
|
|
198
|
+
server = grpc.server(
|
|
199
|
+
futures.ThreadPoolExecutor(max_workers=10),
|
|
200
|
+
interceptors=[
|
|
201
|
+
AuthServerInterceptor(
|
|
202
|
+
security_port=security_port,
|
|
203
|
+
workload_port=workload_port,
|
|
204
|
+
required=False,
|
|
205
|
+
)
|
|
206
|
+
],
|
|
207
|
+
)
|
|
208
|
+
```
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
# Hexastack Auth
|
|
4
|
+
|
|
5
|
+
**`hexastack-auth`** is the security, identity, and authorization engine for the Hexastack framework. It provides protocol-agnostic identity primitives, JWT token creation/verification, PBKDF2 password hashing, and declarative `@authorize` access control across CQRS pipelines (RBAC, OPA Policy-as-Code, OpenFGA ReBAC, and SPIFFE Workload Identity).
|
|
6
|
+
|
|
7
|
+
[](https://pypi.org/project/hexastack-auth/)
|
|
8
|
+
[](https://www.python.org/downloads/)
|
|
9
|
+
[](https://codecov.io/github/TheTrueSCU/hexastack)
|
|
10
|
+
[](../../LICENSE)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 🏛️ Architectural Overview
|
|
15
|
+
|
|
16
|
+
`hexastack-auth` adheres strictly to Hexagonal Architecture by maintaining zero dependencies on HTTP web frameworks or transport libraries. Presentation adapters (FastAPI, gRPC, GraphQL, MCP, CLI) populate the `Identity` context, and the CQRS `AuthorizationMiddleware` enforces permissions, policies, relationship checks, and workload identity uniformly.
|
|
17
|
+
|
|
18
|
+
```mermaid
|
|
19
|
+
graph TD
|
|
20
|
+
subgraph DrivingTransports ["Inbound Transports (Extract Credentials)"]
|
|
21
|
+
HTTP["FastAPI (Bearer Header)"]
|
|
22
|
+
GRPC["gRPC (Metadata Header)"]
|
|
23
|
+
GQL["GraphQL (Context Header)"]
|
|
24
|
+
CLI["CLI (Token Flag / Session)"]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
subgraph SecurityKernel ["hexastack-auth (Zero Web Dependencies)"]
|
|
28
|
+
SEC_PORT["SecurityPort (JWT / Token Service)"]
|
|
29
|
+
HASH_PORT["PasswordHasherPort (PBKDF2 / Bcrypt)"]
|
|
30
|
+
POLICY_PORT["AuthorizationPolicyPort (OPA / OpenFGA)"]
|
|
31
|
+
WORKLOAD_PORT["WorkloadIdentityPort (SPIFFE / SPIRE)"]
|
|
32
|
+
ID_MODEL["Identity (user_id, roles, permissions, claims)"]
|
|
33
|
+
MID["AuthorizationMiddleware (@authorize / RBAC / Policies)"]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
subgraph PolicyEngines ["External Policy Engines (Optional Extras)"]
|
|
37
|
+
OPA["Open Policy Agent (OPA REST API)"]
|
|
38
|
+
OPENFGA["OpenFGA (ReBAC Check API)"]
|
|
39
|
+
SPIFFE["SPIRE Agent (Workload API mTLS / SVID)"]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
HTTP -.->|verifies token via| SEC_PORT
|
|
43
|
+
GRPC -.->|verifies token via| SEC_PORT
|
|
44
|
+
GQL -.->|verifies token via| SEC_PORT
|
|
45
|
+
CLI -.->|verifies token via| SEC_PORT
|
|
46
|
+
|
|
47
|
+
POLICY_PORT -.-> OPA
|
|
48
|
+
POLICY_PORT -.-> OPENFGA
|
|
49
|
+
WORKLOAD_PORT -.-> SPIFFE
|
|
50
|
+
|
|
51
|
+
MID -->|evaluates @authorize against Identity & Policies| ID_MODEL
|
|
52
|
+
MID --> POLICY_PORT
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 📦 Features & Optional Extras
|
|
58
|
+
|
|
59
|
+
| Feature / Engine | Scoped Extra | Key Components | Description |
|
|
60
|
+
|---|---|---|---|
|
|
61
|
+
| **Core RBAC & JWT** | *(Included by default)* | `JwtSecurityAdapter`, `Pbkdf2PasswordHasher` | Role/permission-based access control, cryptographic token issuance. |
|
|
62
|
+
| **FastAPI Route Guards** | `hexastack-auth[fastapi]` | `require_policy`, `require_relation` | HTTP endpoint dependencies enforcing OPA policies and OpenFGA relationships. |
|
|
63
|
+
| **gRPC Auth Interceptor** | `hexastack-auth[grpc]` | `AuthServerInterceptor` | Server interceptor extracting metadata credentials and SPIFFE IDs into `UserContext`. |
|
|
64
|
+
| **Open Policy Agent** | `hexastack-auth[opa]` | `OpaPolicyAdapter` | Policy-as-Code evaluation querying OPA Rego decision endpoints. |
|
|
65
|
+
| **OpenFGA ReBAC** | `hexastack-auth[openfga]` | `OpenFgaPolicyAdapter` | Fine-grained relationship-based access control (user can_edit document). |
|
|
66
|
+
| **SPIFFE / SPIRE** | `hexastack-auth[spiffe]` | `SpiffeWorkloadAdapter` | Zero-Trust workload identity and service-to-service SVID attestation. |
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## 🚀 Quickstart
|
|
71
|
+
|
|
72
|
+
### 1. Configuration (`pyproject.toml` or `hexastack.toml`)
|
|
73
|
+
|
|
74
|
+
```toml
|
|
75
|
+
[hexastack.auth]
|
|
76
|
+
secret_key = "your-production-secret-key"
|
|
77
|
+
algorithm = "HS256"
|
|
78
|
+
token_expire_minutes = 120
|
|
79
|
+
provider = "jwt"
|
|
80
|
+
hasher = "pbkdf2"
|
|
81
|
+
|
|
82
|
+
# Open Policy Agent (OPA)
|
|
83
|
+
[hexastack.auth.opa]
|
|
84
|
+
enabled = true
|
|
85
|
+
url = "http://localhost:8181"
|
|
86
|
+
policy_path = "v1/data/authz/allow"
|
|
87
|
+
|
|
88
|
+
# OpenFGA ReBAC
|
|
89
|
+
[hexastack.auth.openfga]
|
|
90
|
+
enabled = true
|
|
91
|
+
api_url = "http://localhost:8080"
|
|
92
|
+
store_id = "01HN7K2M9V..."
|
|
93
|
+
|
|
94
|
+
# SPIFFE / SPIRE Workload Identity
|
|
95
|
+
[hexastack.auth.spiffe]
|
|
96
|
+
enabled = true
|
|
97
|
+
socket_path = "unix:///tmp/spire-agent/public/api.sock"
|
|
98
|
+
trust_domain = "example.org"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 2. Protecting CQRS Messages with `@authorize`
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
from hexastack_core.domain import Command
|
|
105
|
+
from hexastack_auth import authorize, requires_role
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
# 1. Standard RBAC
|
|
109
|
+
@authorize(roles=["admin"], permissions=["users:ban"])
|
|
110
|
+
class BanUserCommand(Command):
|
|
111
|
+
user_id: str
|
|
112
|
+
reason: str
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# 2. OPA Policy-as-Code
|
|
116
|
+
@authorize(policy="policies.finance.approve_invoice")
|
|
117
|
+
class ApproveInvoiceCommand(Command):
|
|
118
|
+
invoice_id: str
|
|
119
|
+
amount: float
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
# 3. OpenFGA Relationship Check (ReBAC)
|
|
123
|
+
@authorize(relation="editor", object_type="document", object_id_field="doc_id")
|
|
124
|
+
class EditDocumentCommand(Command):
|
|
125
|
+
doc_id: str
|
|
126
|
+
content: str
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
# 4. SPIFFE Workload Trust (Service-to-Service)
|
|
130
|
+
@authorize(spiffe_ids=["spiffe://example.org/ns/prod/sa/billing-service"])
|
|
131
|
+
class SyncBillingCommand(Command):
|
|
132
|
+
tx_id: str
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### 3. FastAPI Route-Level Policy & Relationship Guards
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
from fastapi import Depends, FastAPI
|
|
139
|
+
from hexastack_auth.adapters.fastapi import require_policy, require_relation
|
|
140
|
+
|
|
141
|
+
app = FastAPI()
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
# Guard endpoint with OPA Rego policy
|
|
145
|
+
@app.get(
|
|
146
|
+
"/reports/confidential",
|
|
147
|
+
dependencies=[Depends(require_policy("v1/data/reports/view"))],
|
|
148
|
+
)
|
|
149
|
+
async def get_confidential_reports():
|
|
150
|
+
return {"data": "classified"}
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
# Guard endpoint with OpenFGA ReBAC relation
|
|
154
|
+
@app.post(
|
|
155
|
+
"/documents/{doc_id}",
|
|
156
|
+
dependencies=[Depends(require_relation("editor", "document", "doc_id"))],
|
|
157
|
+
)
|
|
158
|
+
async def update_document(doc_id: str):
|
|
159
|
+
return {"status": "updated", "doc_id": doc_id}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### 4. gRPC Server Authentication Interceptor
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
import grpc
|
|
166
|
+
from hexastack_auth.adapters.grpc import AuthServerInterceptor
|
|
167
|
+
from hexastack_auth.ports import SecurityPort, WorkloadIdentityPort
|
|
168
|
+
|
|
169
|
+
security_port = runtime.container.resolve(SecurityPort)
|
|
170
|
+
workload_port = runtime.container.resolve(WorkloadIdentityPort)
|
|
171
|
+
|
|
172
|
+
server = grpc.server(
|
|
173
|
+
futures.ThreadPoolExecutor(max_workers=10),
|
|
174
|
+
interceptors=[
|
|
175
|
+
AuthServerInterceptor(
|
|
176
|
+
security_port=security_port,
|
|
177
|
+
workload_port=workload_port,
|
|
178
|
+
required=False,
|
|
179
|
+
)
|
|
180
|
+
],
|
|
181
|
+
)
|
|
182
|
+
```
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "hexastack-auth"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Authentication, authorization, RBAC, JWT token services, and @authorize CQRS pipeline security for Hexastack"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "Apache-2.0"
|
|
7
|
+
requires-python = ">=3.13"
|
|
8
|
+
dependencies = [
|
|
9
|
+
"hexastack-core",
|
|
10
|
+
"hexastack-cqrs",
|
|
11
|
+
"pydantic>=2.10.0",
|
|
12
|
+
"pyjwt>=2.8.0",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
[[project.authors]]
|
|
16
|
+
name = "Richard West"
|
|
17
|
+
email = "dopplereffect.us@gmail.com"
|
|
18
|
+
|
|
19
|
+
[project.optional-dependencies]
|
|
20
|
+
fastapi = ["fastapi>=0.115.0"]
|
|
21
|
+
grpc = ["grpcio>=1.62.0"]
|
|
22
|
+
opa = ["httpx>=0.27.0"]
|
|
23
|
+
openfga = [
|
|
24
|
+
"httpx>=0.27.0",
|
|
25
|
+
"openfga-sdk>=0.6.0",
|
|
26
|
+
]
|
|
27
|
+
spiffe = [
|
|
28
|
+
"cryptography>=43.0.0",
|
|
29
|
+
"spiffe>=0.3.0",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.entry-points."hexastack.bootstrappers"]
|
|
33
|
+
auth = "hexastack_auth.infra.bootstrap:AuthBootstrapper"
|
|
34
|
+
|
|
35
|
+
[build-system]
|
|
36
|
+
requires = ["uv_build>=0.12.3,<0.13.0"]
|
|
37
|
+
build-backend = "uv_build"
|
|
38
|
+
|
|
39
|
+
[tool.uv.sources.hexastack-core]
|
|
40
|
+
workspace = true
|
|
41
|
+
|
|
42
|
+
[tool.uv.sources.hexastack-cqrs]
|
|
43
|
+
workspace = true
|
|
44
|
+
|
|
45
|
+
[tool.importlinter]
|
|
46
|
+
root_packages = ["hexastack_auth"]
|
|
47
|
+
|
|
48
|
+
[[tool.importlinter.contracts]]
|
|
49
|
+
name = "Hexagonal architecture layer hierarchy"
|
|
50
|
+
type = "layers"
|
|
51
|
+
containers = ["hexastack_auth"]
|
|
52
|
+
layers = [
|
|
53
|
+
"adapters",
|
|
54
|
+
"ports",
|
|
55
|
+
"domain",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
[[tool.importlinter.contracts]]
|
|
59
|
+
name = "Forbidden imports for domain"
|
|
60
|
+
type = "forbidden"
|
|
61
|
+
source_modules = ["hexastack_auth.domain"]
|
|
62
|
+
forbidden_modules = [
|
|
63
|
+
"hexastack_auth.ports",
|
|
64
|
+
"hexastack_auth.adapters",
|
|
65
|
+
"hexastack_auth.infra",
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
[[tool.importlinter.contracts]]
|
|
69
|
+
name = "Forbidden imports for ports"
|
|
70
|
+
type = "forbidden"
|
|
71
|
+
source_modules = ["hexastack_auth.ports"]
|
|
72
|
+
forbidden_modules = [
|
|
73
|
+
"hexastack_auth.adapters",
|
|
74
|
+
"hexastack_auth.infra",
|
|
75
|
+
]
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "hexastack-auth"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Authentication, authorization, RBAC, JWT token services, and @authorize CQRS pipeline security for Hexastack"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "Apache-2.0"
|
|
7
|
+
authors = [
|
|
8
|
+
{ name = "Richard West", email = "dopplereffect.us@gmail.com" }
|
|
9
|
+
]
|
|
10
|
+
requires-python = ">=3.13"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"hexastack-core",
|
|
13
|
+
"hexastack-cqrs",
|
|
14
|
+
"pydantic>=2.10.0",
|
|
15
|
+
"pyjwt>=2.8.0",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[project.optional-dependencies]
|
|
19
|
+
fastapi = [
|
|
20
|
+
"fastapi>=0.115.0",
|
|
21
|
+
]
|
|
22
|
+
grpc = [
|
|
23
|
+
"grpcio>=1.62.0",
|
|
24
|
+
]
|
|
25
|
+
opa = [
|
|
26
|
+
"httpx>=0.27.0",
|
|
27
|
+
]
|
|
28
|
+
openfga = [
|
|
29
|
+
"httpx>=0.27.0",
|
|
30
|
+
"openfga-sdk>=0.6.0",
|
|
31
|
+
]
|
|
32
|
+
spiffe = [
|
|
33
|
+
"cryptography>=43.0.0",
|
|
34
|
+
"spiffe>=0.3.0",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[project.entry-points."hexastack.bootstrappers"]
|
|
38
|
+
auth = "hexastack_auth.infra.bootstrap:AuthBootstrapper"
|
|
39
|
+
|
|
40
|
+
[build-system]
|
|
41
|
+
requires = ["uv_build>=0.12.3,<0.13.0"]
|
|
42
|
+
build-backend = "uv_build"
|
|
43
|
+
|
|
44
|
+
[tool.uv.sources]
|
|
45
|
+
hexastack-core = { workspace = true }
|
|
46
|
+
hexastack-cqrs = { workspace = true }
|
|
47
|
+
|
|
48
|
+
[tool.importlinter]
|
|
49
|
+
root_packages = ["hexastack_auth"]
|
|
50
|
+
|
|
51
|
+
[[tool.importlinter.contracts]]
|
|
52
|
+
name = "Hexagonal architecture layer hierarchy"
|
|
53
|
+
type = "layers"
|
|
54
|
+
containers = ["hexastack_auth"]
|
|
55
|
+
layers = [
|
|
56
|
+
"adapters",
|
|
57
|
+
"ports",
|
|
58
|
+
"domain",
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
[[tool.importlinter.contracts]]
|
|
62
|
+
name = "Forbidden imports for domain"
|
|
63
|
+
type = "forbidden"
|
|
64
|
+
source_modules = ["hexastack_auth.domain"]
|
|
65
|
+
forbidden_modules = [
|
|
66
|
+
"hexastack_auth.ports",
|
|
67
|
+
"hexastack_auth.adapters",
|
|
68
|
+
"hexastack_auth.infra",
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
[[tool.importlinter.contracts]]
|
|
72
|
+
name = "Forbidden imports for ports"
|
|
73
|
+
type = "forbidden"
|
|
74
|
+
source_modules = ["hexastack_auth.ports"]
|
|
75
|
+
forbidden_modules = [
|
|
76
|
+
"hexastack_auth.adapters",
|
|
77
|
+
"hexastack_auth.infra",
|
|
78
|
+
]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from hexastack_auth.adapters.grpc import AuthServerInterceptor
|
|
2
|
+
from hexastack_auth.adapters.in_memory import (
|
|
3
|
+
InMemoryPasswordHasher,
|
|
4
|
+
InMemorySecurityService,
|
|
5
|
+
)
|
|
6
|
+
from hexastack_auth.adapters.jwt import JwtSecurityAdapter
|
|
7
|
+
from hexastack_auth.adapters.opa import OpaPolicyAdapter
|
|
8
|
+
from hexastack_auth.adapters.openfga import OpenFgaPolicyAdapter
|
|
9
|
+
from hexastack_auth.adapters.password import Pbkdf2PasswordHasher
|
|
10
|
+
from hexastack_auth.adapters.spiffe import SpiffeWorkloadAdapter
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"AuthServerInterceptor",
|
|
14
|
+
"InMemoryPasswordHasher",
|
|
15
|
+
"InMemorySecurityService",
|
|
16
|
+
"JwtSecurityAdapter",
|
|
17
|
+
"OpaPolicyAdapter",
|
|
18
|
+
"OpenFgaPolicyAdapter",
|
|
19
|
+
"Pbkdf2PasswordHasher",
|
|
20
|
+
"SpiffeWorkloadAdapter",
|
|
21
|
+
]
|