Skip to content

Commit

Permalink
Hide delete button for SSO MFA devices in account settings
Browse files Browse the repository at this point in the history
An SSO device cannot be deleted and will fail if you try to delete. This
will hide the button to prevent any confusion
  • Loading branch information
avatus authored and Joerger committed Oct 11, 2024
1 parent c41e117 commit 8963f30
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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',
},
];
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -77,6 +89,23 @@ test('renders devices', () => {
});
});

test('does not render delete button on SSO devices', () => {
render(
<AuthDeviceList
header="Header"
deviceTypeColumnName="Passkey Type"
devices={ssoDevice}
/>
);
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', '']],
});

expect(screen.queryByTestId('delete-device')).not.toBeInTheDocument();
});

test('renders no devices', () => {
render(
<AuthDeviceList
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,14 @@ export function AuthDeviceList({
{
altKey: 'remove-btn',
headerText: 'Actions',
render: device => (
<RemoveCell onRemove={() => onRemove(device)} />
),
render: device => {
if (device.type === 'sso') {
// return empty cell because we don't want to delete SSO devices
// but also we want the row highlight to still work on this dummy cell
return <Cell />;
}
return <RemoveCell onRemove={() => onRemove(device)} />;
},
},
]}
data={devices}
Expand All @@ -97,7 +102,7 @@ interface RemoveCellProps {

function RemoveCell({ onRemove }: RemoveCellProps) {
return (
<Cell>
<Cell data-testid="delete-device">
<ButtonWarningBorder title="Delete" p={2} onClick={onRemove}>
<Icon.Trash size="small" />
</ButtonWarningBorder>
Expand Down
14 changes: 12 additions & 2 deletions web/packages/teleport/src/services/mfa/makeMfaDevice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,17 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { MfaDevice } from './types';
import { DeviceType, MfaDevice } from './types';

function getType(jsonType: string): DeviceType {
if (jsonType === 'TOTP') {
return 'totp';
}
if (jsonType === 'SSO') {
return 'sso';
}
return 'webauthn';
}

export default function makeMfaDevice(json): MfaDevice {
const { id, name, lastUsed, addedAt, residentKey } = json;
Expand All @@ -32,7 +42,7 @@ export default function makeMfaDevice(json): MfaDevice {
description = 'unknown device';
}

const type = json.type === 'TOTP' ? 'totp' : 'webauthn';
const type = getType(json.type);
const usage = residentKey ? 'passwordless' : 'mfa';

return {
Expand Down
2 changes: 1 addition & 1 deletion web/packages/teleport/src/services/mfa/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down

0 comments on commit 8963f30

Please sign in to comment.