Skip to content

Commit

Permalink
Update getMfaChallengeResponse to take DeviceType and otp code.
Browse files Browse the repository at this point in the history
  • Loading branch information
Joerger committed Dec 9, 2024
1 parent cda50c0 commit 7515ca6
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,10 @@ export function ReauthenticateStep({
m === 'passwordless' ? 'required' : 'discouraged',
});

const response = await auth.getMfaChallengeResponse(challenge);
const response = await auth.getMfaChallengeResponse(
challenge,
'webauthn'
);

// TODO(Joerger): handle non-webauthn response.
onAuthenticated(response.webauthn_response);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ export default function useGetScpUrl(addMfaToScpUrls: boolean) {
scope: MfaChallengeScope.USER_SESSION,
});

const response = await auth.getMfaChallengeResponse(challenge);
const response = await auth.getMfaChallengeResponse(
challenge,
'webauthn'
);

setAttempt({
status: 'success',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export default function useReAuthenticate(props: Props) {
if ('onMfaResponse' in props) {
auth
.getMfaChallenge({ scope: props.challengeScope })
.then(auth.getMfaChallengeResponse)
.then(challenge => auth.getMfaChallengeResponse(challenge, 'webauthn'))
.catch(handleError);

return;
Expand Down
40 changes: 32 additions & 8 deletions web/packages/teleport/src/services/auth/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ const auth = {
headlessSSOAccept(transactionId: string) {
return auth
.getMfaChallenge({ scope: MfaChallengeScope.HEADLESS_LOGIN })
.then(auth.getMfaChallengeResponse)
.then(challenge => auth.getMfaChallengeResponse(challenge, 'webauthn'))
.then(res => {
const request = {
action: 'accept',
Expand Down Expand Up @@ -286,19 +286,43 @@ const auth = {

// getChallengeResponse gets an MFA challenge response for the provided parameters.
// If is_mfa_required_req is provided and it is found that MFA is not required, returns null instead.
async getMfaChallengeResponse(challenge: MfaAuthenticateChallenge) {
// TODO(Joerger): Handle sso and otp. We need to provide some global context which we
// can use to display the MFA component currently found in useMFA.
return auth.getWebAuthnChallengeResponse(challenge);
async getMfaChallengeResponse(
challenge: MfaAuthenticateChallenge,
mfaType?: DeviceType,
totpCode?: string
): Promise<MfaChallengeResponse> {
// TODO(Joerger): If mfaType is not provided by a parent component, use some global context
// to display a component, similar to the one used in useMfa. For now we just default to
// whichever method we can succeed with first.
if (!mfaType) {
if (totpCode) {
mfaType == 'totp';
} else if (challenge.webauthnPublicKey) {
mfaType == 'webauthn';
}
}

if (mfaType === 'webauthn') {
return auth.getWebAuthnChallengeResponse(challenge.webauthnPublicKey);
}

if (mfaType === 'totp') {
return {
totp_code: totpCode,
};
}

// No viable challenge, return empty response.
return null;
},

async getWebAuthnChallengeResponse(
challenge: MfaAuthenticateChallenge
webauthnPublicKey: PublicKeyCredentialRequestOptions
): Promise<MfaChallengeResponse> {
return auth.checkWebauthnSupport().then(() =>
navigator.credentials
.get({
publicKey: challenge.webauthnPublicKey,
publicKey: webauthnPublicKey,
})
.then(cred => {
return makeWebauthnAssertionResponse(cred);
Expand Down Expand Up @@ -365,7 +389,7 @@ const auth = {

return auth
.getMfaChallenge({ scope, allowReuse, isMfaRequiredRequest }, abortSignal)
.then(challenge => auth.getMfaChallengeResponse(challenge))
.then(challenge => auth.getMfaChallengeResponse(challenge, 'webauthn'))
.then(res => makeWebauthnAssertionResponse(res.webauthn_response));
},

Expand Down

0 comments on commit 7515ca6

Please sign in to comment.