From 6379231a2116ff197f6d606811f542c6abc39050 Mon Sep 17 00:00:00 2001 From: simonredfern Date: Mon, 29 Dec 2025 17:24:45 +0100 Subject: [PATCH] debug/providers-status --- components.d.ts | 2 + server/routes/status.ts | 72 +- .../debug/providers-status/+page.svelte | 626 ++++++++++++++++++ 3 files changed, 699 insertions(+), 1 deletion(-) create mode 100644 src/routes/debug/providers-status/+page.svelte diff --git a/components.d.ts b/components.d.ts index b02e0e2..a436ca1 100644 --- a/components.d.ts +++ b/components.d.ts @@ -18,6 +18,7 @@ declare module 'vue' { ElAside: typeof import('element-plus/es')['ElAside'] ElBacktop: typeof import('element-plus/es')['ElBacktop'] ElButton: typeof import('element-plus/es')['ElButton'] + ElCard: typeof import('element-plus/es')['ElCard'] ElCol: typeof import('element-plus/es')['ElCol'] ElCollapse: typeof import('element-plus/es')['ElCollapse'] ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem'] @@ -27,6 +28,7 @@ declare module 'vue' { ElDropdown: typeof import('element-plus/es')['ElDropdown'] ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu'] + ElEmpty: typeof import('element-plus/es')['ElEmpty'] ElFooter: typeof import('element-plus/es')['ElFooter'] ElForm: typeof import('element-plus/es')['ElForm'] ElFormItem: typeof import('element-plus/es')['ElFormItem'] diff --git a/server/routes/status.ts b/server/routes/status.ts index 9c8c7b2..7d5124a 100644 --- a/server/routes/status.ts +++ b/server/routes/status.ts @@ -30,6 +30,7 @@ import type { Request, Response } from 'express' import { Container } from 'typedi' import OBPClientService from '../services/OBPClientService.js' import { OAuth2Service } from '../services/OAuth2Service.js' +import { OAuth2ProviderManager } from '../services/OAuth2ProviderManager.js' import { commitId } from '../app.js' import { RESOURCE_DOCS_API_VERSION, @@ -42,8 +43,14 @@ const router = Router() // Get services from container const obpClientService = Container.get(OBPClientService) const oauth2Service = Container.get(OAuth2Service) +const providerManager = Container.get(OAuth2ProviderManager) -const connectors = ['akka_vDec2018', 'rest_vMar2019', 'stored_procedure_vDec2019', 'rabbitmq_vOct2024'] +const connectors = [ + 'akka_vDec2018', + 'rest_vMar2019', + 'stored_procedure_vDec2019', + 'rabbitmq_vOct2024' +] /** * Helper function to check if response contains an error @@ -225,4 +232,67 @@ router.get('/status/oauth2/reconnect', async (req: Request, res: Response) => { } }) +/** + * GET /status/providers + * Get configured OAuth2 providers (for debugging) + * Shows provider configuration with masked credentials + */ +router.get('/status/providers', (req: Request, res: Response) => { + try { + // Helper function to mask sensitive data (show first 3 and last 3 chars) + const maskCredential = (value: string | undefined): string => { + if (!value || value.length < 8) { + return value ? '***masked***' : 'not configured' + } + return `${value.substring(0, 3)}...${value.substring(value.length - 3)}` + } + + // Get providers from manager + const availableProviders = providerManager.getAvailableProviders() + const allProviderStatus = providerManager.getAllProviderStatus() + + // Get env configuration (masked) + const envConfig = { + obpOidc: { + clientId: maskCredential(process.env.VITE_OBP_OAUTH2_CLIENT_ID), + wellKnownUrl: process.env.VITE_OBP_OAUTH2_WELL_KNOWN_URL || 'not configured', + redirectUrl: process.env.VITE_OBP_OAUTH2_REDIRECT_URL || 'not configured' + }, + keycloak: { + clientId: maskCredential(process.env.VITE_KEYCLOAK_CLIENT_ID), + redirectUrl: process.env.VITE_KEYCLOAK_REDIRECT_URL || 'not configured' + }, + google: { + clientId: maskCredential(process.env.VITE_GOOGLE_CLIENT_ID), + redirectUrl: process.env.VITE_GOOGLE_REDIRECT_URL || 'not configured' + }, + github: { + clientId: maskCredential(process.env.VITE_GITHUB_CLIENT_ID), + redirectUrl: process.env.VITE_GITHUB_REDIRECT_URL || 'not configured' + }, + custom: { + providerName: process.env.VITE_CUSTOM_OIDC_PROVIDER_NAME || 'not configured', + clientId: maskCredential(process.env.VITE_CUSTOM_OIDC_CLIENT_ID), + redirectUrl: process.env.VITE_CUSTOM_OIDC_REDIRECT_URL || 'not configured' + } + } + + res.json({ + summary: { + totalConfigured: availableProviders.length, + availableProviders: availableProviders, + obpApiHost: process.env.VITE_OBP_API_HOST || 'not configured' + }, + providerStatus: allProviderStatus, + environmentConfig: envConfig, + note: 'Credentials are masked for security. Format: first3...last3' + }) + } catch (error) { + console.error('Status: Error getting provider status:', error) + res.status(500).json({ + error: error instanceof Error ? error.message : 'Unknown error' + }) + } +}) + export default router diff --git a/src/routes/debug/providers-status/+page.svelte b/src/routes/debug/providers-status/+page.svelte new file mode 100644 index 0000000..acae0d0 --- /dev/null +++ b/src/routes/debug/providers-status/+page.svelte @@ -0,0 +1,626 @@ + + + + + + OAuth2 Provider Configuration Status + + +
+

OAuth2 Provider Configuration Status

+ +
+

This page shows which OAuth2/OIDC identity providers are configured and available for login.

+

Note: Client secrets are masked for security.

+
+ + {#if loading} +
+
+ Loading provider status... +
+ {:else if error} +
+

Error loading provider status:

+

{error}

+
+ {:else if status} +
+ +
+
+ Summary + +
+
+
+ + {status.summary.totalConfigured} +
+
+ + {status.summary.availableProviders.join(', ') || 'None'} +
+
+ + {status.summary.obpApiHost} +
+
+
+ + +

Active Providers

+ {#if status.providerStatus.length === 0} +
+

No providers configured

+ + View Setup Guide + +
+ {:else} +
+ {#each status.providerStatus as provider (provider.name)} +
+
+ {getProviderDisplayName(provider.name)} + + {provider.status} + +
+
+
+ + {provider.name} +
+
+ + + {provider.available ? 'Available' : 'Unavailable'} + +
+
+ + {formatDate(provider.lastChecked)} +
+ {#if provider.error} +
+ + {provider.error} +
+ {/if} +
+
+ {/each} +
+ {/if} + + +

Environment Configuration

+
+ {#each Object.entries(status.environmentConfig) as [providerKey, config]} +
+ + {#if expandedProviders.has(providerKey)} +
+ {#each Object.entries(config) as [key, value]} +
+ + {value} +
+ {/each} +
+ {/if} +
+ {/each} +
+ +
+ ℹ️ + {status.note} +
+
+ {/if} +
+ +