Skip to content

Commit

Permalink
Refactor useReauthenticate and Reauthenticate component.
Browse files Browse the repository at this point in the history
  • Loading branch information
Joerger committed Dec 3, 2024
1 parent 7a41d14 commit 81466bc
Show file tree
Hide file tree
Showing 14 changed files with 336 additions and 417 deletions.
3 changes: 0 additions & 3 deletions web/packages/teleport/src/Account/Account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -279,16 +279,13 @@ export function Account({
usage={newDeviceUsage}
auth2faType={cfg.getAuth2faType()}
privilegeToken={token}
devices={devices}
onClose={closeAddDeviceWizard}
onSuccess={onAddDeviceSuccess}
/>
)}

{deviceToRemove && (
<DeleteAuthDeviceWizard
auth2faType={cfg.getAuth2faType()}
devices={devices}
deviceToDelete={deviceToRemove}
onClose={hideRemoveDevice}
onSuccess={onDeleteDeviceSuccess}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@

import React from 'react';

import { Auth2faType } from 'shared/services';

import Dialog from 'design/Dialog';

import { http, HttpResponse, delay } from 'msw';
Expand All @@ -29,7 +27,11 @@ import { ContextProvider } from 'teleport/index';

import cfg from 'teleport/config';

import { DeviceUsage } from 'teleport/services/mfa';
import {
DeviceType,
DeviceUsage,
getMfaRegisterOptions,
} from 'teleport/services/mfa';

import {
AddAuthDeviceWizardStepProps,
Expand Down Expand Up @@ -62,23 +64,13 @@ export function ReauthenticateLimitedOptions() {
return (
<ReauthenticateStep
{...stepProps}
devices={[
{
id: '1',
description: 'Authenticator App',
name: 'gizmo',
registeredDate: new Date(1628799417000),
lastUsedDate: new Date(1628799417000),
type: 'totp',
usage: 'mfa',
},
]}
mfaChallengeOptions={[{ value: 'totp', label: 'Authenticator App' }]}
/>
);
}

export function ReauthenticateNoOptions() {
return <ReauthenticateStep {...stepProps} devices={[]} />;
return <ReauthenticateStep {...stepProps} />;
}

export function CreatePasskey() {
Expand All @@ -92,7 +84,9 @@ export function CreateMfaHardwareDevice() {
}

export function CreateMfaAppQrCodeLoading() {
return <CreateDeviceStep {...stepProps} usage="mfa" newMfaDeviceType="otp" />;
return (
<CreateDeviceStep {...stepProps} usage="mfa" newMfaDeviceType="totp" />
);
}
CreateMfaAppQrCodeLoading.parameters = {
msw: {
Expand All @@ -106,7 +100,9 @@ CreateMfaAppQrCodeLoading.parameters = {
};

export function CreateMfaAppQrCodeFailed() {
return <CreateDeviceStep {...stepProps} usage="mfa" newMfaDeviceType="otp" />;
return (
<CreateDeviceStep {...stepProps} usage="mfa" newMfaDeviceType="totp" />
);
}
CreateMfaAppQrCodeFailed.parameters = {
msw: {
Expand All @@ -129,7 +125,9 @@ const dummyQrCode =
'iVBORw0KGgoAAAANSUhEUgAAAB0AAAAdAQMAAABsXfVMAAAABlBMVEUAAAD///+l2Z/dAAAAAnRSTlP//8i138cAAAAJcEhZcwAACxIAAAsSAdLdfvwAAABrSURBVAiZY/gPBAxoxAcxh3qG71fv1zN8iQ8EEReBRACQ+H4ZKPZBFCj7/3v9f4aPU9vqGX4kFtUzfG5mBLK2aNUz/PM3AsmqAk2RNQTquLYLqDdG/z/QlGAgES4CFLu4GygrXF2Pbi+IAADZqFQFAjXZWgAAAABJRU5ErkJggg==';

export function CreateMfaApp() {
return <CreateDeviceStep {...stepProps} usage="mfa" newMfaDeviceType="otp" />;
return (
<CreateDeviceStep {...stepProps} usage="mfa" newMfaDeviceType="totp" />
);
}
CreateMfaApp.parameters = {
msw: {
Expand All @@ -153,7 +151,7 @@ export function SaveMfaHardwareDevice() {
}

export function SaveMfaAuthenticatorApp() {
return <SaveDeviceStep {...stepProps} usage="mfa" newMfaDeviceType="otp" />;
return <SaveDeviceStep {...stepProps} usage="mfa" newMfaDeviceType="totp" />;
}

const stepProps: AddAuthDeviceWizardStepProps = {
Expand All @@ -165,35 +163,24 @@ const stepProps: AddAuthDeviceWizardStepProps = {
flowLength: 1,
refCallback: () => {},

// Other props
// Shared props
privilegeToken: 'privilege-token',
usage: 'passwordless' as DeviceUsage,
auth2faType: 'on' as Auth2faType,
credential: { id: 'cred-id', type: 'public-key' },
newMfaDeviceType: 'webauthn' as Auth2faType,
devices: [
{
id: '1',
description: 'Authenticator App',
name: 'gizmo',
registeredDate: new Date(1628799417000),
lastUsedDate: new Date(1628799417000),
type: 'totp',
usage: 'mfa',
},
{
id: '2',
description: 'Hardware Key',
name: 'key',
registeredDate: new Date(1623722252000),
lastUsedDate: new Date(1623981452000),
type: 'webauthn',
usage: 'mfa',
},
],
onNewMfaDeviceTypeChange: () => {},
onDeviceCreated: () => {},
onAuthenticated: () => {},
newMfaDeviceType: 'webauthn',
onClose: () => {},
onSuccess: () => {},
usage: 'passwordless' as DeviceUsage,

// Reauth props
reauthAttempt: null,
clearReauthAttempt: () => {},
mfaChallengeOptions: getMfaRegisterOptions('on'),
submitWithMfa: async (mfaType?: DeviceType, otpCode?: string) => {},

// Create props
mfaRegisterOptions: null,
onDeviceCreated: (c: Credential) => {},
onNewMfaDeviceTypeChange: (d: DeviceType) => {},

// Save props
credential: { id: 'cred-id', type: 'public-key' },
};
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ beforeEach(() => {
jest
.spyOn(auth, 'createPrivilegeTokenWithWebauthn')
.mockResolvedValueOnce('webauthn-privilege-token');
jest.spyOn(auth, 'getMfaChallenge').mockResolvedValueOnce({
totpChallenge: true,
webauthnPublicKey: {} as PublicKeyCredentialRequestOptions,
});
jest
.spyOn(auth, 'createPrivilegeTokenWithTotp')
.mockImplementationOnce(token =>
Expand All @@ -74,7 +78,6 @@ function TestWizard(props: Partial<AddAuthDeviceWizardStepProps> = {}) {
<AddAuthDeviceWizard
usage="passwordless"
auth2faType="optional"
devices={deviceCases.all}
onClose={() => {}}
onSuccess={onSuccess}
{...props}
Expand Down Expand Up @@ -243,10 +246,8 @@ describe('flow with reauthentication', () => {
expect(onSuccess).toHaveBeenCalled();
});

test('shows all authentication options', async () => {
render(
<TestWizard usage="mfa" auth2faType="on" devices={deviceCases.all} />
);
test('shows reauthentication options', async () => {
render(<TestWizard usage="mfa" />);

const reauthenticateStep = within(
screen.getByTestId('reauthenticate-step')
Expand All @@ -258,40 +259,4 @@ describe('flow with reauthentication', () => {
reauthenticateStep.queryByLabelText(/authenticator app/i)
).toBeVisible();
});

test('limits authentication options to devices owned', async () => {
render(
<TestWizard usage="mfa" auth2faType="on" devices={deviceCases.authApps} />
);

const reauthenticateStep = within(
screen.getByTestId('reauthenticate-step')
);
expect(
reauthenticateStep.queryByLabelText(/passkey or security key/i)
).not.toBeInTheDocument();
expect(
reauthenticateStep.queryByLabelText(/authenticator app/i)
).toBeVisible();
});

test.each`
auth2faType | deviceCase | error
${'otp'} | ${'mfaDevices'} | ${/authenticator app is required/i}
${'webauthn'} | ${'authApps'} | ${/passkey or security key is required/i}
${'on'} | ${'none'} | ${/identity verification is required/i}
`(
'shows an error if no way to authenticate for MFA type "$auth2faType"',
async ({ auth2faType, deviceCase, error }) => {
render(
<TestWizard
usage="mfa"
auth2faType={auth2faType}
devices={deviceCases[deviceCase]}
/>
);

expect(screen.getByText(error)).toBeVisible();
}
);
});
Loading

0 comments on commit 81466bc

Please sign in to comment.