diff --git a/migrations/20250713133718-oidcClients-separate-ids-for-oidc-proxyauth.js b/migrations/20250713133718-oidcClients-separate-ids-for-oidc-proxyauth.js new file mode 100644 index 000000000..0e8245610 --- /dev/null +++ b/migrations/20250713133718-oidcClients-separate-ids-for-oidc-proxyauth.js @@ -0,0 +1,18 @@ +'use strict'; + +exports.up = async function (db) { + const allApps = await db.runSql('SELECT * FROM apps'); + + for (const app of allApps) { + const manifest = JSON.parse(app.manifestJson); + // assume apps only have one of them + if (manifest.addons.oidc) { + await db.runSql('UPDATE oidcClients SET id=? WHERE id=?', [ `${app.id}-oidc`, app.id ]); + } else { + await db.runSql('UPDATE oidcClients SET id=? WHERE id=?', [ `${app.id}-proxyauth`, app.id ]); + } + } +}; + +exports.down = async function (db) { +}; diff --git a/src/services.js b/src/services.js index 34c534f8f..846bc19c6 100644 --- a/src/services.js +++ b/src/services.js @@ -1827,17 +1827,16 @@ async function setupProxyAuth(app, options) { debug('Creating OpenID client for proxyAuth'); - // openid client_id is appId for now - const result = await oidcClients.get(app.id); + const proxyAuthClientId = `${app.id}-proxyauth`; + const result = await oidcClients.get(proxyAuthClientId); - // ensure we keep the secret const data = { - id: app.id, - secret: result ? result.secret : hat(4 * 128), + id: proxyAuthClientId, + secret: result ? result.secret : hat(4 * 128), // ensure we keep the secret loginRedirectUri: `https://${app.fqdn}/callback`, logoutRedirectUri: '', tokenSignatureAlgorithm: 'RS256', - name: '', + name: 'ProxyAuth Addon', appId: app.id }; @@ -1853,7 +1852,9 @@ async function teardownProxyAuth(app, options) { debug('Deleting OpenID client for proxyAuth'); - const [error] = await safe(oidcClients.del(app.id)); + const proxyAuthClientId = `${app.id}-proxyauth`; + + const [error] = await safe(oidcClients.del(proxyAuthClientId)); if (error && error.reason !== BoxError.NOT_FOUND) throw error; } @@ -2145,18 +2146,18 @@ async function setupOidc(app, options) { debug('Setting up OIDC'); - // openid client_id is appId for now - const [error, result] = await safe(oidcClients.get(app.id)); + const oidcAddonClientId = `${app.id}-oidc`; + const [error, result] = await safe(oidcClients.get(oidcAddonClientId)); if (error) throw error; // ensure we keep the secret const data = { - id: app.id, + id: oidcAddonClientId, secret: result ? result.secret : hat(4 * 128), loginRedirectUri: options.loginRedirectUri || '', logoutRedirectUri: options.logoutRedirectUri || '', tokenSignatureAlgorithm: options.tokenSignatureAlgorithm || 'RS256', - name: '', + name: 'OIDC Addon', appId: app.id }; @@ -2170,7 +2171,9 @@ async function teardownOidc(app, options) { debug('Tearing down OIDC'); - const [error] = await safe(oidcClients.del(app.id)); + const oidcAddonClientId = `${app.id}-oidc`; + + const [error] = await safe(oidcClients.del(oidcAddonClientId)); if (error && error.reason !== BoxError.NOT_FOUND) throw error; } @@ -2182,26 +2185,25 @@ async function getDynamicEnvironmentOidc(app, options) { if (!app.sso) return {}; - const client = await oidcClients.get(app.id); + const oidcAddonClientId = `${app.id}-oidc`; + const client = await oidcClients.get(oidcAddonClientId); if (!client) throw new BoxError(BoxError.NOT_FOUND, `OIDC client for ${app.id} has not been allocated yet`); // happens with overzealous scheduler logic - const tmp = {}; - tmp['CLOUDRON_OIDC_DISCOVERY_URL'] = `https://${dashboardFqdn}/openid/.well-known/openid-configuration`; - tmp['CLOUDRON_OIDC_ISSUER'] = `https://${dashboardFqdn}/openid`; - tmp['CLOUDRON_OIDC_AUTH_ENDPOINT'] = `https://${dashboardFqdn}/openid/auth`; - tmp['CLOUDRON_OIDC_TOKEN_ENDPOINT'] = `https://${dashboardFqdn}/openid/token`; - tmp['CLOUDRON_OIDC_KEYS_ENDPOINT'] = `https://${dashboardFqdn}/openid/jwks`; - tmp['CLOUDRON_OIDC_PROFILE_ENDPOINT'] = `https://${dashboardFqdn}/openid/me`; - // following is only available if rpInitiatedLogout would be enabled https://github.com/panva/node-oidc-provider/blob/main/docs/README.md#featuresrpinitiatedlogout - // tmp['CLOUDRON_OIDC_LOGOUT_URL'] = `https://${dashboardFqdn}/openid/session/end`; + return { + CLOUDRON_OIDC_DISCOVERY_URL: `https://${dashboardFqdn}/openid/.well-known/openid-configuration`, + CLOUDRON_OIDC_ISSUER: `https://${dashboardFqdn}/openid`, + CLOUDRON_OIDC_AUTH_ENDPOINT: `https://${dashboardFqdn}/openid/auth`, + CLOUDRON_OIDC_TOKEN_ENDPOINT: `https://${dashboardFqdn}/openid/token`, + CLOUDRON_OIDC_KEYS_ENDPOINT: `https://${dashboardFqdn}/openid/jwks`, + CLOUDRON_OIDC_PROFILE_ENDPOINT: `https://${dashboardFqdn}/openid/me`, + // following is only available if rpInitiatedLogout would be enabled https://github.com/panva/node-oidc-provider/blob/main/docs/README.md#featuresrpinitiatedlogout + // CLOUDRON_OIDC_LOGOUT_URL: `https://${dashboardFqdn}/openid/session/end` - tmp['CLOUDRON_OIDC_CLIENT_ID'] = client.id; - tmp['CLOUDRON_OIDC_CLIENT_SECRET'] = client.secret; + CLOUDRON_OIDC_CLIENT_ID: client.id, + CLOUDRON_OIDC_CLIENT_SECRET: client.secret, - const cloudronName = await branding.getCloudronName(); - tmp['CLOUDRON_OIDC_PROVIDER_NAME'] = cloudronName; - - return tmp; + CLOUDRON_OIDC_PROVIDER_NAME: await branding.getCloudronName() + }; } async function checkAddonsSupport(addons) {