From 835927672c20b43223e15c6fd2eebc05de1a79a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Cie=C5=9Blak?= Date: Fri, 24 Nov 2023 10:52:40 +0100 Subject: [PATCH 1/7] Rename existing component to LegacyTestConnection --- .../LegacyTestConnection.story.tsx} | 16 ++++++++-------- .../LegacyTestConnection.tsx} | 2 +- .../index.ts | 2 +- .../src/Discover/ConnectMyComputer/index.ts | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) rename web/packages/teleport/src/Discover/ConnectMyComputer/{TestConnection/TestConnection.story.tsx => LegacyTestConnection/LegacyTestConnection.story.tsx} (91%) rename web/packages/teleport/src/Discover/ConnectMyComputer/{TestConnection/TestConnection.tsx => LegacyTestConnection/LegacyTestConnection.tsx} (99%) rename web/packages/teleport/src/Discover/ConnectMyComputer/{TestConnection => LegacyTestConnection}/index.ts (90%) diff --git a/web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/TestConnection.story.tsx b/web/packages/teleport/src/Discover/ConnectMyComputer/LegacyTestConnection/LegacyTestConnection.story.tsx similarity index 91% rename from web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/TestConnection.story.tsx rename to web/packages/teleport/src/Discover/ConnectMyComputer/LegacyTestConnection/LegacyTestConnection.story.tsx index a434554a9bc9e..e144d4e693f77 100644 --- a/web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/TestConnection.story.tsx +++ b/web/packages/teleport/src/Discover/ConnectMyComputer/LegacyTestConnection/LegacyTestConnection.story.tsx @@ -26,10 +26,10 @@ import { UserContext } from 'teleport/User/UserContext'; import { createTeleportContext } from 'teleport/mocks/contexts'; import { makeDefaultUserPreferences } from 'teleport/services/userPreferences/userPreferences'; -import { TestConnection } from './TestConnection'; +import { LegacyTestConnection } from './LegacyTestConnection'; export default { - title: 'Teleport/Discover/ConnectMyComputer/TestConnection', + title: 'Teleport/Discover/ConnectMyComputer/LegacyTestConnection', loaders: [mswLoader], }; @@ -46,7 +46,7 @@ const agentStepProps = { export const SingleLogin = () => { return ( - + ); }; @@ -67,7 +67,7 @@ SingleLogin.parameters = { export const MultipleLogins = () => { return ( - + ); }; @@ -88,7 +88,7 @@ MultipleLogins.parameters = { export const NoLogins = () => { return ( - + ); }; @@ -109,7 +109,7 @@ NoLogins.parameters = { export const NoRole = () => { return ( - + ); }; @@ -131,7 +131,7 @@ NoRole.parameters = { export const ReloadUserProcessing = () => { return ( - + ); }; @@ -149,7 +149,7 @@ ReloadUserProcessing.parameters = { export const ReloadUserError = () => { return ( - + ); }; diff --git a/web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/TestConnection.tsx b/web/packages/teleport/src/Discover/ConnectMyComputer/LegacyTestConnection/LegacyTestConnection.tsx similarity index 99% rename from web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/TestConnection.tsx rename to web/packages/teleport/src/Discover/ConnectMyComputer/LegacyTestConnection/LegacyTestConnection.tsx index ba14c03b6ea77..9d27ee5368183 100644 --- a/web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/TestConnection.tsx +++ b/web/packages/teleport/src/Discover/ConnectMyComputer/LegacyTestConnection/LegacyTestConnection.tsx @@ -45,7 +45,7 @@ import { NodeMeta } from '../../useDiscover'; import type { AgentStepProps } from '../../types'; -export const TestConnection = (props: AgentStepProps) => { +export const LegacyTestConnection = (props: AgentStepProps) => { const { userService, storeUser } = useTeleport(); const meta = props.agentMeta as NodeMeta; diff --git a/web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/index.ts b/web/packages/teleport/src/Discover/ConnectMyComputer/LegacyTestConnection/index.ts similarity index 90% rename from web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/index.ts rename to web/packages/teleport/src/Discover/ConnectMyComputer/LegacyTestConnection/index.ts index 6852c35b30fc0..351a32d4623de 100644 --- a/web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/index.ts +++ b/web/packages/teleport/src/Discover/ConnectMyComputer/LegacyTestConnection/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export { TestConnection } from './TestConnection'; +export { LegacyTestConnection } from './LegacyTestConnection'; diff --git a/web/packages/teleport/src/Discover/ConnectMyComputer/index.ts b/web/packages/teleport/src/Discover/ConnectMyComputer/index.ts index 2c043f7bd6bd9..695dd92dc4534 100644 --- a/web/packages/teleport/src/Discover/ConnectMyComputer/index.ts +++ b/web/packages/teleport/src/Discover/ConnectMyComputer/index.ts @@ -21,7 +21,7 @@ import { DiscoverEvent } from 'teleport/services/userEvent'; import { ResourceSpec } from '../SelectResource'; import { SetupConnect } from './SetupConnect'; -import { TestConnection } from './TestConnection'; +import { LegacyTestConnection } from './LegacyTestConnection'; export const ConnectMyComputerResource: ResourceViewConfig = { kind: ResourceKind.ConnectMyComputer, @@ -34,7 +34,7 @@ export const ConnectMyComputerResource: ResourceViewConfig = { { // TODO(ravicious): Rename this to "Test Connection" after implementing the connection test. title: 'Start a Session', - component: TestConnection, + component: LegacyTestConnection, eventName: DiscoverEvent.TestConnection, // TODO(ravicious): Manually emit success event on test connection success. manuallyEmitSuccessEvent: true, From 91f5fcb8e2a6e5ed94964c135a19183a0b309f4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Cie=C5=9Blak?= Date: Fri, 24 Nov 2023 11:03:32 +0100 Subject: [PATCH 2/7] Set up new component with feature flag --- .../TestConnection/TestConnection.tsx | 36 +++++++++++++++++++ .../ConnectMyComputer/TestConnection/index.ts | 17 +++++++++ .../src/Discover/ConnectMyComputer/index.ts | 24 ++++++++----- .../services/storageService/storageService.ts | 9 +++++ .../src/services/storageService/types.ts | 2 ++ 5 files changed, 80 insertions(+), 8 deletions(-) create mode 100644 web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/TestConnection.tsx create mode 100644 web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/index.ts diff --git a/web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/TestConnection.tsx b/web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/TestConnection.tsx new file mode 100644 index 0000000000000..ae06662cd82cc --- /dev/null +++ b/web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/TestConnection.tsx @@ -0,0 +1,36 @@ +/** + * Copyright 2023 Gravitational, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; + +import { Flex } from 'design'; + +import { Header } from 'teleport/Discover/Shared'; + +import { NodeMeta } from '../../useDiscover'; + +import type { AgentStepProps } from '../../types'; + +export const TestConnection = (props: AgentStepProps) => { + const meta = props.agentMeta as NodeMeta; + return ( + +
+
Test Connection to “{meta.node.hostname}”
+
+
+ ); +}; diff --git a/web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/index.ts b/web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/index.ts new file mode 100644 index 0000000000000..6852c35b30fc0 --- /dev/null +++ b/web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/index.ts @@ -0,0 +1,17 @@ +/** + * Copyright 2023 Gravitational, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { TestConnection } from './TestConnection'; diff --git a/web/packages/teleport/src/Discover/ConnectMyComputer/index.ts b/web/packages/teleport/src/Discover/ConnectMyComputer/index.ts index 695dd92dc4534..9c009c1e7cafa 100644 --- a/web/packages/teleport/src/Discover/ConnectMyComputer/index.ts +++ b/web/packages/teleport/src/Discover/ConnectMyComputer/index.ts @@ -17,11 +17,13 @@ import { ResourceViewConfig } from 'teleport/Discover/flow'; import { Finished, ResourceKind } from 'teleport/Discover/Shared'; import { DiscoverEvent } from 'teleport/services/userEvent'; +import { storageService } from 'teleport/services/storageService'; import { ResourceSpec } from '../SelectResource'; import { SetupConnect } from './SetupConnect'; import { LegacyTestConnection } from './LegacyTestConnection'; +import { TestConnection } from './TestConnection'; export const ConnectMyComputerResource: ResourceViewConfig = { kind: ResourceKind.ConnectMyComputer, @@ -31,14 +33,20 @@ export const ConnectMyComputerResource: ResourceViewConfig = { component: SetupConnect, eventName: DiscoverEvent.DeployService, }, - { - // TODO(ravicious): Rename this to "Test Connection" after implementing the connection test. - title: 'Start a Session', - component: LegacyTestConnection, - eventName: DiscoverEvent.TestConnection, - // TODO(ravicious): Manually emit success event on test connection success. - manuallyEmitSuccessEvent: true, - }, + storageService.isDiscoverConnectMyComputerNewConnectionTestEnabled() + ? { + title: 'Test Connection', + component: TestConnection, + eventName: DiscoverEvent.TestConnection, + // TODO(ravicious): Manually emit success event on test connection success. + manuallyEmitSuccessEvent: true, + } + : { + title: 'Start a Session', + component: LegacyTestConnection, + eventName: DiscoverEvent.TestConnection, + manuallyEmitSuccessEvent: true, + }, { title: 'Finished', component: Finished, diff --git a/web/packages/teleport/src/services/storageService/storageService.ts b/web/packages/teleport/src/services/storageService/storageService.ts index 188a7c339866f..5976deef0e3cd 100644 --- a/web/packages/teleport/src/services/storageService/storageService.ts +++ b/web/packages/teleport/src/services/storageService/storageService.ts @@ -36,6 +36,7 @@ const KEEP_LOCALSTORAGE_KEYS_ON_LOGOUT = [ KeysEnum.USER_PREFERENCES, KeysEnum.RECOMMEND_FEATURE, KeysEnum.UNIFIED_RESOURCES_DISABLED, + KeysEnum.DISCOVER_CONNECT_MY_COMPUTER_NEW_CONNECTION_TEST_ENABABLED, ]; export const storageService = { @@ -276,4 +277,12 @@ export const storageService = { JSON.stringify(true) ); }, + + isDiscoverConnectMyComputerNewConnectionTestEnabled(): boolean { + return ( + window.localStorage.getItem( + KeysEnum.DISCOVER_CONNECT_MY_COMPUTER_NEW_CONNECTION_TEST_ENABABLED + ) === 'true' + ); + }, }; diff --git a/web/packages/teleport/src/services/storageService/types.ts b/web/packages/teleport/src/services/storageService/types.ts index bc8e135ae026d..ee6106122fd85 100644 --- a/web/packages/teleport/src/services/storageService/types.ts +++ b/web/packages/teleport/src/services/storageService/types.ts @@ -36,6 +36,8 @@ export const KeysEnum = { ACCESS_GRAPH_SQL_ENABLED: 'grv_teleport_access_graph_sql_enabled', EXTERNAL_AUDIT_STORAGE_CTA_DISABLED: 'grv_teleport_external_audit_storage_disabled', + DISCOVER_CONNECT_MY_COMPUTER_NEW_CONNECTION_TEST_ENABABLED: + 'grv_teleport_discover_connect_my_computer_new_connection_test_enabled', }; // SurveyRequest is the request for sending data to the back end From 94713c107883eef24da8adc54dc5487ef0991869 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Cie=C5=9Blak?= Date: Fri, 24 Nov 2023 12:38:47 +0100 Subject: [PATCH 3/7] Copy server TestConnection to Connect My Computer --- .../TestConnection/TestConnection.tsx | 123 ++++++++++++++++-- .../src/Discover/ConnectMyComputer/index.ts | 1 - 2 files changed, 109 insertions(+), 15 deletions(-) diff --git a/web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/TestConnection.tsx b/web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/TestConnection.tsx index ae06662cd82cc..d6ecbcb5bdeff 100644 --- a/web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/TestConnection.tsx +++ b/web/packages/teleport/src/Discover/ConnectMyComputer/TestConnection/TestConnection.tsx @@ -1,11 +1,11 @@ /** - * Copyright 2023 Gravitational, Inc + * Copyright 2022 Gravitational, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -14,23 +14,118 @@ * limitations under the License. */ -import React from 'react'; +import React, { useState } from 'react'; +import { ButtonSecondary, Text, Box, LabelInput } from 'design'; +import Select from 'shared/components/Select'; -import { Flex } from 'design'; - -import { Header } from 'teleport/Discover/Shared'; +import cfg from 'teleport/config'; +import ReAuthenticate from 'teleport/components/ReAuthenticate'; +import { openNewTab } from 'teleport/lib/util'; +import { + useConnectionDiagnostic, + Header, + ActionButtons, + HeaderSubtitle, + ConnectionDiagnosticResult, + StyledBox, +} from 'teleport/Discover/Shared'; +import { sortNodeLogins } from 'teleport/services/nodes'; import { NodeMeta } from '../../useDiscover'; +import type { Option } from 'shared/components/Select'; import type { AgentStepProps } from '../../types'; +import type { MfaAuthnResponse } from 'teleport/services/mfa'; + +export function TestConnection(props: AgentStepProps) { + const { + runConnectionDiagnostic, + attempt, + diagnosis, + nextStep, + prevStep, + canTestConnection, + showMfaDialog, + cancelMfaDialog, + } = useConnectionDiagnostic(); + const node = (props.agentMeta as NodeMeta).node; + const logins = sortNodeLogins(node.sshLogins); + + function startSshSession(login: string) { + const url = cfg.getSshConnectRoute({ + clusterId: node.clusterId, + serverId: node.id, + login, + }); + + openNewTab(url); + } + + function testConnection(login: string, mfaResponse?: MfaAuthnResponse) { + runConnectionDiagnostic( + { + resourceKind: 'node', + resourceName: props.agentMeta.resourceName, + sshPrincipal: login, + }, + mfaResponse + ); + } + + const usernameOpts = logins.map(l => ({ value: l, label: l })); + // There will always be one login, as the user cannot proceed + // the step that requires users to have at least one login. + const [selectedOpt, setSelectedOpt] = useState(usernameOpts[0]); -export const TestConnection = (props: AgentStepProps) => { - const meta = props.agentMeta as NodeMeta; return ( - -
-
Test Connection to “{meta.node.hostname}”
-
-
+ + {showMfaDialog && ( + testConnection(selectedOpt.value, res)} + onClose={cancelMfaDialog} + /> + )} +
Test Connection
+ + Optionally verify that you can successfully connect to the server you + just added. + + + Step 1 + + Pick the OS user to test + + + Select Login + setSelectedOpt(o)} - isDisabled={attempt.status === 'processing'} - /> - - - testConnection(selectedOpt.value)} - stepNumber={2} - stepDescription="Verify that the server is accessible" + + {(fetchLoginsAttempt.status === '' || + fetchLoginsAttempt.status === 'processing') && } + + {fetchLoginsAttempt.status === 'error' && + (fetchLoginsAttempt.error instanceof ApiError && + fetchLoginsAttempt.error.response.status === 404 ? ( + window.location.reload()} + > + <> + For Connect My Computer to work, the role{' '} + {connectMyComputer.getRoleNameForUser(storeUser.getUsername())}{' '} + must be assigned to you. +
+ {$restartSetupInstructions} + +
+ ) : ( + + fetchLoginsAndUpdateLoginSelection(abortController.current.signal) + } + > + <>Encountered Error: {fetchLoginsAttempt.statusText} + + ))} + + {fetchLoginsAttempt.status === 'success' && + (fetchLoginsAttempt.data.length === 0 ? ( + window.location.reload()} + > + <> + The role{' '} + {connectMyComputer.getRoleNameForUser(storeUser.getUsername())}{' '} + does not contain any logins. It has likely been manually edited. +
+ {$restartSetupInstructions} + +
+ ) : ( + <> + {hasMultipleLogins && ( + + + Select Login +