diff --git a/src/oidc.js b/src/oidc.js index a42fcdecf..b2002fa60 100644 --- a/src/oidc.js +++ b/src/oidc.js @@ -2,6 +2,7 @@ exports = module.exports = { getProvider, + upsertClient, routes: { renderInteractionPage, interactionLogin, @@ -23,6 +24,10 @@ const assert = require('assert'), safe = require('safetydance'), settings = require('./settings.js'); +// currently non-persistent client store instead of .json file +// FIXME this has to go to our db +const gClients = {}; + class CloudronAdapter { /** @@ -38,18 +43,24 @@ class CloudronAdapter { */ constructor(name) { this.name = name; - this.fileStorePath = path.join(paths.OIDC_STORE_DIR, `${name}.json`); - debug(`Creating adapter for ${name} backed by ${this.fileStorePath}`); + if (name === 'Client') { + this.store = gClients; + this.fileStorePath = null; + } else { + this.fileStorePath = path.join(paths.OIDC_STORE_DIR, `${name}.json`); - let data = {}; - try { - data = JSON.parse(fs.readFileSync(this.fileStorePath), 'utf8'); - } catch (e) { - debug(`filestore for adapter ${name} not found, start with new one`); + debug(`Creating adapter for ${name} backed by ${this.fileStorePath}`); + + let data = {}; + try { + data = JSON.parse(fs.readFileSync(this.fileStorePath), 'utf8'); + } catch (e) { + debug(`filestore for adapter ${name} not found, start with new one`); + } + + this.store = data; } - - this.store = data; } /** @@ -68,7 +79,7 @@ class CloudronAdapter { debug(`[${this.name}] upsert id:${id} expiresIn:${expiresIn}`, payload); this.store[id] = { id, expiresIn, payload, consumed: false }; - fs.writeFileSync(this.fileStorePath, JSON.stringify(this.store), 'utf8'); + if (this.fileStorePath) fs.writeFileSync(this.fileStorePath, JSON.stringify(this.store), 'utf8'); } /** @@ -86,6 +97,8 @@ class CloudronAdapter { if (!this.store[id]) return false; + debug(`[${this.name}] find id:${id}`, this.store[id]); + return this.store[id].payload; } @@ -139,6 +152,8 @@ class CloudronAdapter { debug(`[${this.name}] consume id:${id}`); if (this.store[id]) this.store[id].consumed = true; + + if (this.fileStorePath) fs.writeFileSync(this.fileStorePath, JSON.stringify(this.store), 'utf8'); } /** @@ -155,6 +170,8 @@ class CloudronAdapter { debug(`[${this.name}] destroy id:${id}`); delete this.store[id]; + + if (this.fileStorePath) fs.writeFileSync(this.fileStorePath, JSON.stringify(this.store), 'utf8'); } /** @@ -179,6 +196,24 @@ class CloudronAdapter { } } +async function upsertClient(provider, clientId, clientSecret, redirectUri) { + assert.strictEqual(typeof provider, 'object'); + assert.strictEqual(typeof clientId, 'string'); + assert.strictEqual(typeof clientSecret, 'string'); + assert.strictEqual(typeof redirectUri, 'string'); + + debug(`upsertClient clientId:${clientId} clientSecret:${clientSecret} redirectUri:${redirectUri}`); + + const payload = { + client_id: clientId, + client_secret: clientSecret, + redirect_uris: [ redirectUri ], + response_types: [ 'code id_token', 'code', 'id_token', 'none' ] + } + + gClients[clientId] = { id: clientId, expiresIn: 0, payload, consumed: false }; +} + function renderInteractionPage(routePrefix, provider) { assert.strictEqual(typeof routePrefix, 'string'); assert.strictEqual(typeof provider, 'object'); @@ -411,11 +446,11 @@ async function getProvider(routePrefix) { features: { devInteractions: { enabled: false } }, - clients: [{ - client_id: 'foo', - client_secret: 'bar', - redirect_uris: ['https://openidconnect.net/callback'], - }], + clients: [], + cookies: { + // FIXME https://github.com/panva/node-oidc-provider/blob/b1c1a9318036c2d3793cc9e668f99937c5c36bc6/lib/helpers/defaults.js#L770 + keys: [ 'cookiesecret1', 'cookiesecret2' ] + }, pkce: { required: function pkceRequired(ctx, client) { return false; diff --git a/src/server.js b/src/server.js index 6ab83e85d..8ce18286d 100644 --- a/src/server.js +++ b/src/server.js @@ -388,6 +388,10 @@ async function initializeExpressSync() { app.use(oidcPrefix, oidcProvider.callback()); + // FIXME this should come from the database + await oidc.upsertClient(oidcProvider, 'foo', 'bar', 'https://openidconnect.net/callback'); + await oidc.upsertClient(oidcProvider, 'oidcdebugger', 'bar', 'https://oidcdebugger.com/debug'); + // disable server socket "idle" timeout. we use the timeout middleware to handle timeouts on a route level // we rely on nginx for timeouts on the TCP level (see client_header_timeout) httpServer.setTimeout(0);