diff --git a/docs/images/phase-1-registration-and-application-setup.png b/docs/images/phase-1-registration-and-application-setup.png index baed923..a957710 100644 Binary files a/docs/images/phase-1-registration-and-application-setup.png and b/docs/images/phase-1-registration-and-application-setup.png differ diff --git a/docs/images/phase-2-authorization-request-and-user-consent.png b/docs/images/phase-2-authorization-request-and-user-consent.png index 13d0bf5..fe0e121 100644 Binary files a/docs/images/phase-2-authorization-request-and-user-consent.png and b/docs/images/phase-2-authorization-request-and-user-consent.png differ diff --git a/docs/images/phase-3-authorization-code-and-callback-handling.png b/docs/images/phase-3-authorization-code-and-callback-handling.png index 66096d4..0052033 100644 Binary files a/docs/images/phase-3-authorization-code-and-callback-handling.png and b/docs/images/phase-3-authorization-code-and-callback-handling.png differ diff --git a/docs/images/phase-4-token-exchange.png b/docs/images/phase-4-token-exchange.png index 35c605c..0953437 100644 Binary files a/docs/images/phase-4-token-exchange.png and b/docs/images/phase-4-token-exchange.png differ diff --git a/docs/images/phase-5-protected-resource-access.png b/docs/images/phase-5-protected-resource-access.png new file mode 100644 index 0000000..a99332e Binary files /dev/null and b/docs/images/phase-5-protected-resource-access.png differ diff --git a/docs/oauth/overview.md b/docs/oauth/overview.md index 03c66b8..b86f4f4 100644 --- a/docs/oauth/overview.md +++ b/docs/oauth/overview.md @@ -1,16 +1,17 @@ -# **OAuth Implementation Overview (Authorization Code Flow)** +# OAuth Implementation Overview This document describes the **complete OAuth 2.0 Authorization Code Flow** implemented in the ActivityPub/LOLA testbed. It explains the roles of Source and Destination services, outlines the step-by-step flow, and highlights security and compliance considerations. -## **Context** +## Context The LOLA specification ([ActivityPub Data Portability](https://swicg.github.io/activitypub-data-portability/lola.html)) defines a protocol for **live account portability** between ActivityPub servers. Our implementation enables: - Secure data transfers initiated by the **Destination service**. - User-controlled authorization via the **Source service** (testbed). - Standardized export of ActivityPub data in **JSON‑LD** format. +- Dual-mode authentication supporting both standard ActivityPub federation and enhanced LOLA portability features. -## **Flow Overview** +## Flow Overview ### **Key Actors** @@ -18,13 +19,13 @@ The LOLA specification ([ActivityPub Data Portability](https://swicg.github.io/a - **Destination Service (Client)** – Initiates data import. - **Source Service (Authorization Server)** – Hosts user data and issues tokens. -## **OAuth Flow Diagram** +## OAuth Flow Diagram ![OAuth Flow Diagram](../images/oauth-flow-diagram.png) -## **OAuth Flow Phases** +## OAuth Flow Phases -### **Phase 1: Registration & Application Setup** +### Phase 1: Registration & Application Setup - **Purpose:** Establish trust between services by registering clients. - **Process:** @@ -32,7 +33,7 @@ The LOLA specification ([ActivityPub Data Portability](https://swicg.github.io/a 2. The Source issues credentials (client ID and client secret) and stores them securely. 3. Redirect URIs and basic metadata are set for future authorization steps. -### **Phase 2: Authorization Request & User Consent** +### Phase 2: Authorization Request & User Consent - **Purpose:** Initiate the authorization process and request user approval. - **Process:** @@ -40,7 +41,7 @@ The LOLA specification ([ActivityPub Data Portability](https://swicg.github.io/a 2. The user is prompted to log in if not already authenticated. 3. A consent screen allows the user to approve or deny access to their data. -### **Phase 3: Authorization Code & Callback** +### Phase 3: Authorization Code & Callback - **Purpose:** Deliver a temporary code confirming user consent. - **Process:** @@ -48,7 +49,7 @@ The LOLA specification ([ActivityPub Data Portability](https://swicg.github.io/a 2. The user is redirected back to the Destination with this code and a state value to confirm request integrity. 3. The Destination prepares to exchange this code for an access token. -### **Phase 4: Token Exchange** +### Phase 4: Token Exchange - **Purpose:** Convert the authorization code into an access token. - **Process:** @@ -56,7 +57,7 @@ The LOLA specification ([ActivityPub Data Portability](https://swicg.github.io/a 2. The Source validates the request and returns an access token. 3. This token will be used for accessing protected resources. -### **Phase 5: Protected Resource Access** +### Phase 5: Protected Resource Access - **Purpose:** Access user data from the Source service using the access token. - **Process:** @@ -64,7 +65,9 @@ The LOLA specification ([ActivityPub Data Portability](https://swicg.github.io/a 2. The Source validates the token and ensures the request is within the approved scope. 3. Data is returned in JSON-LD format aligned with ActivityPub and LOLA standards. -### **Phase 6: Account Recreation** +## Data Transfer / Account Portability Features + +### Account Recreation - **Purpose:** Use the retrieved data to recreate the user’s account on the new service. - **Process:** @@ -72,53 +75,87 @@ The LOLA specification ([ActivityPub Data Portability](https://swicg.github.io/a 2. The user resumes activity seamlessly on the new platform. 3. This phase concludes the portability process. -## **Security Measures** +*Note: This phase is part of the broader Data Transfer and Account Portability workflow, utilizing the data obtained through the OAuth flow but extending beyond the core OAuth 2.0 specification.* + +## OptionalOAuth2Authentication + +Our implementation uses a custom OptionalOAuth2Authentication class that enables dual-mode operation on the same endpoints: + +### Dual-Mode Operation + +1. **Unauthenticated Mode:** Standard ActivityPub federation with public data +2. **Authenticated Mode:** Enhanced LOLA data with `activitypub_account_portability` scope + +### Key Features + +- **Graceful Degradation:** Invalid or missing tokens don't cause failures; requests continue as unauthenticated +- **Scope-Based Enhancement:** Only tokens with `activitypub_account_portability` scope unlock LOLA-specific data +- **Request Flags:** Adds `is_oauth_authenticated` and `has_portability_scope` flags to request objects +- **URL Parameter Authentication:** Supports `auth_token` URL parameter for testing convenience +- **Flexible Authentication:** Supports both Authorization header and URL parameter authentication -- **Authorization Code Flow** – Chosen for confidential clients (most secure option). -- **Redirect URI Validation** – Prevents open redirect vulnerabilities. -- **State Parameter** – Mitigates CSRF attacks. -- **Hashed Client Secrets** – Stored securely in DB; raw secret shown only once. -- **HTTPS Enforcement** – Required in production environments. +### **Benefits** -## **Error Handling & Testing Scenarios** +- Same endpoint serves both ActivityPub federation and LOLA portability +- No separate API versions needed +- Maintains backward compatibility with existing ActivityPub clients +- Provides enhanced data only when properly authenticated for portability -### **Common Error Cases** +## Security Measures + +### Current Implementation + +- **Authorization Code Flow** – Chosen for confidential clients (most secure option). +- **Redirect URI Validation** — Prevents open redirect vulnerabilities via `ActivityPubOAuth2Validator`. +- **State Parameter** — Mitigates CSRF attacks with cryptographically secure state generation and validation. +- **Scope Validation** — Enforces `activitypub_account_portability` scope requirement for LOLA operations. +- **Session-based Client Secrets** — Raw secrets stored temporarily in session for token exchange. +- **OptionalOAuth2Authentication** — Graceful degradation prevents authentication failures from breaking federation. + +### Future Enhancements + +- **Hashed Client Secrets** — Store only hashed secrets in DB; show raw secret only once during registration. +- **HTTPS Enforcement** — Required in production environments. +- **Rate Limiting** — Implement rate limiting for token endpoints to prevent abuse. + +### Common Error Cases Validation - Invalid client_id or redirect_uri mismatch. - Expired or invalid authorization code. - Invalid or expired access token. - Scope mismatch during token validation. -### **Security Tests** - -- Verify state parameter prevents CSRF. -- Confirm HTTPS and redirect validation. -- Ensure rate limiting for token endpoints. - ### **Data Access Validation** - Verify returned data is JSON‑LD and LOLA-compliant. - Ensure tokens allow only scoped access (e.g., activitypub_account_portability). +- Validate enhanced LOLA data is only provided to properly authenticated requests. +- Confirm public ActivityPub data remains accessible without authentication. ## **Implementation Notes** +- OptionalOAuth2Authentication — Core component enabling dual-mode operation for ActivityPub federation and LOLA portability. - **One Application per User**: Simplifies testbed logic and mirrors real-world service isolation. +- **Session-based Secret Management** — Raw client secrets stored in session during OAuth flow for token exchange. +- **Comprehensive Testing** — Extensive test coverage ensures security and proper authentication behavior. - **Credential Rotation**: Future enhancement — add secret regeneration endpoint for compromised clients. - **Logging**: Record significant events (registration, authorization, token exchange) without exposing secrets. - **Compliance**: Aligns with [RFC 6749](https://datatracker.ietf.org/doc/html/rfc6749) and LOLA portability guidelines. -## **Real-Case Example** +## Real-Case Example **Scenario:** A developer of “MyFediverse” registers their service and imports data: 1. Registers service at testbed → receives client_id and client_secret. 2. User at MyFediverse clicks “Import from Testbed.” 3. Redirects to testbed for login and consent. -4. Authorization code exchanged for token. -5. MyFediverse retrieves ActivityPub data (profile, posts, followers). +4. Authorization code exchanged for token with activitypub_account_portability scope. +5. MyFediverse retrieves enhanced ActivityPub data (profile, posts, followers) including LOLA-specific collection URLs. -## OAuth Implementation Phases +## OAuth Implementation Diagram with Methods and Files Involved + +*This diagram demonstrates the complete OAuth flow implementation showing the specific templates, views, and methods involved in each phase. It serves as a technical reference for understanding how the OAuth flow maps to actual code components in the testbed.* ``` ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ @@ -129,6 +166,12 @@ The LOLA specification ([ActivityPub Data Portability](https://swicg.github.io/a └────────┬─────────┘ └────────┬─────────┘ └────────┬─────────┘ │ │ │ │ │ │ + │ │ │ + │ │ │ + │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + │ ┃ PHASE 1: REGISTRATION & APPLICATION SETUP ┃ + │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + │ │ │ │ │ (1) Register Application │ │ │ ←---------------------------┘ │ │ [Method: index() - views.py] @@ -140,6 +183,10 @@ The LOLA specification ([ActivityPub Data Portability](https://swicg.github.io/a │ │ ---------------------------→│ │ │ │ │ │ │ + │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + │ ┃ PHASE 2: AUTHORIZATION REQUEST & CONSENT ┃ + │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + │ │ │ │ (3) User initiates account transfer at Destination │ │ ←-----------------------------------------------------┐ │ │ │ │ │ @@ -154,31 +201,37 @@ The LOLA specification ([ActivityPub Data Portability](https://swicg.github.io/a │ -----------------------------→ │ │ │ [Handled by Django OAuth Toolkit] │ │ [Route: oauth2_provider:authorize] - │ │ │ + │ │ [Validator: ActivityPubOAuth2Validator - oauth_validators.py] │ │ │ │ (6) Login if needed │ │ │ ←----------------------------- │ │ │ [Django Authentication] │ │ │ │ - │ │ │ - │ (7) Authorization Page Displayed │ + │(7) Authorization Page Displayed │ │ ←----------------------------- │ │ │ [Template: oauth2_provider/authorize.html] │ │ │ - │ │ │ │ (8) User approves │ │ │ -----------------------------→ │ │ │ [Form submission to oauth2_provider:authorize] - │ │ [Validation: ActivityPubOAuth2Validator - oauth_validators.py] │ │ │ │ │ │ + │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + │ ┃ PHASE 3: AUTHORIZATION CODE & CALLBACK ┃ + │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + │ │ │ │ │ (9) Redirect with code │ │ │ [Django OAuth Toolkit code generation] │ │ [Demo view: oauth_callback() - views.py] │ │ [Template: oauth_callback.html] + │ │ [Validation: validate_state_from_session() - oauth_utils.py] │ │ ---------------------------→│ │ │ │ │ │ │ + │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + │ ┃ PHASE 4: TOKEN EXCHANGE ┃ + │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + │ │ │ │ │ (10) Token Exchange Request│ │ │ [Method: Similar to test_token_exchange_view() - views.py] │ │ ←---------------------------┘ @@ -191,20 +244,28 @@ The LOLA specification ([ActivityPub Data Portability](https://swicg.github.io/a │ │ ---------------------------→│ │ │ │ │ │ │ + │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + │ ┃ PHASE 5: PROTECTED RESOURCE ACCESS ┃ + │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + │ │ │ │ │ (12) API Request with Token│ │ │ [Client uses token in Authorization header] + │ │ [OptionalOAuth2Authentication - authentication.py] │ │ ←---------------------------┘ │ │ │ - │ │ (13) Return ActivityPub Data + │ │ (13). Return ActivityPub Data │ │ [API views with OAuth protection] │ │ [e.g., actor_detail(), portability_outbox_detail() - views.py] │ │ [JSON-LD builders - json_ld_builders.py] │ │ ---------------------------→│ │ │ │ │ │ │ + │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + │ ┃ DATA TRANSFER / ACCOUNT PORTABILITY ┃ + │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + │ │ │ │ (14) Account recreated at Destination │ │ ←-----------------------------------------------------┐ │ │ │ │ │ │ │ │ │ - ``` \ No newline at end of file diff --git a/docs/oauth/phase-1-registration-and-application-setup.md b/docs/oauth/phase-1-registration-and-application-setup.md index 3c1637c..167b53e 100644 --- a/docs/oauth/phase-1-registration-and-application-setup.md +++ b/docs/oauth/phase-1-registration-and-application-setup.md @@ -2,20 +2,20 @@ ![Phase 1](../images/phase-1-registration-and-application-setup.png) -## **Overview** +## Overview Phase 1 establishes the foundation of our OAuth 2.0 implementation for the testbed. It covers the **registration of applications** (representing ActivityPub services) and the creation of **immutable OAuth credentials**. This step is essential to establish trust between the authorization server (Source Service) and the client applications (Destination Services) participating in the LOLA data portability flow. -By completing this phase, each service obtains a unique **client ID** and **client secret** that identify it throughout the OAuth flow, enabling secure interactions during subsequent phases such as authorization, token exchange, and protected resource access. +By completing this phase, each service obtains a unique **Client ID** and **Client Secret** that identify it throughout the OAuth flow, enabling secure interactions during subsequent phases such as authorization, token exchange, and protected resource access. -## **Objectives of Phase 1** +## Objectives of Phase 1 - Enable new services to register with the Source Service and establish a trusted OAuth relationship. -- Generate **immutable credentials** (client ID and client secret) that remain consistent for the lifetime of the application. +- Generate **immutable credentials** (Client ID and Client Secret) that remain consistent for the lifetime of the application. - Provide a user interface and workflow for managing OAuth application settings. - Enforce **security best practices** by ensuring credentials are securely generated, stored, and not user-editable. -## **Context in the LOLA Flow** +## Context in the LOLA Flow Within the **LOLA** portability process: @@ -25,9 +25,9 @@ Within the **LOLA** portability process: This **one user → one service → one application** model simplifies the flow while maintaining security and realism for testing ActivityPub implementations. -## **Core Components** +## Core Components -### **1. OAuth Application Form** +### 1. OAuth Application Form The OAuthApplicationForm (**`forms/oauth_connection_form.py`**) provides the interface for registering and configuring an OAuth application. @@ -44,17 +44,18 @@ The OAuthApplicationForm (**`forms/oauth_connection_form.py`**) provides the int Proper validation and default configuration prevent common security pitfalls such as open redirect vulnerabilities or weak client handling. -### **2. Credential Generation & Storage** +### 2. Credential Generation & Storage Credential handling is implemented via the get_user_application() method (oauth_utils.py): - **Immutable Credential Creation:** If the user has no existing application, new credentials are generated using secure random functions. - **Session-Based Raw Secret Storage:** - - The client secret is hashed when stored in the database for security. - - The raw secret is temporarily stored in the user’s session and attached as a runtime-only attribute to the application object. - - This allows it to be used for token exchange later without exposing it beyond its intended lifespan. + - Client secrets are currently stored in raw form in the database for simplicity in the testbed environment. + - The raw secret is temporarily stored in the user's session and attached as a runtime-only attribute to the application object. + - This session storage enables token exchange during the OAuth flow without requiring database retrieval of the secret. + - **Note:** Hashed client secret storage is planned as a future security enhancement for production deployments. -### **3. Index View** +### 3. Index View The index() view serves as the **entry point** for Phase 1, integrating the form and utility logic: @@ -63,14 +64,16 @@ The index() view serves as the **entry point** for Phase 1, integrating the form - Handles form submissions for updating application details like redirect URIs. - Enforces immutability of client ID and client secret through both frontend (read-only fields) and backend (overridden save() method) safeguards. -## **Security Considerations** +## Security Considerations -- **Immutable Credentials:** Client ID and client secret cannot be edited after creation. -- **Session Storage:** Raw secrets are stored only in secure server-side sessions and never persisted in plaintext. +- **Immutable Credentials:** Client ID and Client Secret cannot be edited after creation. +- **Current Storage Approach:** Client Secrets are stored in raw form in the database for testbed simplicity, with session-based access during OAuth flows. +- **Session Management:** Raw secrets are temporarily stored in secure server-side sessions to enable token exchange without additional database queries. - **Redirect URI Validation:** Ensures callback URLs are safe and properly formatted; additional validation (e.g., allowlists, HTTPS-only) is recommended for production. - **Audit Logging:** Key events (credential creation, retrieval, anomalies) are logged for traceability. +- **Future Security Enhancement:** Hashed Client Secret storage is planned for production deployments to enhance security. -## **User Experience Flow** +## User Experience Flow 1. **Initial Registration (New Application):** - User accesses the registration form. @@ -79,14 +82,14 @@ The index() view serves as the **entry point** for Phase 1, integrating the form 2. **Subsequent Visits (Existing Application):** - Form is pre-filled with existing application data. - Credentials remain immutable; only redirect URIs or service name can be updated. - - Raw client secret may be retrieved from session if needed for token exchange. + - Raw Client Secret may be retrieved from session if needed for token exchange. 3. **Update Flow:** - User can update non-sensitive fields (e.g., redirect URIs). - - Client secret regeneration is not part of this phase but may be considered for future enhancements. + - Client Secret regeneration is not part of this phase but may be considered for future enhancements. -## **Implementation Details** +## Implementation Details -### **Form Snippet** +### Form Snippet ```python class OAuthApplicationForm(forms.ModelForm): @@ -103,7 +106,7 @@ class OAuthApplicationForm(forms.ModelForm): } ``` -### **Credential Handling Logic** +### Credential Handling Logic ```python def get_user_application(user, request=None): @@ -134,14 +137,14 @@ def get_user_application(user, request=None): return application ``` -## **Future Enhancements** +## Future Enhancements - **Credential Rotation:** Implement a secure flow for regenerating client secrets when necessary. - **Advanced URI Validation:** Enforce HTTPS and allowlist domains in production environments. - **Scope Management:** Extend registration to include configurable scopes for fine-grained access control. - **Enhanced Auditing:** Expand logging for compliance with security frameworks (SOC 2, ISO 27001). -## **Significance of Phase 1** +## Significance of Phase 1 This phase creates the **secure foundation** for the entire OAuth implementation in our testbed. By enforcing credential immutability, secure secret handling, and clear user workflows, we establish trust and ensure a robust basis for subsequent phases: diff --git a/docs/oauth/phase-2-authorization-request-and-user-consent.md b/docs/oauth/phase-2-authorization-request-and-user-consent.md index 22646cd..2fbce5e 100644 --- a/docs/oauth/phase-2-authorization-request-and-user-consent.md +++ b/docs/oauth/phase-2-authorization-request-and-user-consent.md @@ -1,14 +1,14 @@ -# **Phase 2: Authorization Request & User Consent** +# Phase 2: Authorization Request & User Consent ![Phase 2](../images/phase-2-authorization-request-and-user-consent.png) -## **Overview** +## Overview Phase 2 is the stage where the user explicitly authorizes the **Destination Service** to access their data from the **Source Service**. This phase introduces **user consent**, a core principle of OAuth 2.0 and the foundation of data portability in the LOLA implementation. In this phase, the Destination Service constructs an **authorization request** and redirects the user to the Source Service’s authorization endpoint. The Source Service handles user authentication (if necessary) and presents a **consent screen** detailing the data to be shared. Upon user approval, the process transitions into **Phase 3: Authorization Code & Callback Handling**. -## **Objectives of Phase 2** +## Objectives of Phase 2 - Provide a secure mechanism for **user consent** within the OAuth flow. - Ensure the **Destination Service** properly constructs the authorization request, including all required parameters. @@ -16,7 +16,7 @@ In this phase, the Destination Service constructs an **authorization request** a - Prevent **CSRF attacks** using a cryptographically secure state parameter. - Clearly communicate the scope and purpose of data sharing in the consent screen. -## **Context in the LOLA Flow** +## Context in the LOLA Flow Within LOLA portability: @@ -26,9 +26,9 @@ Within LOLA portability: This explicit consent step differentiates LOLA from many typical OAuth implementations, which often request narrower scopes (e.g., profile or email access). -## **Core Components** +## Core Components -### **1. Authorization URL Construction** +### 1. Authorization URL Construction The **Destination Service** initiates the flow by building an authorization URL that includes the following parameters: @@ -51,7 +51,7 @@ state=secureRandomState This URL is constructed dynamically in the **Destination Service’s** view, often using the current request’s scheme and host for the callback URI. -### **2. State Parameter Security** +### 2. State Parameter Security The state parameter is critical for **CSRF protection**: @@ -72,7 +72,7 @@ This pattern prevents: - store_state_in_session() - validate_state_from_session() -### **3. Consent Screen** +### 3. Consent Screen The consent screen (authorize.html) is presented by the **Source Service** and includes: @@ -88,7 +88,7 @@ The consent screen (authorize.html) is presented by the **Source Service** and i - Hidden fields for necessary OAuth parameters. - Clear visual hierarchy and plain language for user comprehension. -### **4. Validation Logic** +### 4. Validation Logic Custom validation is implemented in ActivityPubOAuth2Validator: @@ -102,31 +102,31 @@ Custom validation is implemented in ActivityPubOAuth2Validator: This ensures that only valid, registered redirect URIs and scopes can proceed through the authorization process. -## **Interaction Flow** +## Interaction Flow -### **1. Initiation** +### 1. Initiation - User clicks “Import from [Source Service]” on the Destination Service. - Destination Service constructs the authorization URL with required parameters and a secure state. -### **2. Redirection** +### 2. Redirection - User’s browser is redirected to /oauth/authorize at the Source Service. -### **3. Authentication** +### 3. Authentication - If not already authenticated, the user logs into the Source Service. -### **4. Consent Presentation** +### 4. Consent Presentation - Source Service displays the consent screen, showing requested data and permissions. -### **5. User Decision** +### 5. User Decision - If approved: Source Service issues an authorization code and redirects to the registered redirect_uri. - If denied: Redirect occurs with error parameters indicating denial. -## **Security Considerations** +## Security Considerations - **State Parameter** – Prevents CSRF and replay attacks. - **Redirect URI Validation** – Defends against open redirect and code interception attacks. @@ -135,9 +135,9 @@ This ensures that only valid, registered redirect URIs and scopes can proceed th - **Logging** – Records key events for auditability (invalid scopes, URIs, approvals). -## **Implementation Example** +## Implementation Example -### **Authorization URL Construction (Destination Service)** +### Authorization URL Construction (Destination Service) ```python @login_required @@ -171,7 +171,7 @@ def test_authorization_view(request): return redirect(auth_url) ``` -## **Significance of Phase 2** +## Significance of Phase 2 This phase embodies the **core consent principle** of OAuth: the user explicitly approves the data transfer. By enforcing strict scope validation, secure redirect URI handling, and robust CSRF protection, Phase 2 ensures: diff --git a/docs/oauth/phase-3-authorization-code-and-callback-handling.md b/docs/oauth/phase-3-authorization-code-and-callback-handling.md index 3ed271e..14817b2 100644 --- a/docs/oauth/phase-3-authorization-code-and-callback-handling.md +++ b/docs/oauth/phase-3-authorization-code-and-callback-handling.md @@ -1,14 +1,14 @@ -# **Phase 3: Authorization Code & Callback Handling** +# Phase 3: Authorization Code & Callback Handling ![Phase 3](../images/phase-3-authorization-code-and-callback-handling.png) -## **Overview** +## Overview Phase 3 represents the secure bridge between **user consent** (Phase 2) and **token exchange** (Phase 4) in our OAuth 2.0 flow. At this stage, the **Source Service (Authorization Server)** issues a **short-lived authorization code** to the **Destination Service (Client)** after the user has granted consent. This code is delivered via a secure redirect to the client’s registered callback URI and serves as proof that the user has approved the data transfer. In the context of LOLA portability, this phase confirms user intent to transfer their entire ActivityPub account data from the Source Service to the Destination Service, enabling the next step: requesting an access token. -## **Objectives of Phase 3** +## Objectives of Phase 3 - Deliver a **temporary, one-time-use authorization code** securely to the Destination Service. - Maintain security integrity by validating the **state parameter** to prevent CSRF attacks. @@ -16,7 +16,7 @@ In the context of LOLA portability, this phase confirms user intent to transfer - Provide a clear **callback handling process** that prepares for token exchange. - Handle **success and error scenarios** gracefully for the end-user and client application. -## **Context in the LOLA Flow** +## Context in the LOLA Flow This phase begins **after** the user has consented to the data transfer (Phase 2) and ends **before** the Destination Service exchanges the code for an access token (Phase 4). The key outcomes of this phase are: @@ -25,9 +25,9 @@ This phase begins **after** the user has consented to the data transfer (Phase 2 - Validation of the state parameter to confirm request integrity. - Preparation for the token exchange process. -## **Core Components** +## Core Components -### **1. Authorization Code Generation** +### * - **Triggered by User Consent:** Once the user approves access on the Source Service’s consent screen, Django OAuth Toolkit generates an **authorization code**. - **Security Properties:** @@ -36,7 +36,7 @@ This phase begins **after** the user has consented to the data transfer (Phase 2 - Bound to the requesting client_id, approved scope, and redirect_uri. - One-time use — automatically invalidated upon successful token exchange. -### **2. Secure Redirection** +### 2. Secure Redirection After generating the authorization code: @@ -49,7 +49,7 @@ https://destination.com/callback?code=abc123&state=xyz789 This preserves the security context established earlier and signals the Destination Service to begin callback handling. -### **3. Callback Handling** +### 3. Callback Handling The **Destination Service** processes the callback via a dedicated view (oauth_callback): @@ -58,7 +58,7 @@ The **Destination Service** processes the callback via a dedicated view (oauth_c - Distinguishes between success (valid code) and error scenarios (denied or invalid requests). - Prepares the code for token exchange in Phase 4. -### **4. State Parameter Validation** +### 4. State Parameter Validation State validation ensures the callback originates from the legitimate request: @@ -68,9 +68,9 @@ State validation ensures the callback originates from the legitimate request: If validation fails, the request is rejected and logged as a potential security incident. -## **Implementation Details** +## Implementation Details -### **Authorization Code Handling (Callback View)** +### Authorization Code Handling (Callback View) ```python def oauth_callback(request): @@ -108,7 +108,7 @@ def oauth_callback(request): return render(request, 'oauth_callback.html', context) ``` -### **State Validation Utility** +### State Validation Utility ```python def validate_state_from_session(request, state): @@ -125,7 +125,7 @@ def validate_state_from_session(request, state): return secrets.compare_digest(stored_state, state) ``` -## **Security Considerations** +## Security Considerations - **Time-Limited Codes:** Authorization codes expire after 10 minutes. - **One-Time Use:** Codes are invalidated immediately after token exchange. @@ -133,7 +133,7 @@ def validate_state_from_session(request, state): - **State Parameter Validation:** Protects against CSRF and callback forgery. - **HTTPS Enforcement:** All production environments should transmit authorization codes exclusively over HTTPS. -## **User Experience Flow** +## User Experience Flow 1. **User Consent Granted:** Phase 2 completes, and the Source Service issues an authorization code. 2. **Redirection to Callback:** User is redirected to the Destination Service’s registered callback URI. @@ -142,14 +142,14 @@ def validate_state_from_session(request, state): - Authorization code is extracted and displayed/stored. 4. **Preparation for Token Exchange:** The code is now ready to be exchanged for an access token in Phase 4. -## **Future Enhancements** +## Future Enhancements - **PKCE Support:** Add code challenge/verification for public clients. - **Enhanced Error Handling:** Provide user-friendly error pages with actionable next steps. - **Replay Detection Metrics:** Add monitoring for repeated invalid state or expired code attempts. - **Automated Transition to Token Exchange:** Optionally trigger Phase 4 immediately after successful callback. -## **Significance of Phase 3** +## Significance of Phase 3 This phase ensures a **secure transition** between user consent and token issuance, preserving the integrity of the OAuth flow: diff --git a/docs/oauth/phase-4-token-exchange.md b/docs/oauth/phase-4-token-exchange.md index 6f1fc15..ad7f438 100644 --- a/docs/oauth/phase-4-token-exchange.md +++ b/docs/oauth/phase-4-token-exchange.md @@ -1,14 +1,14 @@ -# **Phase 4: Token Exchange** +# Phase 4: Token Exchange ![Phase 4](../images/phase-4-token-exchange.png) -## **Overview** +## Overview Phase 4 represents the critical security bridge between **user authorization** (Phase 2) and **protected resource access** (Phase 5) in our OAuth 2.0 flow. After a user grants consent and the client receives an authorization code (Phase 3), Phase 4 is where the **Destination Service (Client)** securely exchanges this temporary code for a longer-lived **access token** that grants actual API access permissions. In the context of LOLA account portability, this phase transforms the user's authorization decision into secure credentials that allow the Destination Service to begin the actual data transfer process from the Source Service. -## **Objectives of Phase 4** +## Objectives of Phase 4 - Securely exchange the short-lived authorization code for a longer-lived access token. - Authenticate the client application using secure methods (HTTP Basic Authentication or request body). @@ -17,7 +17,7 @@ In the context of LOLA account portability, this phase transforms the user's aut - Implement strict security controls to prevent token theft or misuse. - Provide clear error handling for common token exchange issues. -## **Context in the LOLA Flow** +## Context in the LOLA Flow Within the LOLA portability process: @@ -28,9 +28,9 @@ Within the LOLA portability process: This phase acts as the "handshake" that establishes trust between services for data transfer. Once complete, the security context shifts from "proving authorization" to "accessing authorized resources." -## **Core Components** +## Core Components -### **1. Token Request Construction** +### 1. Token Request Construction The Destination Service constructs a token request with the following required parameters: @@ -52,7 +52,7 @@ Authorization: Basic base64(client_id:client_secret) grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=https%3A%2F%2Fdestination.example.com%2Fcallback ``` -### **2. Server-Side Token Generation** +### 2. Server-Side Token Generation Upon receiving the token request, the Source Service performs multiple validation steps: @@ -69,7 +69,7 @@ If all validations pass, the server generates: - Scope information - Token expiration time -### **3. Token Response** +### 3. Token Response The Source Service returns a standardized token response: @@ -83,7 +83,7 @@ The Source Service returns a standardized token response: } ``` -### **4. Client-Side Token Storage** +### 4. Client-Side Token Storage The Destination Service securely stores: @@ -91,7 +91,7 @@ The Destination Service securely stores: - The refresh token (if provided) for obtaining new access tokens without user interaction - Token metadata including expiration and scope -## **Implementation Details** +## Implementation Details In our testbed implementation: @@ -112,7 +112,7 @@ In our testbed implementation: - HTTP Basic Authentication (preferred according to OAuth spec) - Request body authentication (as a fallback) -### **Client Authentication Methods** +### Client Authentication Methods ```python # First try: Use HTTP Basic Authentication for client credentials (preferred method) @@ -138,7 +138,7 @@ if token_response.status_code == 401: ) ``` -### **Token Validation Process** +### Token Validation Process The token endpoint performs sequential validation steps: @@ -156,7 +156,7 @@ def validate_scopes(self, client_id, scopes, client, request, *args, **kwargs): return super().validate_scopes(client_id, scopes, client, request, *args, **kwargs) ``` -## **Security Considerations** +## Security Considerations - **Client Authentication** – This phase is critical for security as it ensures only the legitimate client with correct credentials can exchange the code for tokens. @@ -171,7 +171,7 @@ def validate_scopes(self, client_id, scopes, client, request, *args, **kwargs): - Never exposed to client-side code - Protected against CSRF attacks when used -## **Error Handling** +## Error Handling Common errors during token exchange include: @@ -200,7 +200,7 @@ except: context['token_error'] = f"Error: HTTP {token_response.status_code} - {token_response.text}" ``` -## **Testing Interface** +## Testing Interface Our implementation includes an testing interface in `oauth_token_exchange.html` that: @@ -229,9 +229,9 @@ response = requests.get('https://api.example.com/activity-pub/user', headers=hea 3. **Explains Errors** – Provides troubleshooting guidance for common token exchange errors. -## **Best Practices Implemented** +## Best Practices Implemented -1. **Secure Client Secret Management** – Raw client secrets are never stored in the database, only securely hashed versions. +1. **Session-Based Secret Management** – Client secrets are stored in raw form in the database for testbed simplicity, with secure session-based access during OAuth flows. Hashed storage is planned as a future security enhancement. 2. **Robust Error Handling** – Clear error messages with proper HTTP status codes and OAuth error responses. @@ -241,7 +241,7 @@ response = requests.get('https://api.example.com/activity-pub/user', headers=hea 5. **Strict Validation** – Thorough validation of all parameters including redirect URI matching and scope validation. -## **Configuration Settings** +## Configuration Settings Our implementation has specific settings in Django's settings.py: @@ -260,7 +260,7 @@ OAUTH2_PROVIDER = { } ``` -## **Future Enhancements** +## Future Enhancements - **PKCE Support** – Enable Proof Key for Code Exchange for improved security with public clients. - **JWT Tokens** – Consider using JWT tokens with custom claims for enhanced security and portability. @@ -268,7 +268,7 @@ OAUTH2_PROVIDER = { - **Monitoring and Alerts** – Add monitoring for unusual token exchange patterns that might indicate attacks. - **Rate Limiting** – Implement token endpoint rate limiting to prevent brute force attacks. -## **Significance of Phase 4** +## Significance of Phase 4 This phase completes the secure authorization process and enables protected resource access: diff --git a/docs/oauth/phase-5-protected-resource-access.md b/docs/oauth/phase-5-protected-resource-access.md new file mode 100644 index 0000000..474a9bf --- /dev/null +++ b/docs/oauth/phase-5-protected-resource-access.md @@ -0,0 +1,280 @@ +# **Phase 5: Protected Resource Access** + +![Phase 5](../images/phase-5-protected-resource-access.png) + +## Overview + +Phase 5 represents the culmination of the OAuth 2.0 authorization flow, where the **Destination Service** uses the access token obtained in Phase 4 to securely access protected ActivityPub resources from the **Source Service**. This phase enables the actual data transfer that is the core purpose of LOLA account portability. + +In our implementation, Phase 5 introduces a unique **dual-mode authentication system** that allows the same API endpoints to serve both standard ActivityPub federation (unauthenticated) and enhanced LOLA portability data (authenticated with proper OAuth scope). This approach maintains backward compatibility while providing enriched data for authorized account transfers. + +## Objectives of Phase 5 + +- Enable secure access to protected ActivityPub resources using OAuth 2.0 access tokens. +- Provide **dual-mode operation** where the same endpoints serve different data based on authentication status. +- Implement **graceful degradation** that doesn't break standard ActivityPub federation when OAuth fails. +- Deliver **enhanced LOLA data** (private activities, portability endpoints) only to properly authenticated requests. +- Ensure **scope validation** so that only tokens with `activitypub_account_portability` scope unlock enhanced features. +- Maintain full **ActivityPub specification compliance** for both authenticated and unauthenticated requests. + +## Context in the LOLA Flow + +Within the LOLA portability process, Phase 5 is where the actual data retrieval occurs: + +- The **Destination Service** presents the access token to request user data from the Source Service. +- The **Source Service** validates the token and scope, then provides either basic ActivityPub data or enhanced LOLA data. +- Enhanced data includes **private activities**, **LOLA discovery endpoints**, and **account portability metadata**. +- The retrieved data is in **JSON-LD format**, ready for account recreation at the destination. + +This phase transforms the authorization (Phases 1-4) into actual data access, enabling the Destination Service to begin reconstructing the user's account with complete fidelity. + +## Core Components + +### 1. OptionalOAuth2Authentication + +Our custom authentication class enables dual-mode operation: + +```python +class OptionalOAuth2Authentication(OAuth2Authentication): + """ + Authentication class that makes OAuth2 authentication optional. + + This class allows API endpoints to function in two distinct modes: + 1. Unauthenticated Mode: For standard ActivityPub federation + 2. Authenticated Mode: For LOLA account portability with proper OAuth scope + """ + + LOLA_PORTABILITY_SCOPE = 'activitypub_account_portability' +``` + +**Key Features:** +- **Graceful Degradation:** Authentication failures don't cause API errors; requests continue as unauthenticated +- **Scope Validation:** Only tokens with `activitypub_account_portability` scope unlock LOLA features +- **Request Flags:** Adds `is_oauth_authenticated` and `has_portability_scope` flags to request objects +- **Flexible Authentication:** Supports both Authorization header and URL parameter authentication + +### 2. Protected Endpoints + +Two primary endpoints provide OAuth-protected access: + +#### **Actor Detail Endpoint** +- **URL:** `/api/actors//` +- **Unauthenticated:** Returns basic ActivityPub Person object +- **Authenticated with Portability Scope:** Adds LOLA discovery fields + +#### **Portability Outbox Endpoint** +- **URL:** `/api/actors//outbox/` +- **Unauthenticated:** Returns public activities only +- **Authenticated with Portability Scope:** Returns ALL activities (public + private) + +### 3. Authentication Context System + +The authentication system creates context flags that JSON-LD builders use for conditional data enhancement: + +```python +# Set by OptionalOAuth2Authentication +request.is_oauth_authenticated = True/False +request.has_portability_scope = True/False + +# Used by JSON-LD builders +auth_context = { + 'is_authenticated': getattr(request, 'is_oauth_authenticated', False), + 'has_portability_scope': getattr(request, 'has_portability_scope', False), + 'request': request +} +``` + +### 4. Enhanced Data Features + +#### **Actor Enhancements (LOLA Fields)** +When authenticated with portability scope, actor objects include: + +```json +{ + "accountPortabilityOauth": "https://source.example.com/oauth/authorize/", + "content": "https://source.example.com/api/actors/1/content", + "blocked": "https://source.example.com/api/actors/1/blocked", + "migration": "https://source.example.com/api/actors/1/outbox" +} +``` + +#### Outbox Content Filtering +- **Unauthenticated:** Only public activities (`visibility: "public"`) +- **Authenticated:** All activities including private, followers-only, etc. + +## Implementation Details + +### Token Authentication Process + +1. **Authorization Header Authentication** (Primary): + ```http + GET /api/actors/1/ HTTP/1.1 + Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9... + Accept: application/activity+json + ``` + +2. **URL Parameter Authentication** (Testing): + ```http + GET /api/actors/1/?auth_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9... + ``` + +### Authentication Flow + +```python +def authenticate(self, request): + # Initialize authentication flags + request.is_oauth_authenticated = False + request.has_portability_scope = False + + try: + # Try Authorization header first + result = super().authenticate(request) + + # Fallback to URL parameter for testing + if result is None: + result = self._authenticate_with_url_token(request) + + if result is not None: + user, token = result + request.is_oauth_authenticated = True + + # Check for LOLA portability scope + if self._has_portability_scope(token): + request.has_portability_scope = True + + return user, token + + except exceptions.AuthenticationFailed: + # Continue as unauthenticated - this is the key difference + pass + + return None # Allow unauthenticated requests +``` + +### JSON-LD Building with Authentication Context + +```python +def build_actor_json_ld(actor, auth_context=None): + # Base ActivityPub Actor (always included) + actor_data = { + "@context": build_actor_context(), + "type": "Person", + "id": build_actor_id(actor.id), + "preferredUsername": actor.username, + # Standard ActivityPub collections + "outbox": f"{build_actor_id(actor.id)}/outbox", + # ... + } + + # Add LOLA fields ONLY when authenticated with portability scope + if auth_context and auth_context.get('has_portability_scope'): + actor_data["accountPortabilityOauth"] = build_oauth_endpoint_url(auth_context['request']) + actor_data["content"] = f"{build_actor_id(actor.id)}/content" + actor_data["blocked"] = f"{build_actor_id(actor.id)}/blocked" + actor_data["migration"] = f"{build_actor_id(actor.id)}/outbox" + + return actor_data +``` + +### Activity Filtering Logic + +```python +def build_outbox_json_ld(outbox, auth_context=None): + all_activities = create_activities + like_activities + follow_activities + + # Filter content based on authentication and scope + if not auth_context or not auth_context.get('has_portability_scope'): + # Public only for unauthenticated requests + all_activities = [activity for activity in all_activities + if activity.visibility == 'public'] + # LOLA authenticated requests get ALL activities + + return { + "@context": build_basic_context(), + "type": "OrderedCollection", + "totalItems": len(all_activities), + "items": [build_activity_json_ld(activity) for activity in all_activities] + } +``` + +## Security Considerations + +- **Token Validation:** Every request validates the access token against the database and checks expiration +- **Scope Enforcement:** Enhanced LOLA data is only provided when the token explicitly includes `activitypub_account_portability` scope +- **Graceful Degradation:** Invalid tokens don't cause service failures, maintaining ActivityPub federation compatibility +- **Content-Type Validation:** Responses use proper `application/activity+json` content-type for ActivityPub compliance +- **CORS Headers:** `Access-Control-Allow-Origin: *` enables cross-origin federation while maintaining security through authentication + +## API Response Examples + +### **Unauthenticated Actor Request** +```json +{ + "@context": ["https://www.w3.org/ns/activitystreams"], + "type": "Person", + "id": "https://source.example.com/api/actors/1/", + "preferredUsername": "testuser", + "name": "testuser", + "inbox": "https://source.example.com/api/actors/1/inbox", + "outbox": "https://source.example.com/api/actors/1/outbox", + "followers": "https://source.example.com/api/actors/1/followers", + "following": "https://source.example.com/api/actors/1/following" +} +``` + +### Authenticated Actor Request (with Portability Scope) +```json +{ + "@context": ["https://www.w3.org/ns/activitystreams"], + "type": "Person", + "id": "https://source.example.com/api/actors/1/", + "preferredUsername": "testuser", + "name": "testuser", + "inbox": "https://source.example.com/api/actors/1/inbox", + "outbox": "https://source.example.com/api/actors/1/outbox", + "followers": "https://source.example.com/api/actors/1/followers", + "following": "https://source.example.com/api/actors/1/following", + "accountPortabilityOauth": "https://source.example.com/oauth/authorize/", + "content": "https://source.example.com/api/actors/1/content", + "blocked": "https://source.example.com/api/actors/1/blocked", + "migration": "https://source.example.com/api/actors/1/outbox" +} +``` + +## User Experience Flow + +1. **Destination Service Preparation:** Uses access token from Phase 4 in API requests +2. **API Request:** Includes `Authorization: Bearer ` header in HTTP requests +3. **Token Validation:** Source Service validates token and checks for portability scope +4. **Data Enhancement:** If valid scope, JSON-LD response includes LOLA-specific fields +5. **Data Retrieval:** Destination Service receives complete user data for account recreation +6. **Comparison Testing:** Same endpoints serve different data based on authentication status + +## Testing Capabilities + +Our implementation includes comprehensive testing features: + +- **URL Parameter Authentication:** `?auth_token=` for easy browser-based testing +- **Side-by-side Comparison:** Same endpoint with/without authentication shows data differences +- **Scope Validation Testing:** Tokens without portability scope behave like unauthenticated requests +- **DRF Browsable API:** Web interface for testing with proper content-type handling + +## Future Enhancements + +- **Rate Limiting:** Implement per-token rate limiting to prevent abuse +- **Detailed Activity Streams:** Add pagination support for large outboxes +- **Additional LOLA Endpoints:** Implement `/content`, `/blocked`, and other discovery endpoints +- **Caching:** Add token validation caching to improve performance +- **Enhanced Logging:** Add detailed access logging for security auditing + +## Significance of Phase 5 + +Phase 5 completes the OAuth 2.0 flow and enables the core LOLA functionality: + +- **Unified API Design:** Same endpoints serve both ActivityPub federation and LOLA portability +- **Backward Compatibility:** Standard ActivityPub clients continue to work unchanged +- **Enhanced Data Access:** Authorized clients receive complete account data including private content +- **Secure Token Usage:** Proper scope validation ensures only authorized access to sensitive data +- **JSON-LD Compliance:** All responses conform to ActivityPub and LOLA specifications + +With Phase 5 complete, the OAuth implementation provides a secure, standards-compliant foundation for ActivityPub account portability that maintains full compatibility with existing federation while enabling enhanced data access for authorized account transfers.