diff --git a/package.json b/package.json index b956449..96e4dcc 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ue-auth", "altName": "UE-Auth", - "version": "1.40.2", + "version": "1.41.1", "description": "UE Auth is a multi-tenant OIDC Provider, User Management, B2B Product Access, and Roles/Permissions Management system intended to create a single hybrid solution to serve as Identity and Access for both self-registered B2C Apps and Enterprise B2B Solutions", "private": false, "license": "SEE LICENSE IN ./LICENSE.md", diff --git a/src/api/authGroup/model.js b/src/api/authGroup/model.js index 36ff92f..a3de212 100644 --- a/src/api/authGroup/model.js +++ b/src/api/authGroup/model.js @@ -199,6 +199,10 @@ const authGroup = new mongoose.Schema({ config: { keys: Array, cookieKeys: Array, + defaultLogoutRedirect: String, + defaultLogoutName: String, + globalSkipLogoutConfirm: Boolean, + globalSkipAuthorize: Boolean, restrictPasswordRepeats: { type: Boolean, default: false diff --git a/src/api/oidc/interactions/api.js b/src/api/oidc/interactions/api.js index 1796f15..3c06190 100644 --- a/src/api/oidc/interactions/api.js +++ b/src/api/oidc/interactions/api.js @@ -100,7 +100,8 @@ const api = { return res.render('login/login', options); } case 'consent': { - if(client.client_skip_consent === true || params.federated_redirect === true) { + + if(client.client_skip_consent === true || authGroup?.config?.globalSkipAuthorize === true || params.federated_redirect === true) { const result = await interactions.confirmAuthorization(provider, intDetails, authGroup); return provider.interactionFinished(req, res, result, { mergeWithLastSubmission: true }); } @@ -731,9 +732,10 @@ const api = { if(ctx?.oidc?.client) { client = JSON.parse(JSON.stringify(ctx.oidc.client)); } - const name = (client?.clientName) ? client.clientName : ctx.authGroup.name; + const name = (client?.clientName) ? client.clientName : (ctx.authGroup?.config?.defaultLogoutName || ctx.authGroup.name); const sid = ctx.oidc?.entities?.Session?.jti; - if ((client?.client_optional_skip_logout_prompt === true || ctx.req.query.skipPrompt === 'true') && sid) { + + if ((client?.client_optional_skip_logout_prompt === true || ctx.req.query.skipPrompt === 'true' || ctx.authGroup?.config?.globalSkipLogoutConfirm === true) && sid) { await ctx.oidc.entities.Session.destroy(sid); if(ctx.oidc.entities.Session.destroyed === true) { //reload... @@ -741,14 +743,14 @@ const api = { return ctx.redirect(end); } } - //} + const pug = new Pug({ viewPath: path.resolve(__dirname, '../../../../views'), basedir: 'path/for/pug/extends', }); const options = await interactions.oidcLogoutSourceOptions(ctx.authGroup, name, action, ctx.oidc.session.state.secret, client); if (ctx?.req?.query?.onCancel) { - options.onCancel = ctx.req.query.onCancel; + options.clientUri = ctx.req.query.onCancel } if (ctx?.req?.query?.json === 'true') { // enable REST response @@ -775,23 +777,28 @@ const api = { try { const { authGroup } = await safeAuthGroup(ctx.authGroup); - const clientName = (ctx.oidc.client) ? ctx.oidc.client.clientName : null; const clientId = (ctx.oidc.client) ? ctx.oidc.client.clientId : null; - let clientUri = (ctx.oidc.client) ? ctx.oidc.client.clientUri : null; const initiateLoginUri = (ctx.oidc.client) ? ctx.oidc.client.initiateLoginUri : null; const logoUri = (ctx.oidc.client) ? ctx.oidc.client.logoUri : null; const policyUri = (ctx.oidc.client) ? ctx.oidc.client.policyUri : null; const tosUri = (ctx.oidc.client) ? ctx.oidc.client.tosUri : null; + const clientName = (ctx.oidc.client) ? ctx.oidc.client.clientName : (authGroup?.config?.defaultLogoutName || null); + let clientUri = (ctx.oidc.client?.clientUri) ? ctx.oidc.client.clientUri : ( authGroup?.config?.defaultLogoutRedirect || null); - if(authGroup.associatedClient === clientId) { + if(!clientUri && authGroup.associatedClient === clientId) { clientUri = `https://${(authGroup.aliasDnsUi) ? authGroup.aliasDnsUi : config.UI_URL}/${authGroup.prettyName}`; } + + if (ctx.authGroup?.config?.globalSkipLogoutConfirm === true && clientUri) { + return ctx.redirect(clientUri); + } + const name = (clientName) ? clientName : ctx.authGroup.name; const pug = new Pug({ viewPath: path.resolve(__dirname, '../../../../views'), basedir: 'path/for/pug/extends', }); - const message = (clientName) ? `You are still logged into ${name}` : undefined; + const message = (ctx.oidc.client) ? `You are still logged into ${name}` : undefined; const options = await interactions.oidcPostLogoutSourceOptions(authGroup, message, clientUri, initiateLoginUri, logoUri, policyUri, tosUri, clientName); ctx.type = 'html'; ctx.set('json-data', JSON.stringify({ @@ -809,7 +816,7 @@ const api = { } }, async renderError(ctx, out, error) { - console.error(error); + console.error('OIDC UI ERROR CAUGHT', error); const { authGroup, safeAG } = await safeAuthGroup(ctx.authGroup); const pug = new Pug({ viewPath: path.resolve(__dirname, '../../../../views'), diff --git a/src/api/oidc/interactions/interactions.js b/src/api/oidc/interactions/interactions.js index 2d088f4..c840e5d 100644 --- a/src/api/oidc/interactions/interactions.js +++ b/src/api/oidc/interactions/interactions.js @@ -203,6 +203,7 @@ const api = { }; }, async oidcLogoutSourceOptions(authGroup, name, action, secret, client, skipPrompt = false) { + let clientUri = (client?.clientUri) ? client.clientUri : ( authGroup?.config?.defaultLogoutRedirect || null); return { title: 'Log Out', bgGradientLow: authGroup.config.ui.skin.bgGradientLow || config.DEFAULT_UI_SKIN_GRADIENT_LOW, @@ -210,9 +211,9 @@ const api = { favicon: authGroup.config?.ui?.skin?.favicon, authGroupLogo: authGroup.config?.ui?.skin?.logo || undefined, splashImage: authGroup.config?.ui?.skin?.splashImage || undefined, - clientName: (client?.clientId === authGroup.associatedClient) ? undefined : client?.clientName, - clientUri: (authGroup.associatedClient === client?.clientId) ? - `https://${(authGroup.aliasDnsUi) ? authGroup.aliasDnsUi : config.UI_URL}/${authGroup.prettyName}` : client?.clientUri, + clientName: (name !== authGroup.name) ? name : undefined, + clientUri: (!clientUri && authGroup.associatedClient === client?.clientId) ? + `https://${(authGroup.aliasDnsUi) ? authGroup.aliasDnsUi : config.UI_URL}/${authGroup.prettyName}` : clientUri, initiateLoginUri: client?.initiateLoginUri, logoUri: client?.logoUri, tosUri: client?.tosUri || authGroup.primaryTOS || undefined, @@ -223,7 +224,7 @@ const api = { primaryTOS: authGroup.primaryTOS, primaryDomain: authGroup.primaryDomain }, - message: `Are you sure you want to sign-out from ${(client?.clientId === authGroup.associatedClient) ? authGroup.name : client?.clientName}?`, + message: `Are you sure you want to sign-out from ${name}?`, formId: 'op.logoutForm', actionUrl: action, secret, diff --git a/swagger.clean.yaml b/swagger.clean.yaml index d889f26..88a6a36 100644 --- a/swagger.clean.yaml +++ b/swagger.clean.yaml @@ -8995,6 +8995,18 @@ components: grant: type: number default: 864000 + defaultLogoutRedirect: + type: string + description: when clients logout of any app, if a redirect for the logout is not defined, this is the default. + defaultLogoutName: + type: string + description: text to display with default logout redirect + globalSkipLogoutConfirm: + type: boolean + default: false + globalSkipAuthorize: + type: boolean + default: false requireVerified: type: boolean default: false diff --git a/swagger.yaml b/swagger.yaml index 002c175..a8b6942 100644 --- a/swagger.yaml +++ b/swagger.yaml @@ -9630,6 +9630,18 @@ components: grant: type: number default: 864000 + defaultLogoutRedirect: + type: string + description: when clients logout of any app, if a redirect for the logout is not defined, this is the default. + defaultLogoutName: + type: string + description: text to display with default logout redirect + globalSkipLogoutConfirm: + type: boolean + default: false + globalSkipAuthorize: + type: boolean + default: false requireVerified: type: boolean default: false diff --git a/views/logout/logout.pug b/views/logout/logout.pug index 3af1345..67919b3 100644 --- a/views/logout/logout.pug +++ b/views/logout/logout.pug @@ -20,9 +20,7 @@ block content input(type="hidden" name=inName value=secret) input(type="hidden" id='skip') button.btn.btn-outline-dark.btn-custom(type="submit" autofocus form=formId value="yes" name="logout") Sign Out - if onCancel - a.btn.btn-outline-dark.btn-custom.m-t-20(href=onCancel id='onCancel') Cancel - else if clientUri + if clientUri a.btn.btn-outline-dark.btn-custom.m-t-20(href=clientUri id='clientUri') Cancel else button.btn.btn-outline-dark.btn-custom.m-t-20(type="submit" form=formId id='cancel' value="no") Cancel