diff --git a/web/packages/teleport/src/Account/ManageDevices/AuthDeviceList/AuthDeviceList.story.tsx b/web/packages/teleport/src/Account/ManageDevices/AuthDeviceList/AuthDeviceList.story.tsx
index ba8678459ac13..7841bdf4ff680 100644
--- a/web/packages/teleport/src/Account/ManageDevices/AuthDeviceList/AuthDeviceList.story.tsx
+++ b/web/packages/teleport/src/Account/ManageDevices/AuthDeviceList/AuthDeviceList.story.tsx
@@ -111,4 +111,13 @@ const devices: MfaDevice[] = [
type: 'webauthn',
usage: 'passwordless',
},
+ {
+ id: '5',
+ description: 'sso provider',
+ name: 'okta',
+ registeredDate: new Date(1612493852000),
+ lastUsedDate: new Date(1614481052000),
+ type: 'sso',
+ usage: 'mfa',
+ },
];
diff --git a/web/packages/teleport/src/Account/ManageDevices/AuthDeviceList/AuthDeviceList.test.tsx b/web/packages/teleport/src/Account/ManageDevices/AuthDeviceList/AuthDeviceList.test.tsx
index 3e809cae0a538..10e4781b2071d 100644
--- a/web/packages/teleport/src/Account/ManageDevices/AuthDeviceList/AuthDeviceList.test.tsx
+++ b/web/packages/teleport/src/Account/ManageDevices/AuthDeviceList/AuthDeviceList.test.tsx
@@ -45,6 +45,18 @@ const devices: MfaDevice[] = [
},
];
+const ssoDevice: MfaDevice[] = [
+ {
+ id: '1',
+ description: 'SSO Provider',
+ name: 'okta',
+ registeredDate: new Date(1628799417000),
+ lastUsedDate: new Date(1628799417000),
+ type: 'sso',
+ usage: 'mfa',
+ },
+];
+
function getTableCellContents() {
const [header, ...rows] = screen.getAllByRole('row');
return {
@@ -75,6 +87,32 @@ test('renders devices', () => {
['Hardware Key', 'yubikey', '2021-06-15', '2021-06-18', ''],
],
});
+
+ const buttons = screen.queryAllByTitle('Delete');
+ expect(buttons).toHaveLength(2);
+ // all buttons should be enabled
+ buttons.forEach(button => {
+ expect(button).toBeEnabled();
+ });
+});
+
+test('delete button is disabled for sso devices', () => {
+ render(
+
+ );
+ expect(screen.getByText('Header')).toBeInTheDocument();
+ expect(getTableCellContents()).toEqual({
+ header: ['Passkey Type', 'Nickname', 'Added', 'Last Used', 'Actions'],
+ rows: [['SSO Provider', 'okta', '2021-08-12', '2021-08-12', '']],
+ });
+
+ const button = screen.getByTitle('SSO device cannot be deleted');
+ expect(button).toBeInTheDocument();
+ expect(button).toBeDisabled();
});
test('renders no devices', () => {
diff --git a/web/packages/teleport/src/Account/ManageDevices/AuthDeviceList/AuthDeviceList.tsx b/web/packages/teleport/src/Account/ManageDevices/AuthDeviceList/AuthDeviceList.tsx
index dcc3af1da3ac4..ed1b94964ea8b 100644
--- a/web/packages/teleport/src/Account/ManageDevices/AuthDeviceList/AuthDeviceList.tsx
+++ b/web/packages/teleport/src/Account/ManageDevices/AuthDeviceList/AuthDeviceList.tsx
@@ -72,9 +72,14 @@ export function AuthDeviceList({
{
altKey: 'remove-btn',
headerText: 'Actions',
- render: device => (
- onRemove(device)} />
- ),
+ render: device => {
+ return (
+ onRemove(device)}
+ />
+ );
+ },
},
]}
data={devices}
@@ -93,12 +98,18 @@ export function AuthDeviceList({
interface RemoveCellProps {
onRemove?: () => void;
+ isSsoDevice?: boolean;
}
-function RemoveCell({ onRemove }: RemoveCellProps) {
+function RemoveCell({ onRemove, isSsoDevice }: RemoveCellProps) {
return (
-
-
+
+
|
diff --git a/web/packages/teleport/src/services/mfa/makeMfaDevice.ts b/web/packages/teleport/src/services/mfa/makeMfaDevice.ts
index dec83f762e4e0..2547f4d720c28 100644
--- a/web/packages/teleport/src/services/mfa/makeMfaDevice.ts
+++ b/web/packages/teleport/src/services/mfa/makeMfaDevice.ts
@@ -16,7 +16,17 @@
* along with this program. If not, see .
*/
-import { MfaDevice } from './types';
+import { DeviceType, MfaDevice } from './types';
+
+function getType(deviceTypeFromJsonResponse: string): DeviceType {
+ if (deviceTypeFromJsonResponse === 'TOTP') {
+ return 'totp';
+ }
+ if (deviceTypeFromJsonResponse === 'SSO') {
+ return 'sso';
+ }
+ return 'webauthn';
+}
export default function makeMfaDevice(json): MfaDevice {
const { id, name, lastUsed, addedAt, residentKey } = json;
@@ -26,11 +36,13 @@ export default function makeMfaDevice(json): MfaDevice {
description = 'Authenticator App';
} else if (json.type === 'U2F' || json.type === 'WebAuthn') {
description = 'Hardware Key';
+ } else if (json.type === 'SSO') {
+ description = 'SSO Provider';
} else {
description = 'unknown device';
}
- const type = json.type === 'TOTP' ? 'totp' : 'webauthn';
+ const type = getType(json.type);
const usage = residentKey ? 'passwordless' : 'mfa';
return {
diff --git a/web/packages/teleport/src/services/mfa/types.ts b/web/packages/teleport/src/services/mfa/types.ts
index 401bee906d3b5..6d1752c4082a1 100644
--- a/web/packages/teleport/src/services/mfa/types.ts
+++ b/web/packages/teleport/src/services/mfa/types.ts
@@ -45,7 +45,7 @@ export type SaveNewHardwareDeviceRequest = {
credential: Credential;
};
-export type DeviceType = 'totp' | 'webauthn';
+export type DeviceType = 'totp' | 'webauthn' | 'sso';
// MfaAuthnResponse is a response to a MFA device challenge.
export type MfaAuthnResponse =
|