test: Add automated test for service account token acquisition (ADR-002 Tier 1)

Add comprehensive automated integration test for Keycloak service account
token acquisition via client_credentials grant, validating ADR-002 Tier 1
implementation for external IdP mode.

Changes:
- Add keycloak_oauth_client fixture in tests/conftest.py
  - Creates KeycloakOAuthClient instance for service account operations
  - Session-scoped fixture with automatic cleanup
  - Discovers Keycloak endpoints automatically

- Add test_keycloak_service_account_token_acquisition test
  - Tests client_credentials grant token acquisition
  - Verifies token response structure (access_token, token_type, expires_in)
  - Validates token works with Nextcloud APIs via capabilities endpoint
  - Documents limitation for Nextcloud OIDC app (integrated mode)

- Update ADR-002 documentation
  - Mark automated test as complete ()
  - Document supported providers (Keycloak , Nextcloud OIDC app )
  - Add note that KeycloakOAuthClient is provider-agnostic
  - Clarify that Nextcloud OIDC app support requires config only

Test results:
-  Service account token acquired successfully (300s expiry, Bearer type)
-  Token validated by Nextcloud user_oidc app
-  Token works with Nextcloud capabilities API

Note: Nextcloud OIDC app (integrated mode) service account token support
not yet implemented. See app.py:631-635 for current status.

Resolves: "TODO: Automated integration tests needed for both Keycloak and
Nextcloud OIDC app" from ADR-002
This commit is contained in:
Chris Coutinho
2025-11-02 22:03:22 +01:00
parent 76430bec21
commit 1e071c83a9
3 changed files with 136 additions and 2 deletions
+53
View File
@@ -2526,6 +2526,59 @@ async def keycloak_oauth_client_credentials(anyio_backend, oauth_callback_server
# No cleanup needed - client is pre-configured in realm export
@pytest.fixture(scope="session")
async def keycloak_oauth_client(anyio_backend, keycloak_oauth_client_credentials):
"""
Fixture to create a KeycloakOAuthClient instance for service account token operations.
This fixture is used to test ADR-002 Tier 1 (service account token acquisition) and
Tier 3 (token exchange with delegation).
Returns:
KeycloakOAuthClient instance configured with Keycloak credentials
"""
from nextcloud_mcp_server.auth.keycloak_oauth import KeycloakOAuthClient
# Get Keycloak configuration from environment
keycloak_discovery_url = os.getenv(
"OIDC_DISCOVERY_URL",
"http://localhost:8888/realms/nextcloud-mcp/.well-known/openid-configuration",
)
# Extract base URL and realm from discovery URL
# Format: http://keycloak:8080/realms/nextcloud-mcp/.well-known/openid-configuration
if "/realms/" in keycloak_discovery_url:
base_url = keycloak_discovery_url.split("/realms/")[0]
realm = keycloak_discovery_url.split("/realms/")[1].split("/")[0]
else:
pytest.skip("Invalid Keycloak discovery URL format")
client_id, client_secret, callback_url, _, _ = keycloak_oauth_client_credentials
logger.info("Creating KeycloakOAuthClient for service account operations...")
logger.info(f" Keycloak URL: {base_url}")
logger.info(f" Realm: {realm}")
logger.info(f" Client ID: {client_id}")
oauth_client = KeycloakOAuthClient(
keycloak_url=base_url,
realm=realm,
client_id=client_id,
client_secret=client_secret,
redirect_uri=callback_url,
)
# Discover endpoints
await oauth_client.discover()
logger.info("✓ KeycloakOAuthClient initialized")
logger.info(f" Token endpoint: {oauth_client.token_endpoint}")
yield oauth_client
# Cleanup (close http client if needed)
await oauth_client.close()
async def _get_keycloak_oauth_token(
browser,
keycloak_oauth_client_credentials,