Skip to content

Commit

Permalink
Remove circular dependency with auth.
Browse files Browse the repository at this point in the history
  • Loading branch information
Joerger committed Jan 3, 2025
1 parent 4d8260d commit 2f056e0
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 2 deletions.
2 changes: 2 additions & 0 deletions web/packages/teleport/src/MFAContext/MFAContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createContext, PropsWithChildren, useCallback, useState } from 'react';

import AuthnDialog from 'teleport/components/AuthnDialog';
import { useMfa } from 'teleport/lib/useMfa';
import api from 'teleport/services/api/api';
import { CreateAuthenticateChallengeRequest } from 'teleport/services/auth';
import auth from 'teleport/services/auth/auth';
import { MfaChallengeResponse } from 'teleport/services/mfa';
Expand Down Expand Up @@ -43,6 +44,7 @@ export const MfaContextProvider = ({ children }: PropsWithChildren) => {
const mfaCtx = { getMfaChallengeResponse };
setMfaCtx(mfaCtx);
auth.setMfaContext(mfaCtx);
api.setMfaContext(mfaCtx);
}

return (
Expand Down
36 changes: 34 additions & 2 deletions web/packages/teleport/src/services/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,22 @@ import websession from 'teleport/services/websession';

import 'whatwg-fetch';

import auth from '../auth/auth';
import { MfaContextValue } from 'teleport/MFAContext/MFAContext';

import { MfaChallengeScope } from '../auth/auth';
import { MfaChallengeResponse } from '../mfa';
import { storageService } from '../storageService';
import parseError, { ApiError } from './parseError';

export const MFA_HEADER = 'Teleport-Mfa-Response';

let mfaContext: MfaContextValue;

const api = {
setMfaContext(mfa: MfaContextValue) {
mfaContext = mfa;
},

get(
url: string,
abortSignal?: AbortSignal,
Expand Down Expand Up @@ -191,7 +199,7 @@ const api = {

let mfaResponseForRetry;
try {
mfaResponseForRetry = await auth.getAdminActionMfaResponse();
mfaResponseForRetry = await api.getAdminActionMfaResponse();
} catch {
throw new Error(
'This is an admin-level API request and requires MFA verification. Please try again with a registered MFA device. If you do not have an MFA device registered, you can add one in the account settings page.'
Expand All @@ -205,6 +213,30 @@ const api = {
);
},

getAdminActionMfaResponse(allowReuse?: boolean) {
// mfaContext is set once the react-scoped MFA Context Provider is initialized.
// Since this is a global object outside of the react scope, there is a marginal
// chance for a race condition here (the react scope should generally be initialized
// before this has a chance of being called). This conditional is not expected to
// be hit, but will catch any major issues that could arise from this solution.
if (!mfaContext) {
setTimeout(() => {
if (!mfaContext)
throw new Error(
'Failed to set up MFA prompt for admin action. This is a bug.'
);
}, 1000);
}

return mfaContext.getMfaChallengeResponse({
scope: MfaChallengeScope.ADMIN_ACTION,
allowReuse,
isMfaRequiredRequest: {
admin_action: {},
},
});
},

/**
* fetch calls upon native fetch with options and headers set
* to default (or provided) values.
Expand Down

0 comments on commit 2f056e0

Please sign in to comment.