feature/helm-chart-multi-user-basic-support
4 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
babd60e08b |
feat: Implement ADR-004 Hybrid Flow with comprehensive integration tests
Implement the ADR-004 Hybrid Flow OAuth pattern where the MCP server intercepts the OAuth callback to obtain master refresh tokens while maintaining PKCE security for clients. ## Implementation ### OAuth Routes (ADR-004 Hybrid Flow) - Add `/oauth/authorize` endpoint: Intercepts client OAuth initiation - Add `/oauth/callback` endpoint: Receives IdP callback, stores master token - Add `/oauth/token` endpoint: Exchanges MCP code for client access token - Implement PKCE code challenge/verifier validation - Store OAuth sessions with state/challenge correlation ### MCP Server Integration - Update `setup_oauth_config()` to return client_id and client_secret - Initialize OAuth context in Starlette lifespan for login routes - Add OAuth session storage to RefreshTokenStorage - Configure authlib dependency for OAuth flow management ### Integration Tests - Create `test_adr004_hybrid_flow.py` with Playwright automation - Add `adr004_hybrid_flow_mcp_client` session-scoped fixture - Test MCP session establishment with hybrid flow token - Test tool execution using stored refresh tokens (on-behalf-of pattern) - Test persistent access across multiple operations - All tests passing: ✅ 3 passed in 8.82s ### Documentation - Update ADR-004 with comprehensive Testing section - Add integration test commands and coverage details - Document test implementation and verification steps - Create TESTING_INSTRUCTIONS.md for manual and automated testing - Include manual test scripts for reference/debugging ## What This Enables ✅ PKCE code challenge/verifier flow ✅ MCP server intercepts OAuth callback and stores master refresh token ✅ Client receives MCP access token (not master token) ✅ MCP session establishment with hybrid flow token ✅ Tool execution using stored refresh tokens (on-behalf-of pattern) ✅ Multiple operations without re-authentication ✅ Proper token isolation (client never sees master token) ## Testing Run ADR-004 integration tests: ```bash uv run pytest tests/server/oauth/test_adr004_hybrid_flow.py --browser firefox -v ``` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> |
||
|
|
34df5f5b9a |
feat: Implement dual-tier token exchange (Standard V2 + Legacy V1 impersonation)
This commit implements and documents both RFC 8693 token exchange tiers from ADR-002, enabling both production-ready delegation and advanced impersonation capabilities. - Enable Keycloak preview features (`--features=preview`) to support both Standard V2 and Legacy V1 token exchange modes - Update Tier 1 status from "NOT IMPLEMENTED" to "IMPLEMENTED (Legacy V1)" - Add detailed empirical testing results showing: - Standard V2 rejects `requested_subject` parameter - Legacy V1 accepts parameter but requires impersonation permissions - Complete configuration steps for enabling impersonation - Add comparison table showing when to use each tier - Add "When to Use" guidance for both tiers - Document that Tier 2 (Delegation) is the recommended default - Update docstring to document both Tier 1 and Tier 2 support - Add tier-specific logging (shows which tier is being used) - Document permission requirements for Tier 1 impersonation **tests/integration/auth/test_token_exchange_standard_v2.py**: - Test delegation without impersonation (Tier 2) - Verify sub claim remains unchanged (service account identity) - Verify no special permissions required - Test exchanged tokens work with Nextcloud APIs - All tests PASS ✅ **tests/integration/auth/test_token_exchange_legacy_v1.py**: - Test impersonation with `requested_subject` (Tier 1) - Verify sub claim changes to target user - Auto-skip if impersonation permissions not configured - Document permission requirements in test docstrings - Test exchanged tokens work with Nextcloud APIs **tests/manual/test_impersonation.py**: - Comprehensive impersonation validation script - Tests both Standard V2 and Legacy V1 behavior - Decodes JWT tokens to verify sub claim changes - Validates tokens against Nextcloud APIs **tests/manual/configure_impersonation.py**: - Automated permission configuration helper - Documents manual Keycloak CLI configuration steps Both token exchange tiers are now fully implemented and tested: - **Tier 2 (Delegation)** - ✅ RECOMMENDED - Standard V2 (production-ready) - No special permissions required - Service account identity preserved - **Tier 1 (Impersonation)** - ✅ Advanced use only - Legacy V1 (--features=preview required) - Requires manual permission grant via Keycloak CLI - Subject claim changes to target user 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> |
||
|
|
e26c5128b7 |
docs: Reject service account tokens as OAuth authentication pattern
Service account tokens (client_credentials grant) violate OAuth "act on-behalf-of" principles and have been moved to ADR-002's "Will Not Implement" section. ## Problem Discovery Testing revealed that service account tokens create Nextcloud user accounts (e.g., `service-account-nextcloud-mcp-server`) due to user_oidc's bearer provisioning feature. This violates core OAuth principles: - ❌ Creates stateful server identity in Nextcloud - ❌ All actions attributed to service account, not real user - ❌ Breaks audit trail and user attribution - ❌ Service account becomes "admin by another name" ## Changes ### Documentation (ADR-002) - Moved service account (old Tier 1) to "Will Not Implement" section - Added "OAuth Act On-Behalf-Of Principle" section - Renumbered tiers: - Tier 1: Impersonation (NOT IMPLEMENTED) - Tier 2: Delegation via token exchange (IMPLEMENTED) - Updated status to reflect rejection of service accounts ### Code Warnings - Added comprehensive warning to KeycloakOAuthClient.get_service_account_token() - Clarified VALID use: only as subject_token for RFC 8693 token exchange - Clarified INVALID use: direct API access with service account token ### Supporting Documentation - CLAUDE.md: Removed outdated "Tier 1" references, added rejection note - oauth-impersonation-findings.md: Added prominent update banner - audience-validation-setup.md: Updated tier numbers, added rejection note - tests/manual/test_token_exchange.py: Added warning comment ## Valid Patterns (ADR-002) ✅ Foreground operations: User's access token from MCP request ✅ Background operations: Token exchange (impersonation/delegation) ✅ Offline access: Refresh tokens with user consent ❌ Service accounts: Creates independent server identity (REJECTED) ## Alternative If service account pattern is truly needed, use BasicAuth mode instead of OAuth mode. OAuth mode MUST maintain "act on-behalf-of" semantics. Related: c12df98 (revert of service account test) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> |
||
|
|
e331544cee |
feat: Implement RFC 8693 token exchange for Keycloak (ADR-002 Tier 2)
Implements OAuth 2.0 Token Exchange (RFC 8693) enabling the MCP server to exchange service account tokens for user-scoped tokens. This provides an alternative to refresh tokens for background operations. **Core Implementation:** - Added `get_service_account_token()` method to KeycloakOAuthClient for client_credentials grant - Added `exchange_token_for_user()` method implementing RFC 8693 token exchange - Fixed Fernet encryption key handling in RefreshTokenStorage (was incorrectly base64 decoding already-encoded keys) - Updated OAuth configuration to support offline_access scope and refresh token storage infrastructure **Keycloak Configuration:** - Enabled `serviceAccountsEnabled` in realm-export.json - Added `token.exchange.grant.enabled` attribute - Added `client.token.exchange.standard.enabled` attribute (required for Keycloak 26.2+ Standard Token Exchange V2) - Fresh Keycloak imports now correctly enable token exchange **Docker Compose:** - Added TOKEN_ENCRYPTION_KEY and ENABLE_OFFLINE_ACCESS environment variables - Created oauth-tokens volume for refresh token storage - Configured both mcp-oauth and mcp-keycloak services **Testing & Documentation:** - Added tests/manual/test_token_exchange.py - Validates complete RFC 8693 flow - Added tests/manual/test_nextcloud_impersonate.py - Documents session-based impersonation limitations - Added docs/oauth-impersonation-findings.md - Comprehensive investigation findings and resolution documentation **Verified Working:** ✅ Service account token acquisition (client_credentials grant) ✅ RFC 8693 token exchange for internal-to-internal tokens ✅ Exchanged tokens validate with Nextcloud APIs ✅ Keycloak 26.4.2 Standard Token Exchange V2 support **Known Limitations:** - User impersonation (requested_subject) requires Keycloak Legacy V1 with preview features - Cross-client token exchange limited to same realm - Refresh token storage infrastructure ready but unused (MCP protocol limitation) Dependencies: aiosqlite>=0.20.0 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> |