Chris Coutinho
|
403f8be429
|
feat: Add Keycloak external IdP integration with custom scopes
Add comprehensive support for using Keycloak as an external identity
provider with Nextcloud custom scopes. This enables testing of ADR-002
external IdP integration patterns.
**Keycloak Realm Configuration:**
- Add frontendUrl attribute to issue tokens with public issuer URL
- Define 18 Nextcloud custom client scopes (notes:read/write,
calendar:read/write, contacts:read/write, cookbook:read/write,
deck:read/write, tables:read/write, files:read/write,
sharing:read/write, todo:read/write)
- Add all custom scopes to nextcloud-mcp-server client optional scopes
- Scopes include consent screen text for user-friendly OAuth flow
**MCP Server Configuration:**
- Add OIDC_JWKS_URI environment variable support
- Implement JWKS URI override logic for Docker networking
- Update NEXTCLOUD_PUBLIC_ISSUER_URL to include full realm path
- Enable MCP server to fetch JWKS from internal Docker network
**Test Infrastructure:**
- Add keycloak_oauth_client_credentials fixture (session-scoped)
- Add keycloak_oauth_token fixture with Playwright automation
- Implement PKCE (S256) support for Keycloak OAuth flow
- Add nc_mcp_keycloak_client fixture for MCP testing
- Create comprehensive test suite in test_keycloak_external_idp.py
**Tests Created:**
- test_keycloak_oauth_token_acquisition: Token acquisition via Playwright
- test_keycloak_oauth_client_credentials_discovery: OIDC discovery
- test_mcp_client_connects_to_keycloak_server: MCP connectivity
- test_external_idp_server_initialization: Server auto-detection
- test_external_idp_token_validation: Token validation flow
- test_tools_work_with_keycloak_token: End-to-end tool execution
- test_keycloak_token_persistence: Multi-operation token reuse
- test_user_auto_provisioning: Nextcloud user provisioning
- test_scope_filtering_with_keycloak: Scope-based tool filtering
- test_keycloak_error_handling: Error handling
- test_external_idp_architecture: Architecture documentation
**Current Status:**
- ✅ Keycloak realm configuration complete
- ✅ Custom scopes defined and available
- ✅ OAuth token acquisition working (1 test passing)
- ⚠️ Token validation needs additional work (external IdP userinfo)
**Files Modified:**
- keycloak/realm-export.json: Realm configuration with scopes
- tests/conftest.py: Keycloak OAuth fixtures (+285 lines)
- tests/server/oauth/test_keycloak_external_idp.py: New test suite
- docker-compose.yml: OIDC_JWKS_URI and issuer configuration
- nextcloud_mcp_server/app.py: JWKS URI override logic
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
|
2025-11-02 22:03:20 +01:00 |
|
Chris Coutinho
|
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>
|
2025-11-02 22:03:19 +01:00 |
|
github-actions[bot]
|
5259658458
|
bump: version 0.22.6 → 0.22.7
|
2025-10-29 11:18:41 +00:00 |
|
github-actions[bot]
|
e1aca04aff
|
bump: version 0.22.5 → 0.22.6
|
2025-10-29 10:57:44 +00:00 |
|
github-actions[bot]
|
e647c87dd8
|
bump: version 0.22.4 → 0.22.5
|
2025-10-29 10:54:54 +00:00 |
|
github-actions[bot]
|
202058bdc8
|
bump: version 0.22.3 → 0.22.4
|
2025-10-29 10:44:11 +00:00 |
|
Chris Coutinho
|
e602684743
|
fix(helm): Update helm version with release
|
2025-10-29 11:43:02 +01:00 |
|
github-actions[bot]
|
8221046d8a
|
bump: version 0.22.2 → 0.22.3
|
2025-10-29 10:35:58 +00:00 |
|
Chris Coutinho
|
3e45b6ca25
|
fix(helm): Update helm version with release
|
2025-10-29 11:34:58 +01:00 |
|
github-actions[bot]
|
9ec7637579
|
bump: version 0.22.1 → 0.22.2
|
2025-10-29 10:30:39 +00:00 |
|
Chris Coutinho
|
670188f9e4
|
fix(helm): Update helm version with release
|
2025-10-29 11:29:59 +01:00 |
|
github-actions[bot]
|
3878beaf65
|
bump: version 0.22.0 → 0.22.1
|
2025-10-29 10:17:08 +00:00 |
|
github-actions[bot]
|
0e7e74867f
|
bump: version 0.21.0 → 0.22.0
|
2025-10-29 09:32:27 +00:00 |
|
github-actions[bot]
|
57a2157c58
|
bump: version 0.20.0 → 0.21.0
|
2025-10-25 18:33:56 +00:00 |
|
yuisheaven
|
f0e5333e43
|
Merge branch 'master' into feature/introduce_files_parsing_with_unstructured_service_for_webdav_files_retrieval
|
2025-10-25 17:23:38 +02:00 |
|
github-actions[bot]
|
04e0ab127a
|
bump: version 0.19.1 → 0.20.0
|
2025-10-24 18:24:45 +00:00 |
|
Chris Coutinho
|
1117a83a52
|
Merge pull request #237 from cbcoutinho/feature/app-scopes
Feature/app scopes
|
2025-10-24 20:24:15 +02:00 |
|
github-actions[bot]
|
50a824155c
|
bump: version 0.19.0 → 0.19.1
|
2025-10-24 04:36:51 +00:00 |
|
renovate-bot-cbcoutinho[bot]
|
3baf10662f
|
fix(deps): update dependency mcp to >=1.19,<1.20
|
2025-10-24 04:06:55 +00:00 |
|
Chris Coutinho
|
d452684535
|
feat: Split read/write scopes into app:read/write scopes
|
2025-10-24 04:38:49 +02:00 |
|
github-actions[bot]
|
bfbaed9a66
|
bump: version 0.18.0 → 0.19.0
|
2025-10-23 23:50:51 +00:00 |
|
yuisheaven
|
29df645d53
|
Merge branch 'master' into feature/introduce_files_parsing_with_unstructured_service_for_webdav_files_retrieval
|
2025-10-23 21:30:09 +02:00 |
|
github-actions[bot]
|
87c6f077f3
|
bump: version 0.17.1 → 0.18.0
|
2025-10-23 10:23:48 +00:00 |
|
Chris Coutinho
|
e48f5f3f30
|
feat(server): Add support for custom OIDC scopes and permissions via JWTs
|
2025-10-23 08:37:36 +02:00 |
|
Chris Coutinho
|
c069d78f80
|
feat: Initialize JWT-scoped tools
|
2025-10-22 06:21:16 +02:00 |
|
yuisheaven
|
64649c902d
|
Merge branch 'master' into feature/introduce_files_parsing_with_unstructured_service_for_webdav_files_retrieval
|
2025-10-21 20:37:00 +02:00 |
|
github-actions[bot]
|
4984496d81
|
bump: version 0.17.0 → 0.17.1
|
2025-10-20 21:16:09 +00:00 |
|
Chris Coutinho
|
989b6de3c0
|
build: Switch to uv build backend
|
2025-10-20 20:10:57 +02:00 |
|
Chris Coutinho
|
aa0b6dc5dd
|
docs: Update docs
|
2025-10-20 19:10:23 +02:00 |
|
github-actions[bot]
|
45bbf97033
|
bump: version 0.16.0 → 0.17.0
|
2025-10-19 22:55:23 +00:00 |
|
Chris Coutinho
|
d398a8c8e6
|
refactor: Migrate from internal CalendarClient to caldav library
|
2025-10-19 15:47:17 +02:00 |
|
github-actions[bot]
|
cb7a609ec2
|
bump: version 0.15.2 → 0.16.0
|
2025-10-19 00:13:49 +00:00 |
|
Chris Coutinho
|
d5e6411c45
|
test: disable asyncio fixture
|
2025-10-19 00:49:24 +02:00 |
|
Chris Coutinho
|
b72514bb32
|
ci: Add pytest-timeout to dev deps
|
2025-10-19 00:27:19 +02:00 |
|
Chris Coutinho
|
1459fe9bc8
|
test: Replace pytest-asyncio plugin fixtures with anyio fixtures
|
2025-10-18 22:02:25 +02:00 |
|
Chris Coutinho
|
37164dbdbc
|
chore: sort imports
|
2025-10-18 22:02:25 +02:00 |
|
github-actions[bot]
|
a389f2940e
|
bump: version 0.15.1 → 0.15.2
|
2025-10-17 23:17:32 +00:00 |
|
github-actions[bot]
|
7549c988f4
|
bump: version 0.15.0 → 0.15.1
|
2025-10-17 02:49:37 +00:00 |
|
github-actions[bot]
|
0aeef1b87e
|
bump: version 0.14.3 → 0.15.0
|
2025-10-17 01:25:56 +00:00 |
|
github-actions[bot]
|
6734de8389
|
bump: version 0.14.2 → 0.14.3
|
2025-10-17 00:04:25 +00:00 |
|
renovate-bot-cbcoutinho[bot]
|
16b9123af3
|
fix(deps): update dependency mcp to >=1.18,<1.19
|
2025-10-16 19:20:47 +00:00 |
|
github-actions[bot]
|
e0a68d47a5
|
bump: version 0.14.1 → 0.14.2
|
2025-10-16 08:32:29 +00:00 |
|
renovate-bot-cbcoutinho[bot]
|
7b2002c1b5
|
fix(deps): update dependency pillow to v12
|
2025-10-15 22:09:01 +00:00 |
|
github-actions[bot]
|
9e4c20a4b1
|
bump: version 0.14.0 → 0.14.1
|
2025-10-15 15:26:35 +00:00 |
|
Chris Coutinho
|
3ad9198f36
|
fix(oauth): Remove the option to force_register new clients
|
2025-10-15 16:27:22 +02:00 |
|
github-actions[bot]
|
46deb0f726
|
bump: version 0.13.0 → 0.14.0
|
2025-10-15 09:53:45 +00:00 |
|
github-actions[bot]
|
52044ef053
|
bump: version 0.12.6 → 0.13.0
|
2025-10-13 23:30:55 +00:00 |
|
Chris Coutinho
|
37b0577bfd
|
test: Add asyncio tests using Playwright
|
2025-10-14 01:23:38 +02:00 |
|
Chris Coutinho
|
b3b7c90bd0
|
chore: Move httpd server to separate fixture
|
2025-10-14 01:23:32 +02:00 |
|
Chris Coutinho
|
879cd58db1
|
test: rename interactive mark to oauth
|
2025-10-14 01:23:31 +02:00 |
|