From 6852ad2be7059aeda28209fec2dbe01b34162a8d Mon Sep 17 00:00:00 2001 From: Alexandre Bourdin Date: Mon, 6 Nov 2023 15:26:45 +0100 Subject: [PATCH] Merge pull request #15569 from overleaf/msm-group-sso-link-errors [web] Error handling during SSO linking GitOrigin-RevId: 232ef0672e93dc7c68cd45396306e8b4328a35d9 --- .../Features/Subscription/GroupSSOHandler.js | 32 ++++++------------- .../web/frontend/extracted-translations.json | 9 ++++++ .../sso/sso-link-interstitial.stories.tsx | 27 ++++++++++++++++ services/web/locales/en.json | 3 ++ 4 files changed, 48 insertions(+), 23 deletions(-) create mode 100644 services/web/frontend/stories/subscription/sso/sso-link-interstitial.stories.tsx diff --git a/services/web/app/src/Features/Subscription/GroupSSOHandler.js b/services/web/app/src/Features/Subscription/GroupSSOHandler.js index 0b880119ab..bb6335a604 100644 --- a/services/web/app/src/Features/Subscription/GroupSSOHandler.js +++ b/services/web/app/src/Features/Subscription/GroupSSOHandler.js @@ -5,17 +5,17 @@ const SAMLIdentityManager = require('../User/SAMLIdentityManager') const { User } = require('../../models/User') const Errors = require('../Errors/Errors') -async function canEnrollInSubscription(userId, subscription) { - const ssoEnabled = await isSSOEnabled(subscription) - if (!ssoEnabled) { - return false +async function checkUserCanEnrollInSubscription(userId, subscription) { + const ssoConfig = await SSOConfig.findById(subscription?.ssoConfig).exec() + if (!ssoConfig?.enabled) { + throw new Errors.SAMLGroupSSODisabledError() } const userIsMember = subscription.member_ids.some( memberId => memberId.toString() === userId.toString() ) if (!userIsMember) { - return false + throw new Errors.SAMLGroupSSOLoginIdentityNotFoundError() } const user = await User.findOne( @@ -27,9 +27,8 @@ async function canEnrollInSubscription(userId, subscription) { enrollment => enrollment.groupId.toString() === subscription._id.toString() ) if (userIsEnrolled) { - return false + throw new Errors.SAMLIdentityExistsError() } - return true } async function enrollInSubscription( @@ -39,15 +38,8 @@ async function enrollInSubscription( userIdAttribute, auditLog ) { - const canEnroll = await canEnrollInSubscription(userId, subscription) - if (!canEnroll) { - throw new Errors.SubscriptionNotFoundError( - 'cannot enroll user in SSO subscription', - { - info: { userId, subscription }, - } - ) - } + await checkUserCanEnrollInSubscription(userId, subscription) + const providerId = `ol-group-subscription-id:${subscription._id.toString()}` const userBySamlIdentifier = await SAMLIdentityManager.getUser( @@ -86,15 +78,9 @@ async function enrollInSubscription( ) } -async function isSSOEnabled(subscription) { - const ssoConfig = await SSOConfig.findById(subscription.ssoConfig).exec() - return ssoConfig?.enabled -} - module.exports = { promises: { - canEnrollInSubscription, + checkUserCanEnrollInSubscription, enrollInSubscription, - isSSOEnabled, }, } diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index 948258b0f1..42ecfcfaac 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -990,6 +990,12 @@ "revoke_invite": "", "right": "", "role": "", + "saml_auth_error": "", + "saml_invalid_signature_error": "", + "saml_login_disabled_error": "", + "saml_login_failure": "", + "saml_login_identity_mismatch_error": "", + "saml_login_identity_not_found_error": "", "save": "", "save_or_cancel-cancel": "", "save_or_cancel-or": "", @@ -1116,8 +1122,11 @@ "sso_is_enabled": "", "sso_is_enabled_explanation_1": "", "sso_is_enabled_explanation_2": "", + "sso_link_currently_signed_in": "", "sso_link_error": "", "sso_link_invite_has_been_sent_to_email": "", + "sso_link_now_or_later": "", + "sso_link_your_group_uses_sso": "", "sso_logs": "", "sso_not_active": "", "start_a_free_trial": "", diff --git a/services/web/frontend/stories/subscription/sso/sso-link-interstitial.stories.tsx b/services/web/frontend/stories/subscription/sso/sso-link-interstitial.stories.tsx new file mode 100644 index 0000000000..3c86a6ea2a --- /dev/null +++ b/services/web/frontend/stories/subscription/sso/sso-link-interstitial.stories.tsx @@ -0,0 +1,27 @@ +import { useMeta } from '../../hooks/use-meta' +import SSOLinkConfirm from '../../../../modules/managed-users/frontend/js/components/sso-link-confirm' + +export const LinkConfirmInterstitial = () => { + return +} + +export const LinkConfirmInterstitialWithError = () => { + useMeta({ 'ol-error': 'SAMLInvalidSignatureError' }) + return +} + +export default { + title: 'Subscription / SSO / Link', + component: SSOLinkConfirm, + decorators: [ + (Story: any) => { + useMeta({ 'ol-groupId': '123' }) + useMeta({ 'ol-email': 'user@example.com' }) + return ( +
+ +
+ ) + }, + ], +} diff --git a/services/web/locales/en.json b/services/web/locales/en.json index a2cce8b691..52b97a426e 100644 --- a/services/web/locales/en.json +++ b/services/web/locales/en.json @@ -1690,8 +1690,11 @@ "sso_is_enabled": "SSO is enabled", "sso_is_enabled_explanation_1": "Group members will <0>only be able to sign in via SSO", "sso_is_enabled_explanation_2": "If there are any problems with the configuration, only you (as the group administrator) will be able to disable SSO.", + "sso_link_currently_signed_in": "Currently signed in as <0>__email__. <1>Log out.", "sso_link_error": "Error linking account", "sso_link_invite_has_been_sent_to_email": "An SSO invite reminder has been sent to <0>__email__", + "sso_link_now_or_later": "We need to link your account with the group identity provider. You can either do this now, or do this later.", + "sso_link_your_group_uses_sso": "The group you are part of uses single sign-on", "sso_logs": "SSO Logs", "sso_not_active": "SSO not active", "sso_not_linked": "You have not linked your account to __provider__. Please log in to your account another way and link your __provider__ account via your account settings.",