diff --git a/src/oidc.js b/src/oidc.js index 7d3e0bc58..7a1be42c3 100644 --- a/src/oidc.js +++ b/src/oidc.js @@ -399,12 +399,10 @@ function renderInteractionPage(provider) { return async function (req, res, next) { try { const { uid, prompt, params, session } = await provider.interactionDetails(req, res); - console.log('details', await provider.interactionDetails(req, res)); debug(`route interaction get uid:${uid} prompt.name:${prompt.name} client_id:${params.client_id} session:${session}`); - const [error, client] = await safe(clientsGet(params.client_id)); - if (error) return next(error); + const client = await clientsGet(params.client_id); switch (prompt.name) { case 'login': { @@ -414,10 +412,26 @@ function renderInteractionPage(provider) { }); } case 'consent': { - return res.render('interaction', { - submitUrl: `${ROUTE_PREFIX}/interaction/${uid}/confirm`, - name: client?.name || 'Cloudron' - }); + const options = { + hasAccess: false, + submitUrl: '', + name: client?.name || '' + }; + + // check if user has access to the app if client refers to an app + if (client.appId) { + const app = await apps.get(client.appId); + const user = await users.get(session.accountId); + + options.name = app.label || app.fqdn; + options.hasAccess = apps.canAccess(app, user); + } else { + options.hasAccess = true; + } + + options.submitUrl = `${ROUTE_PREFIX}/interaction/${uid}/${options.hasAccess ? 'confirm' : 'abort'}`; + + return res.render('interaction', options); } default: return undefined; @@ -442,7 +456,7 @@ function interactionLogin(provider) { const prompt = details.prompt; const name = prompt.name; - debug(`route interaction login post uid:${uid} prompt.name:${name}`, req.body); + debug(`route interaction login post uid:${uid} prompt.name:${name}`); assert.equal(name, 'login'); @@ -482,15 +496,30 @@ function interactionConfirm(provider) { return async function (req, res, next) { try { const interactionDetails = await provider.interactionDetails(req, res); - const { uid, prompt: { name, details }, params, session: { accountId } } = interactionDetails; + let { grantId, uid, prompt: { name, details }, params, session: { accountId } } = interactionDetails; debug(`route interaction confirm post uid:${uid} prompt.name:${name} accountId:${accountId}`); assert.equal(name, 'consent'); - let { grantId } = interactionDetails; - let grant; + const client = await clientsGet(params.client_id); + // Check if user has access to the app if client refers to an app + // In most cases the user interaction already ends in the consent screen (see above) + if (client.appId) { + const app = await apps.get(client.appId); + const user = await users.get(accountId); + + if (!apps.canAccess(app, user)) { + const result = { + error: 'access_denied', + error_description: 'User has no access to this app', + }; + return await provider.interactionFinished(req, res, result, { mergeWithLastSubmission: false }); + } + } + + let grant; if (grantId) { // we'll be modifying existing grant in existing session grant = await provider.Grant.find(grantId); diff --git a/src/oidc_templates/interaction.ejs b/src/oidc_templates/interaction.ejs index bec8f0054..34efda79a 100644 --- a/src/oidc_templates/interaction.ejs +++ b/src/oidc_templates/interaction.ejs @@ -26,15 +26,23 @@

-

Authorize <%= name %>

+<% if (hasAccess) { -%> +

Authorize for <%= name %>

+<% } else { -%> +

You do not have access to <%= name %>

+<% } -%>

+<% if (hasAccess) { -%>
+<% } else { -%> + Continue +<% } -%>