diff --git a/web/packages/teleport/src/DesktopSession/DesktopSession.tsx b/web/packages/teleport/src/DesktopSession/DesktopSession.tsx index 7bcaeda1a8700..f76ce7dc726c6 100644 --- a/web/packages/teleport/src/DesktopSession/DesktopSession.tsx +++ b/web/packages/teleport/src/DesktopSession/DesktopSession.tsx @@ -33,6 +33,7 @@ import { AuthenticatedWebSocket } from 'teleport/lib/AuthenticatedWebSocket'; import { adaptWebSocketToTdpTransport } from 'teleport/lib/tdp'; import { shouldShowMfaPrompt, useMfaEmitter } from 'teleport/lib/useMfa'; import { getHostName } from 'teleport/services/api'; +import auth from 'teleport/services/auth'; export function DesktopSession() { const ctx = useTeleport(); @@ -72,10 +73,29 @@ export function DesktopSession() { }, [ctx.userService]) ); - const hasAnotherSession = useCallback( - () => ctx.desktopService.checkDesktopIsActive(clusterId, desktopName), - [clusterId, ctx.desktopService, desktopName] - ); + // Returns an active session only if per-session MFA is disabled. + // This improves the user experience by preventing multiple confirmation prompts: + // - one from the active desktop alert, + // - another from the per-session MFA prompt. + // The check for another session was added to prevent a situation where a user could be tricked + // into clicking a link that would DOS another user's active session. + // https://github.com/gravitational/webapps/pull/1297 + // Showing only the MFA prompt is enough for security. + const hasAnotherSession = useCallback(async (): Promise => { + const [mfaRequiredResponse, desktopActive] = await Promise.all([ + auth.checkMfaRequired(clusterId, { + windows_desktop: { + desktop_name: desktopName, + login: username, + }, + }), + ctx.desktopService.checkDesktopIsActive(clusterId, desktopName), + ]); + if (mfaRequiredResponse.required) { + return false; + } + return desktopActive; + }, [clusterId, ctx.desktopService, desktopName, username]); useEffect(() => { fetchAcl(); diff --git a/web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/TestConnection.story.tsx b/web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/TestConnection.story.tsx index 218b443e03898..e9dbace9ceb26 100644 --- a/web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/TestConnection.story.tsx +++ b/web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/TestConnection.story.tsx @@ -41,7 +41,7 @@ export default { HttpResponse.json({}) ), mfaRequired: [ - http.post(cfg.getMfaRequiredUrl(), () => + http.post(cfg.getMfaRequiredUrl(cfg.proxyCluster), () => HttpResponse.json({ required: false }) ), ], diff --git a/web/packages/teleport/src/Discover/Shared/ConnectionDiagnostic/useConnectionDiagnostic.ts b/web/packages/teleport/src/Discover/Shared/ConnectionDiagnostic/useConnectionDiagnostic.ts index b47dbf3b7411a..ba3dca5e5e55f 100644 --- a/web/packages/teleport/src/Discover/Shared/ConnectionDiagnostic/useConnectionDiagnostic.ts +++ b/web/packages/teleport/src/Discover/Shared/ConnectionDiagnostic/useConnectionDiagnostic.ts @@ -73,7 +73,10 @@ export function useConnectionDiagnostic() { try { if (!mfaAuthnResponse) { const mfaReq = getMfaRequest(req, resourceSpec); - const sessionMfa = await auth.checkMfaRequired(mfaReq); + const sessionMfa = await auth.checkMfaRequired( + ctx.storeUser.getClusterId(), + mfaReq + ); if (sessionMfa.required) { setShowMfaDialog(true); return { mfaRequired: true }; diff --git a/web/packages/teleport/src/config.ts b/web/packages/teleport/src/config.ts index 22ce460dd28dc..e28788dfc7f53 100644 --- a/web/packages/teleport/src/config.ts +++ b/web/packages/teleport/src/config.ts @@ -823,8 +823,7 @@ const cfg = { return generatePath(cfg.api.connectionDiagnostic, { clusterId }); }, - getMfaRequiredUrl() { - const clusterId = cfg.proxyCluster; + getMfaRequiredUrl(clusterId: string) { return generatePath(cfg.api.mfaRequired, { clusterId }); }, diff --git a/web/packages/teleport/src/services/auth/auth.ts b/web/packages/teleport/src/services/auth/auth.ts index 4b04aa20c693b..eb0e9d864a797 100644 --- a/web/packages/teleport/src/services/auth/auth.ts +++ b/web/packages/teleport/src/services/auth/auth.ts @@ -409,10 +409,11 @@ const auth = { }; function checkMfaRequired( + clusterId: string, params: IsMfaRequiredRequest, - abortSignal? + abortSignal?: AbortSignal ): Promise { - return api.post(cfg.getMfaRequiredUrl(), params, abortSignal); + return api.post(cfg.getMfaRequiredUrl(clusterId), params, abortSignal); } function base64EncodeUnicode(str: string) {