Files
nextcloud-mcp-server/app-hooks/post-installation/10-install-oidc-app.sh
Chris Coutinho 9fab6cb550 feat: Implement ADR-005 unified token verifier to eliminate token passthrough vulnerability
Replace two non-compliant token verifiers (NextcloudTokenVerifier and
ProgressiveConsentTokenVerifier) with a single UnifiedTokenVerifier that properly
validates token audiences per MCP Security Best Practices specification.

The previous implementation had a critical security vulnerability where tokens
intended for the MCP server were passed directly to Nextcloud APIs without
proper audience validation (token passthrough anti-pattern). This violates
OAuth 2.0 security principles and the MCP specification.

Changes:
- Add UnifiedTokenVerifier supporting two compliant modes:
  * Multi-audience mode (default): Validates tokens contain BOTH MCP and
    Nextcloud audiences, enabling direct use without exchange
  * Token exchange mode (opt-in): Validates MCP audience only, exchanges
    for Nextcloud tokens via RFC 8693 with caching to minimize latency

- Remove token passthrough vulnerability from context.py and context_helper.py
- Implement token exchange caching (5-minute TTL default) to reduce network calls
- Add required environment variables for audience validation:
  * NEXTCLOUD_MCP_SERVER_URL - MCP server URL (used as audience)
  * NEXTCLOUD_RESOURCE_URI - Nextcloud resource identifier
  * TOKEN_EXCHANGE_CACHE_TTL - Cache TTL for exchanged tokens

- Update docker-compose.yml with resource URI configuration for both OAuth modes
- Add comprehensive test suite (29 tests) covering both authentication modes
- Remove legacy NextcloudTokenVerifier and ProgressiveConsentTokenVerifier

Security improvements:
- Eliminates token passthrough anti-pattern
- Enforces proper audience separation between MCP and Nextcloud
- Complies with MCP Security Best Practices and RFC 8707/8693
- Maintains performance with token exchange caching

Test results: 65/65 unit tests passed, 5/5 smoke tests passed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-05 18:53:14 +01:00

41 lines
1.7 KiB
Bash
Executable File

#!/bin/bash
set -euox pipefail
echo "Installing and configuring OIDC app for testing..."
# Check if development OIDC app is mounted at /opt/apps/oidc
if [ -d /opt/apps/oidc ]; then
echo "Development OIDC app found at /opt/apps/oidc"
# Remove any existing OIDC app in custom_apps (from app store or old symlink)
if [ -e /var/www/html/custom_apps/oidc ]; then
echo "Removing existing OIDC in custom_apps..."
rm -rf /var/www/html/custom_apps/oidc
fi
# Create symlink from custom_apps to the mounted development version
# Per Nextcloud docs: apps outside server root need symlinks in server root
echo "Creating symlink: custom_apps/oidc -> /opt/apps/oidc"
ln -sf /opt/apps/oidc /var/www/html/custom_apps/oidc
echo "Enabling OIDC app from /opt/apps (development mode via symlink)"
php /var/www/html/occ app:enable oidc
elif [ -d /var/www/html/custom_apps/oidc ]; then
echo "OIDC app directory found in custom_apps (already installed)"
php /var/www/html/occ app:enable oidc
else
echo "OIDC app not found, installing from app store..."
php /var/www/html/occ app:install oidc
php /var/www/html/occ app:enable oidc
fi
# Configure OIDC Identity Provider with dynamic client registration enabled
php /var/www/html/occ config:app:set oidc dynamic_client_registration --value='true' # NOTE: String
php /var/www/html/occ config:app:set oidc proof_key_for_code_exchange --value=true --type=boolean
php /var/www/html/occ config:app:set oidc allow_user_settings --value='enabled'
php /var/www/html/occ config:app:set oidc default_token_type --value='jwt'
php /var/www/html/occ config:app:set oidc default_resource_identifier --value='http://localhost:8080'
echo "OIDC app installed and configured successfully"