diff --git a/web/packages/teleterm/src/ui/DocumentAuthorizeWebSession/DocumentAuthorizeWebSession.story.tsx b/web/packages/teleterm/src/ui/DocumentAuthorizeWebSession/DocumentAuthorizeWebSession.story.tsx
index 7b697092f7c62..1ffe93e4cb080 100644
--- a/web/packages/teleterm/src/ui/DocumentAuthorizeWebSession/DocumentAuthorizeWebSession.story.tsx
+++ b/web/packages/teleterm/src/ui/DocumentAuthorizeWebSession/DocumentAuthorizeWebSession.story.tsx
@@ -16,6 +16,7 @@
* along with this program. If not, see .
*/
+import { Meta } from '@storybook/react';
import { wait } from 'shared/utils/wait';
import { MockAppContextProvider } from 'teleterm/ui/fixtures/MockAppContextProvider';
@@ -33,39 +34,41 @@ import { DocumentAuthorizeWebSession } from './DocumentAuthorizeWebSession';
export default {
title: 'Teleterm/DocumentAuthorizeWebSession',
-};
-
-const doc: types.DocumentAuthorizeWebSession = {
- uri: '/docs/e2hyt5',
- rootClusterUri: rootClusterUri,
- kind: 'doc.authorize_web_session',
- title: 'Authorize Web Session',
- webSessionRequest: {
- redirectUri: '',
- token: '',
- id: '',
+ component: Story,
+ argTypes: {
+ isDeviceTrusted: { control: { type: 'boolean' } },
+ isRequestedUserLoggedIn: { control: { type: 'boolean' } },
+ },
+ args: {
+ isDeviceTrusted: true,
+ isRequestedUserLoggedIn: true,
},
-};
+} satisfies Meta;
-export function DeviceNotTrusted() {
- const rootCluster = makeRootCluster();
- const appContext = new MockAppContext();
- appContext.clustersService.setState(draftState => {
- draftState.clusters.set(rootCluster.uri, rootCluster);
- });
- return (
-
-
-
-
-
- );
+interface StoryProps {
+ isDeviceTrusted: boolean;
+ isRequestedUserLoggedIn: boolean;
}
-export function DeviceTrusted() {
+export function Story(props: StoryProps) {
const rootCluster = makeRootCluster({
- loggedInUser: makeLoggedInUser({ isDeviceTrusted: true }),
+ loggedInUser: makeLoggedInUser({ isDeviceTrusted: props.isDeviceTrusted }),
});
+ const doc: types.DocumentAuthorizeWebSession = {
+ uri: '/docs/e2hyt5',
+ rootClusterUri: rootClusterUri,
+ kind: 'doc.authorize_web_session',
+ title: 'Authorize Web Session',
+ webSessionRequest: {
+ redirectUri: '',
+ token: '',
+ id: '',
+ username: props.isRequestedUserLoggedIn
+ ? rootCluster.loggedInUser.name
+ : 'bob',
+ },
+ };
+
const appContext = new MockAppContext();
appContext.clustersService.setState(draftState => {
draftState.clusters.set(rootCluster.uri, rootCluster);
diff --git a/web/packages/teleterm/src/ui/DocumentAuthorizeWebSession/DocumentAuthorizeWebSession.test.tsx b/web/packages/teleterm/src/ui/DocumentAuthorizeWebSession/DocumentAuthorizeWebSession.test.tsx
index c06ff109ff93c..67f47026cde36 100644
--- a/web/packages/teleterm/src/ui/DocumentAuthorizeWebSession/DocumentAuthorizeWebSession.test.tsx
+++ b/web/packages/teleterm/src/ui/DocumentAuthorizeWebSession/DocumentAuthorizeWebSession.test.tsx
@@ -40,10 +40,11 @@ const doc: types.DocumentAuthorizeWebSession = {
redirectUri: '',
token: '',
id: '',
+ username: 'alice',
},
};
-test('authorize button is disabled when device is not trusted', async () => {
+test('warning is visible and authorize button is disabled when device is not trusted', async () => {
const rootCluster = makeRootCluster({
loggedInUser: makeLoggedInUser({ isDeviceTrusted: false }),
});
@@ -64,6 +65,29 @@ test('authorize button is disabled when device is not trusted', async () => {
expect(await screen.findByText(/Authorize Session/)).toBeDisabled();
});
+test('warning is visible and authorize button is disabled when requested user is not logged in', async () => {
+ const rootCluster = makeRootCluster({
+ loggedInUser: makeLoggedInUser({ isDeviceTrusted: true, name: 'bob' }),
+ });
+ const appContext = new MockAppContext();
+ appContext.clustersService.setState(draftState => {
+ draftState.clusters.set(rootCluster.uri, rootCluster);
+ });
+
+ render(
+
+
+
+
+
+ );
+
+ expect(
+ await screen.findByText(/Requested user is not logged in/)
+ ).toBeVisible();
+ expect(await screen.findByText(/Authorize Session/)).toBeDisabled();
+});
+
test('authorizing a session opens its URL and closes document', async () => {
jest.spyOn(window, 'open').mockImplementation();
const rootCluster = makeRootCluster({
diff --git a/web/packages/teleterm/src/ui/DocumentAuthorizeWebSession/DocumentAuthorizeWebSession.tsx b/web/packages/teleterm/src/ui/DocumentAuthorizeWebSession/DocumentAuthorizeWebSession.tsx
index 461a8de679ae4..18ff95e499575 100644
--- a/web/packages/teleterm/src/ui/DocumentAuthorizeWebSession/DocumentAuthorizeWebSession.tsx
+++ b/web/packages/teleterm/src/ui/DocumentAuthorizeWebSession/DocumentAuthorizeWebSession.tsx
@@ -50,7 +50,10 @@ export function DocumentAuthorizeWebSession(props: {
return confirmationToken;
});
const clusterName = routing.parseClusterName(props.doc.rootClusterUri);
- const canAuthorize = rootCluster.loggedInUser?.isDeviceTrusted;
+ const isDeviceTrusted = rootCluster.loggedInUser?.isDeviceTrusted;
+ const isRequestedUserLoggedIn =
+ props.doc.webSessionRequest.username === rootCluster.loggedInUser?.name;
+ const canAuthorize = isDeviceTrusted && isRequestedUserLoggedIn;
async function authorizeAndCloseDocument() {
const [confirmationToken, error] = await authorize();
@@ -95,7 +98,7 @@ export function DocumentAuthorizeWebSession(props: {
Authorize Web Session
{/*It's technically possible to open a deep link to authorize a session on a device that is not enrolled.*/}
- {!canAuthorize && (
+ {!isDeviceTrusted && (
)}
+ {!isRequestedUserLoggedIn && (
+ {
+ ctx.commandLauncher.executeCommand('cluster-logout', {
+ clusterUri: rootCluster.uri,
+ });
+ },
+ }}
+ details={
+ <>
+ You are logged in as {rootCluster.loggedInUser?.name}.
+ To authorize this web session request, please log out in
+ Teleport Connect and log in again as{' '}
+ {props.doc.webSessionRequest.username}.
+
+ Then click Launch Teleport Connect again in the browser.
+ >
+ }
+ >
+ Requested user is not logged in
+
+ )}
{authorizeAttempt.status === 'error' && (
Could not authorize the session
diff --git a/web/packages/teleterm/src/ui/services/deepLinks/deepLinksService.ts b/web/packages/teleterm/src/ui/services/deepLinks/deepLinksService.ts
index 6083df679f626..ea98c9a51ef40 100644
--- a/web/packages/teleterm/src/ui/services/deepLinks/deepLinksService.ts
+++ b/web/packages/teleterm/src/ui/services/deepLinks/deepLinksService.ts
@@ -117,6 +117,7 @@ export class DeepLinksService {
webSessionRequest: {
id,
token,
+ username: url.username,
redirectUri: redirect_uri,
},
});
diff --git a/web/packages/teleterm/src/ui/services/workspacesService/documentsService/types.ts b/web/packages/teleterm/src/ui/services/workspacesService/documentsService/types.ts
index 0c7fd36952285..00238ae5b35fd 100644
--- a/web/packages/teleterm/src/ui/services/workspacesService/documentsService/types.ts
+++ b/web/packages/teleterm/src/ui/services/workspacesService/documentsService/types.ts
@@ -237,6 +237,7 @@ export interface DocumentAuthorizeWebSession extends DocumentBase {
export interface WebSessionRequest {
id: string;
token: string;
+ username: string;
redirectUri: string;
}
diff --git a/web/packages/teleterm/src/ui/services/workspacesService/workspacesService.test.ts b/web/packages/teleterm/src/ui/services/workspacesService/workspacesService.test.ts
index ded2d08080df5..ccb1add834217 100644
--- a/web/packages/teleterm/src/ui/services/workspacesService/workspacesService.test.ts
+++ b/web/packages/teleterm/src/ui/services/workspacesService/workspacesService.test.ts
@@ -218,6 +218,7 @@ describe('state persistence', () => {
id: '',
token: '',
redirectUri: '',
+ username: '',
},
},
],