ferrox-py-auth 1.0.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.
@@ -0,0 +1,51 @@
1
+ Metadata-Version: 2.5
2
+ Name: ferrox-py-auth
3
+ Version: 1.0.0
4
+ Summary: IAM, SSO, GDPR and RBAC suite for Ferrox ecosystem.
5
+ Author: AI-Autistic-Intelligence
6
+ Requires-Python: >=3.11
7
+ Requires-Dist: ferrox-py>=1.0.0
8
+ Requires-Dist: pydantic>=2.0
9
+ Description-Content-Type: text/markdown
10
+
11
+ # Ferrox-Py-Auth
12
+
13
+ ## 1. Overview (What does this do?)
14
+ The `ferrox-py-auth` module is a specialized extension for the Ferrox ecosystem that provides a comprehensive Identity & Access Management (IAM) suite. It delivers pre-built functionalities for managing user registrations, Single Sign-On (SSO), Role-Based Access Control (RBAC), and compliance with European data privacy laws (GDPR).
15
+
16
+ ## 2. Philosophy (Why does it exist?)
17
+ Authentication and authorization are complex and highly sensitive domains. Re-implementing secure login flows, password hashing, SSO integration, and GDPR-compliant data deletion mechanisms for every new project is not only inefficient but heavily prone to critical security vulnerabilities. This module exists to provide a battle-tested, standardized "plug-and-play" identity solution that adheres to strict zero-trust principles.
18
+
19
+ ## 3. Target Audience (Who is it for?)
20
+ This module is intended for backend engineers and security architects building Enterprise SaaS, financial platforms, or any consumer-facing application where data privacy (like GDPR compliance) and secure access controls are legal or operational requirements.
21
+
22
+ ## 4. Architecture (How does it work?)
23
+ `ferrox-py-auth` plugs directly into the **7-Layer Onion Request Pipeline** of the core `ferrox-py` framework, specifically occupying Layers 3 (Threat Engine) and 4 (Auth Guards). It registers a set of domain Services (`AuthService`, `GdprService`) into the central IoC Container and exposes abstract Data Models (`User`, `UserIdentity`) that can be persisted via MongoDB or SQLAlchemy adapters provided by the `ferrox-py` Data Component.
24
+
25
+ ## 5. Installation / Setup
26
+ This package requires the core `ferrox-py` framework to function. Install it via pip:
27
+
28
+ ```bash
29
+ pip install ferrox-py-auth
30
+ ```
31
+ Ensure you have configured a persistent database layer (either SQL or NoSQL) in your core application to store the user identities.
32
+
33
+ ## 6. Quickstart (Usage)
34
+ ```python
35
+ from ferrox_py.core.app import FerroxApp
36
+ from ferrox_py.core.container import Container
37
+ from ferrox_py_auth import AuthModule
38
+
39
+ # Initialize the IoC container
40
+ container = Container()
41
+
42
+ # The AuthModule automatically registers the AuthService, GdprService,
43
+ # and Auth Guards into the container and application lifecycle.
44
+ container.register_module(AuthModule)
45
+
46
+ app = FerroxApp(container)
47
+ app.start()
48
+ ```
49
+
50
+ ## 7. Ecosystem Integration
51
+ This module relies heavily on the **Security** component of the core `ferrox-py` framework for generating and parsing PASETO/JWT tokens. It also serves as a foundational dependency for `ferrox-py-commerce`, as a validated User context is required before initiating billing or subscription processes.
@@ -0,0 +1,41 @@
1
+ # Ferrox-Py-Auth
2
+
3
+ ## 1. Overview (What does this do?)
4
+ The `ferrox-py-auth` module is a specialized extension for the Ferrox ecosystem that provides a comprehensive Identity & Access Management (IAM) suite. It delivers pre-built functionalities for managing user registrations, Single Sign-On (SSO), Role-Based Access Control (RBAC), and compliance with European data privacy laws (GDPR).
5
+
6
+ ## 2. Philosophy (Why does it exist?)
7
+ Authentication and authorization are complex and highly sensitive domains. Re-implementing secure login flows, password hashing, SSO integration, and GDPR-compliant data deletion mechanisms for every new project is not only inefficient but heavily prone to critical security vulnerabilities. This module exists to provide a battle-tested, standardized "plug-and-play" identity solution that adheres to strict zero-trust principles.
8
+
9
+ ## 3. Target Audience (Who is it for?)
10
+ This module is intended for backend engineers and security architects building Enterprise SaaS, financial platforms, or any consumer-facing application where data privacy (like GDPR compliance) and secure access controls are legal or operational requirements.
11
+
12
+ ## 4. Architecture (How does it work?)
13
+ `ferrox-py-auth` plugs directly into the **7-Layer Onion Request Pipeline** of the core `ferrox-py` framework, specifically occupying Layers 3 (Threat Engine) and 4 (Auth Guards). It registers a set of domain Services (`AuthService`, `GdprService`) into the central IoC Container and exposes abstract Data Models (`User`, `UserIdentity`) that can be persisted via MongoDB or SQLAlchemy adapters provided by the `ferrox-py` Data Component.
14
+
15
+ ## 5. Installation / Setup
16
+ This package requires the core `ferrox-py` framework to function. Install it via pip:
17
+
18
+ ```bash
19
+ pip install ferrox-py-auth
20
+ ```
21
+ Ensure you have configured a persistent database layer (either SQL or NoSQL) in your core application to store the user identities.
22
+
23
+ ## 6. Quickstart (Usage)
24
+ ```python
25
+ from ferrox_py.core.app import FerroxApp
26
+ from ferrox_py.core.container import Container
27
+ from ferrox_py_auth import AuthModule
28
+
29
+ # Initialize the IoC container
30
+ container = Container()
31
+
32
+ # The AuthModule automatically registers the AuthService, GdprService,
33
+ # and Auth Guards into the container and application lifecycle.
34
+ container.register_module(AuthModule)
35
+
36
+ app = FerroxApp(container)
37
+ app.start()
38
+ ```
39
+
40
+ ## 7. Ecosystem Integration
41
+ This module relies heavily on the **Security** component of the core `ferrox-py` framework for generating and parsing PASETO/JWT tokens. It also serves as a foundational dependency for `ferrox-py-commerce`, as a validated User context is required before initiating billing or subscription processes.
@@ -0,0 +1,35 @@
1
+ # AuthService (Authentication & SSO)
2
+
3
+ ## 1. Overview (What does this do?)
4
+ The `AuthService` is a singleton service registered within the Ferrox IoC container that handles all aspects of user registration, login, and identity verification. It provides out-of-the-box support for traditional email/password flows as well as external Single Sign-On (SSO) integrations.
5
+
6
+ ## 2. Philosophy (Why does it exist?)
7
+ Modern web applications rarely rely solely on basic username/password authentication anymore. Users expect seamless logins via Google, Apple, or GitHub. The `AuthService` exists to abstract the complexities of linking multiple external identities to a single user account and to enforce secure registration flows (like Double Opt-In) by default.
8
+
9
+ ## 3. Target Audience (Who is it for?)
10
+ This service is for backend developers who need to implement a secure user registration and login system without dealing with the low-level mechanics of hashing passwords, generating secure tokens, or verifying OAuth2 payloads manually.
11
+
12
+ ## 4. Architecture (How does it work?)
13
+ - **Standard Registration**: Handles traditional credentials. It automatically initiates a "Double Opt-In" process, meaning the account remains in a locked, unverified state until a confirmation email link is clicked.
14
+ - **SSO Integration (OIDC/OAuth2)**: Handles login/registration via external Identity Providers (IdPs). The identity (e.g., a Google ID) is saved inside an `identities` sub-document associated with the user. If a user registers via SSO, the "email verified" status is automatically inherited from the trusted IdP, bypassing the email opt-in step.
15
+
16
+ ## 5. Installation / Setup
17
+ The `AuthService` is automatically registered in your IoC container when you import and register the `AuthModule` from `ferrox-py-auth`. You may need to configure external OAuth2 credentials (Client IDs and Secrets) in your environment variables for SSO functionality.
18
+
19
+ ## 6. Quickstart (Usage)
20
+ ```python
21
+ from ferrox_py_auth.services.auth_service import AuthService
22
+
23
+ # Example: Resolving the service from the container and registering via SSO
24
+ async def handle_google_callback(auth_service: AuthService, google_payload: dict):
25
+ # Registration via SSO (Bypasses Email Validation automatically)
26
+ user = await auth_service.register_via_sso(
27
+ email=google_payload["email"],
28
+ provider="google",
29
+ provider_id=google_payload["sub"]
30
+ )
31
+ return user
32
+ ```
33
+
34
+ ## 7. Ecosystem Integration
35
+ The `AuthService` leverages the core **Data Component** to persist the `User` models to the database. Upon successful login, it interacts with the **Security Component** to generate a secure PASETO or JWT token, which is then returned to the client to be used in the Authorization header of subsequent requests.
@@ -0,0 +1,36 @@
1
+ # GdprService
2
+
3
+ ## 1. Overview (What does this do?)
4
+ The `GdprService` is a specialized service that abstracts complex commands required to comply with modern privacy laws (like the GDPR in Europe and the CCPA in California). It provides automated mechanisms for data portability (exporting user data) and the Right to be Forgotten (deleting or anonymizing user data).
5
+
6
+ ## 2. Philosophy (Why does it exist?)
7
+ Compliance with data privacy laws is a strict legal requirement, not a feature. Leaving developers to manually write cascade deletions for user data is highly dangerous; it often results in orphaned records, corrupted relational constraints, or, worse, incomplete deletions that violate privacy laws. This service exists to centralize and automate secure data anonymization and extraction.
8
+
9
+ ## 3. Target Audience (Who is it for?)
10
+ This service is essential for Data Protection Officers (DPOs), compliance engineers, and backend developers who are legally required to provide users with the ability to download their data or permanently delete their accounts from the SaaS platform.
11
+
12
+ ## 4. Architecture (How does it work?)
13
+ - **Right to be Forgotten (Deletion)**: The `delete_user_data` method securely masks, anonymizes, or hard-deletes Personally Identifiable Information (PII) across the database. It triggers an internal event that other modules can listen to, ensuring data is scrubbed across all bounded contexts.
14
+ - **Data Portability**: The `export_user_data` method aggregates the entire user state and preferences into a readable JSON or CSV format, ready to be compressed into a `.zip` file and delivered to the user.
15
+
16
+ ## 5. Installation / Setup
17
+ The `GdprService` is available out of the box when using `ferrox-py-auth`. No additional installation is required, but you must ensure your specific data repositories implement the required anonymization hooks if you have custom tables containing PII.
18
+
19
+ ## 6. Quickstart (Usage)
20
+ ```python
21
+ from ferrox_py_auth.services.gdpr_service import GdprService
22
+
23
+ async def handle_account_deletion(gdpr_service: GdprService, user_id: str):
24
+ # Perform a compliant soft delete or hard delete of PII
25
+ await gdpr_service.delete_user_data(user_id=user_id)
26
+ return {"message": "Account successfully anonymized."}
27
+
28
+ async def handle_data_export(gdpr_service: GdprService, user_id: str):
29
+ # Generate a full export of the user's data footprint
30
+ dump = await gdpr_service.export_user_data(user_id=user_id)
31
+ # Returns a comprehensive dict: { "email": "...", "identities": [...], "created_at": "..." }
32
+ return dump
33
+ ```
34
+
35
+ ## 7. Ecosystem Integration
36
+ The `GdprService` integrates with the **CQRS and Event Dispatcher** from the core framework. When `delete_user_data` is called, it emits a `UserDeletedEvent`. Other modules (like `ferrox-py-commerce`) subscribe to this event to safely cancel active subscriptions and anonymize billing records without creating tightly coupled dependencies.
@@ -0,0 +1,44 @@
1
+ # Models (Pydantic / Mongo)
2
+
3
+ ## 1. Overview (What does this do?)
4
+ The Models module exports the base Data Transfer Objects (DTOs) and Database Schemas used to represent Users and their authentication states. These models are statically validated using Pydantic and are designed to be natively serialized/deserialized into MongoDB or adapted for SQLAlchemy ORMs.
5
+
6
+ ## 2. Philosophy (Why does it exist?)
7
+ A fragmented definition of what constitutes a "User" leads to bugs across different microservices. By providing strict, centrally defined Pydantic models for `User` and `UserIdentity`, `ferrox-py-auth` ensures that every part of the application agrees on the structure of the identity data, ensuring data integrity and fast validation at the API boundaries.
8
+
9
+ ## 3. Target Audience (Who is it for?)
10
+ This module is for developers integrating the Auth module who need to understand the underlying data structure of the User object, or those who need to extend the base models with custom application-specific fields (like `company_name` or `avatar_url`).
11
+
12
+ ## 4. Architecture (How does it work?)
13
+ - **UserIdentity**: A sub-document representing an external Identity Provider (IdP) link. It stores the `provider` (e.g., "google", "apple", "facebook", "local"), the `provider_id` (the alphanumeric unique identifier from the IdP), and auditing timestamps like `last_login`.
14
+ - **User**: The primary aggregate root model. It contains the main `email` address, manages critical boolean flags (`is_email_verified`, `is_active`, `is_locked`), holds a list of `UserIdentity` objects, and contains an array of `roles` (strings) used by the RBAC engine.
15
+
16
+ ## 5. Installation / Setup
17
+ These models require `pydantic` (installed by default with the core framework). If you intend to use them directly with a NoSQL database, the `motor` driver from the core Data Component is recommended.
18
+
19
+ ## 6. Quickstart (Usage)
20
+ ```python
21
+ from ferrox_py_auth.models.user import User, UserIdentity
22
+ from datetime import datetime
23
+
24
+ # Creating an instance of a User manually (usually handled by AuthService)
25
+ identity = UserIdentity(
26
+ provider="google",
27
+ provider_id="sub_123456789",
28
+ last_login=datetime.utcnow()
29
+ )
30
+
31
+ new_user = User(
32
+ email="test@example.com",
33
+ is_email_verified=True,
34
+ is_active=True,
35
+ roles=["user", "editor"],
36
+ identities=[identity]
37
+ )
38
+
39
+ # The model will automatically validate its schema upon instantiation
40
+ print(new_user.model_dump_json())
41
+ ```
42
+
43
+ ## 7. Ecosystem Integration
44
+ These models are utilized by the **Validation Pipes** (Layer 5) to validate incoming request bodies containing user data. They are also intrinsically linked to the **Data Component**, where they act as the primary interface between the `AuthService` and the database repository.
@@ -0,0 +1,39 @@
1
+ # Ferrox-Py-Auth Overview
2
+
3
+ ## 1. Overview (What does this do?)
4
+ The `ferrox-py-auth` package provides a unified, enterprise-ready Identity, Access Management (IAM), and Data Privacy (GDPR) solution designed specifically to plug into the core `ferrox-py` framework.
5
+
6
+ ## 2. Philosophy (Why does it exist?)
7
+ In complex distributed systems and modern SaaS architectures, authentication is rarely as simple as a single "Users" SQL table. It requires dynamic extension to support Single Sign-On (Google, Apple, Microsoft), Multi-Factor Authentication, and a decoupled data architecture to scale securely. This package exists to encapsulate all that complexity into a secure, reusable module so developers can focus on business logic rather than writing boilerplate auth code.
8
+
9
+ ## 3. Target Audience (Who is it for?)
10
+ This package is built for application architects and backend engineers tasked with building secure platforms that require strict user identity tracking, varied permission levels (RBAC), and legal compliance with international privacy laws.
11
+
12
+ ## 4. Architecture (How does it work?)
13
+ The Auth package seamlessly hooks into Layer 3 (Threat Engine) and Layer 4 (Auth Guards) of the `ferrox-py` Onion Request Pipeline. It provides the practical implementation for parsing tokens, validating user state, and persisting user data.
14
+ Integrated features include:
15
+ - Management of multiple users with SSO identities linked to the same aggregate entity.
16
+ - Granular Role-Based Access Control (RBAC).
17
+ - Ready-to-use GDPR tools (Right to be Forgotten, Data Portability).
18
+
19
+ ## 5. Installation / Setup
20
+ Install the package alongside the core framework:
21
+ ```bash
22
+ pip install ferrox-py-auth
23
+ ```
24
+ Ensure that cryptographic keys used for token generation (JWT/PASETO) are injected securely via environment variables.
25
+
26
+ ## 6. Quickstart (Usage)
27
+ To enable IAM across your application, register the module in your root configuration:
28
+
29
+ ```python
30
+ from ferrox_py.core.container import Container
31
+ from ferrox_py_auth import AuthModule
32
+
33
+ container = Container()
34
+ container.register_module(AuthModule)
35
+ # Authentication and RBAC layers are now active globally.
36
+ ```
37
+
38
+ ## 7. Ecosystem Integration
39
+ The Auth module is a fundamental prerequisite for many other ecosystem packages. For instance, `ferrox-py-commerce` requires a guaranteed, authenticated `User` context to bind payment methods and track subscription ownership securely.
@@ -0,0 +1,32 @@
1
+ # RBAC (Role-Based Access Control)
2
+
3
+ ## 1. Overview (What does this do?)
4
+ The RBAC (Role-Based Access Control) module provides a granular mechanism for restricting access to specific API endpoints or Service methods based on the permissions assigned to the currently authenticated user. It exposes the `@require_roles` decorator for declarative access control.
5
+
6
+ ## 2. Philosophy (Why does it exist?)
7
+ Hardcoding `if user.role == "admin"` statements inside controller logic leads to scattered, unmaintainable, and highly insecure code. The philosophy of this component is to extract access control entirely out of the business logic and enforce it at the pipeline boundary. If a user does not have the required role, the request is terminated before the domain logic is ever invoked.
8
+
9
+ ## 3. Target Audience (Who is it for?)
10
+ This module is for developers building multi-tenant SaaS applications, administrative dashboards, or any system where different users (e.g., standard users, editors, superadmins) require different levels of access to the system resources.
11
+
12
+ ## 4. Architecture (How does it work?)
13
+ When an HTTP or gRPC endpoint is called, the authorization token (JWT or PASETO) is validated at Layer 3 of the Onion Pipeline. The token payload contains the user's "claims", which include their list of `roles`. The `@require_roles` decorator operates at Layer 4. It intercepts the call *before* executing the controller, checks the local context for the extracted roles, and compares them against the required roles defined in the decorator.
14
+
15
+ ## 5. Installation / Setup
16
+ RBAC functionalities are automatically available when you install `ferrox-py-auth`. No additional database setup is required for basic RBAC, as the roles are inherently expected to be embedded directly within the cryptographic token payload.
17
+
18
+ ## 6. Quickstart (Usage)
19
+ ```python
20
+ from ferrox_py_auth.security.rbac import require_roles
21
+
22
+ class AdminController:
23
+
24
+ # Restrict this endpoint to users who have at least one of these roles
25
+ @require_roles("superadmin", "editor")
26
+ async def delete_article(self, request, article_id: str):
27
+ # Execution only reaches this point if the token contains a matching role
28
+ return {"status": "Article deleted successfully"}
29
+ ```
30
+
31
+ ## 7. Ecosystem Integration
32
+ The RBAC decorator is tightly integrated with the core **Web & Transports Component**. By operating entirely on the Request context generated by the **Security Component**'s Auth Guards, it remains agnostic to the underlying web framework (e.g., FastAPI), allowing it to secure both HTTP REST endpoints and WebSocket connections uniformly.
@@ -0,0 +1 @@
1
+ # init
@@ -0,0 +1,52 @@
1
+ from fastapi import Request
2
+ from pydantic import BaseModel
3
+ from ferrox_py.core.controllers import BaseController
4
+ from ferrox_py.core.container import Container
5
+ from ..services.auth_service import AuthService
6
+ from ..services.gdpr_service import GdprService
7
+ from ..security.rbac import require_roles
8
+
9
+ class LoginPayload(BaseModel):
10
+ email: str
11
+ password_hash: str
12
+
13
+ class SsoPayload(BaseModel):
14
+ provider: str
15
+ provider_id: str
16
+ email: str
17
+
18
+ class AuthController(BaseController):
19
+ def __init__(self, container: Container):
20
+ super().__init__(prefix="/auth", tags=["Auth & IAM"])
21
+
22
+ self.auth = AuthService(container.resolve("JwtService"))
23
+ self.gdpr = GdprService(self.auth)
24
+
25
+ @self.router.get("/config")
26
+ async def get_config():
27
+ return self.ok(self.auth.get_config(), "Auth settings retrieved")
28
+
29
+ @self.router.post("/register")
30
+ async def register(payload: LoginPayload):
31
+ user = await self.auth.register_local(payload.email, payload.password_hash)
32
+ return self.created(user.model_dump(), "User registered. Please check your email.")
33
+
34
+ @self.router.post("/sso")
35
+ async def sso_login(payload: SsoPayload):
36
+ token = await self.auth.login_sso(payload.provider, payload.provider_id, payload.email)
37
+ return self.ok({"token": token}, "SSO Login successful")
38
+
39
+ @self.router.get("/gdpr/export")
40
+ @require_roles("user", "admin")
41
+ async def export_my_data(request: Request):
42
+ # Extract user_id from the authenticated request state
43
+ user_id = request.state.user["sub"]
44
+ data = await self.gdpr.export_data(user_id)
45
+ return self.ok(data, "GDPR Export ready")
46
+
47
+ @self.router.delete("/gdpr/forget")
48
+ @require_roles("user", "admin")
49
+ async def delete_my_account(request: Request):
50
+ user_id = request.state.user["sub"]
51
+ success = await self.gdpr.forget_me(user_id)
52
+ return self.ok({"deleted": success}, "Account permanently deleted")
@@ -0,0 +1,16 @@
1
+ from pydantic import BaseModel, Field
2
+ from typing import List, Optional
3
+ from datetime import datetime
4
+
5
+ class Identity(BaseModel):
6
+ provider: str # e.g., 'local', 'google', 'facebook', 'apple'
7
+ provider_id: str # ID from the external provider or hash of password
8
+ created_at: datetime = Field(default_factory=datetime.utcnow)
9
+
10
+ class User(BaseModel):
11
+ id: str
12
+ email: str
13
+ email_verified: bool = False
14
+ roles: List[str] = ["user"]
15
+ identities: List[Identity] = []
16
+ created_at: datetime = Field(default_factory=datetime.utcnow)
@@ -0,0 +1,26 @@
1
+ from functools import wraps
2
+ from typing import List
3
+ from fastapi import Request
4
+ from ferrox_py.core.errors import FerroxError
5
+
6
+ def require_roles(*roles: str):
7
+ """
8
+ RBAC Decorator.
9
+ Extracts the user 'roles' claim from the JWT (attached to request.state.user)
10
+ and validates it against the required roles.
11
+ """
12
+ def decorator(func):
13
+ @wraps(func)
14
+ async def wrapper(request: Request, *args, **kwargs):
15
+ user_data = getattr(request.state, "user", None)
16
+ if not user_data:
17
+ raise FerroxError("Unauthorized - No JWT token found", 401)
18
+
19
+ user_roles = user_data.get("roles", [])
20
+
21
+ if not any(role in user_roles for role in roles):
22
+ raise FerroxError(f"Forbidden - Requires one of roles: {roles}", 403)
23
+
24
+ return await func(request, *args, **kwargs)
25
+ return wrapper
26
+ return decorator
@@ -0,0 +1,52 @@
1
+ from ferrox_py.core.provider import injectable
2
+ from ferrox_py.core.errors import FerroxError
3
+ from ferrox_py.security.jwt import JwtService
4
+ from ..models.user import User, Identity
5
+ from typing import Dict, Any
6
+
7
+ @injectable()
8
+ class AuthService:
9
+ def __init__(self, jwt_service: JwtService):
10
+ self.jwt = jwt_service
11
+ self.enforce_sso_only = False # Feature flag configurable by the application
12
+
13
+ # Mock DB
14
+ self._users_db: Dict[str, User] = {}
15
+
16
+ def get_config(self) -> dict:
17
+ """Returns auth settings for the frontend (e.g. to hide password fields)."""
18
+ return {"enforce_sso_only": self.enforce_sso_only}
19
+
20
+ async def register_local(self, email: str, password_hash: str) -> User:
21
+ if self.enforce_sso_only:
22
+ raise FerroxError("Local registration is disabled by SSO policy", 403)
23
+
24
+ if email in self._users_db:
25
+ raise FerroxError("Email already in use", 400)
26
+
27
+ user = User(
28
+ id=email,
29
+ email=email,
30
+ identities=[Identity(provider="local", provider_id=password_hash)]
31
+ )
32
+ self._users_db[email] = user
33
+
34
+ # Here we would trigger the MailerService for email_verified=True
35
+ print(f"AuthService: Emitting Email Confirmation for {email}")
36
+ return user
37
+
38
+ async def login_sso(self, provider: str, provider_id: str, email: str) -> str:
39
+ """Handles SSO login or account linkage if user already exists."""
40
+ user = self._users_db.get(email)
41
+
42
+ if not user:
43
+ # Create new user, auto-verify email since it comes from trusted SSO
44
+ user = User(id=email, email=email, email_verified=True, identities=[])
45
+ self._users_db[email] = user
46
+
47
+ # Link identity if not present
48
+ if not any(i.provider == provider for i in user.identities):
49
+ user.identities.append(Identity(provider=provider, provider_id=provider_id))
50
+
51
+ # Issue JWT
52
+ return self.jwt.sign({"sub": user.id, "roles": user.roles})
@@ -0,0 +1,31 @@
1
+ from ferrox_py.core.provider import injectable
2
+ from ferrox_py.core.errors import FerroxError
3
+ from .auth_service import AuthService
4
+ from typing import Dict
5
+
6
+ @injectable()
7
+ class GdprService:
8
+ def __init__(self, auth_service: AuthService):
9
+ self.auth = auth_service
10
+
11
+ async def export_data(self, user_id: str) -> Dict:
12
+ """Returns all PII (Personally Identifiable Information) for GDPR export."""
13
+ user = self.auth._users_db.get(user_id)
14
+ if not user:
15
+ raise FerroxError("User not found", 404)
16
+
17
+ return {
18
+ "account": user.model_dump(),
19
+ "consent_logs": [],
20
+ "activity_logs": []
21
+ }
22
+
23
+ async def forget_me(self, user_id: str) -> bool:
24
+ """Right to be forgotten: Hard deletes the user and all associated identities."""
25
+ if user_id in self.auth._users_db:
26
+ del self.auth._users_db[user_id]
27
+ # In a real scenario, this would emit an event to soft-delete or anonymize
28
+ # related records across the entire microservice ecosystem.
29
+ print(f"GdprService: User {user_id} completely deleted from system.")
30
+ return True
31
+ return False
@@ -0,0 +1,15 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "ferrox-py-auth"
7
+ version = "1.0.0"
8
+ description = "IAM, SSO, GDPR and RBAC suite for Ferrox ecosystem."
9
+ authors = [{ name = "AI-Autistic-Intelligence" }]
10
+ readme = "README.md"
11
+ requires-python = ">=3.11"
12
+ dependencies = [
13
+ "ferrox-py>=1.0.0",
14
+ "pydantic>=2.0"
15
+ ]