Skip to content

Commit 794281d

Browse files
author
Mark Wolfe
committed
refactor U2F MFA to another function and adjust error handling
1 parent ad226b1 commit 794281d

1 file changed

Lines changed: 66 additions & 59 deletions

File tree

pkg/provider/okta/okta.go

Lines changed: 66 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -759,76 +759,83 @@ func verifyMfa(oc *Client, oktaOrgHost string, loginDetails *creds.LoginDetails,
759759
return gjson.GetBytes(body, "sessionToken").String(), nil
760760

761761
case IdentifierFIDOWebAuthn:
762-
var authErr error
763-
var signedAssertion *SignedAssertion
764-
challengeResponseBody := challengeContext.challengeResponseBody
765-
lastMfaOption := mfaOption
766-
767-
for {
768-
nonce := gjson.Get(challengeResponseBody, "_embedded.factor._embedded.challenge.challenge").String()
769-
credentialID := gjson.Get(challengeResponseBody, "_embedded.factor.profile.credentialId").String()
770-
version := gjson.Get(challengeResponseBody, "_embedded.factor.profile.version").String()
771-
772-
fidoClient, err := NewFidoClient(
773-
nonce,
774-
oktaOrgHost,
775-
version,
776-
credentialID,
777-
stateToken,
778-
new(U2FDeviceFinder),
779-
)
762+
return fidoWebAuthn(oc, oktaOrgHost, challengeContext, mfaOption, stateToken, mfaOptions, resp)
763+
}
780764

781-
if err != nil {
782-
return "", err
783-
}
765+
// catch all
766+
return "", errors.New("no mfa options provided")
767+
}
784768

785-
signedAssertion, authErr = fidoClient.ChallengeU2F()
769+
func fidoWebAuthn(oc *Client, oktaOrgHost string, challengeContext *mfaChallengeContext, mfaOption int, stateToken string, mfaOptions []string, resp string) (string, error) {
770+
771+
var signedAssertion *SignedAssertion
772+
challengeResponseBody := challengeContext.challengeResponseBody
773+
lastMfaOption := mfaOption
774+
775+
for {
776+
nonce := gjson.Get(challengeResponseBody, "_embedded.factor._embedded.challenge.challenge").String()
777+
credentialID := gjson.Get(challengeResponseBody, "_embedded.factor.profile.credentialId").String()
778+
version := gjson.Get(challengeResponseBody, "_embedded.factor.profile.version").String()
779+
780+
fidoClient, err := NewFidoClient(
781+
nonce,
782+
oktaOrgHost,
783+
version,
784+
credentialID,
785+
stateToken,
786+
new(U2FDeviceFinder),
787+
)
788+
if err != nil {
789+
return "", err
790+
}
786791

787-
if _, ok := authErr.(*u2fhost.BadKeyHandleError); ok {
788-
nextMfaOption := findMfaOption(oc.mfa, mfaOptions, lastMfaOption)
789-
if nextMfaOption <= lastMfaOption {
790-
return "", authErr
791-
}
792-
lastMfaOption = nextMfaOption
792+
signedAssertion, err = fidoClient.ChallengeU2F()
793+
if err != nil {
794+
// if this error is not a bad key error we are done
795+
if _, ok := err.(*u2fhost.BadKeyHandleError); !ok {
796+
return "", errors.Wrap(err, "failed to perform U2F challenge")
797+
}
793798

794-
nextChallengeContext, err := getMfaChallengeContext(oc, nextMfaOption, resp)
795-
if err != nil {
796-
return "", err
797-
}
798-
challengeResponseBody = nextChallengeContext.challengeResponseBody
799-
continue
799+
// check if there is another fido device and try that
800+
nextMfaOption := findMfaOption(oc.mfa, mfaOptions, lastMfaOption)
801+
if nextMfaOption <= lastMfaOption {
802+
return "", errors.Wrap(err, "tried all MFA options")
800803
}
804+
lastMfaOption = nextMfaOption
801805

806+
nextChallengeContext, err := getMfaChallengeContext(oc, nextMfaOption, resp)
802807
if err != nil {
803-
return "", err
808+
return "", errors.Wrap(err, "get mfa challenge failed for U2F device")
804809
}
805-
806-
break
810+
challengeResponseBody = nextChallengeContext.challengeResponseBody
811+
continue
807812
}
808813

809-
payload, err := json.Marshal(signedAssertion)
810-
if err != nil {
811-
return "", err
812-
}
814+
break
815+
}
813816

814-
webauthnCallback := gjson.Get(challengeResponseBody, "_links.next.href").String()
815-
req, err := http.NewRequest("POST", webauthnCallback, strings.NewReader(string(payload)))
816-
if err != nil {
817-
return "", errors.Wrap(err, "error building authentication request")
818-
}
819-
req.Header.Add("Accept", "application/json")
820-
req.Header.Add("Content-Type", "application/json")
821-
res, err := oc.client.Do(req)
822-
if err != nil {
823-
return "", errors.Wrap(err, "error retrieving verify response")
824-
}
825-
body, err := ioutil.ReadAll(res.Body)
826-
if err != nil {
827-
return "", errors.Wrap(err, "error retrieving body from response")
828-
}
829-
return gjson.GetBytes(body, "sessionToken").String(), nil
817+
payload, err := json.Marshal(signedAssertion)
818+
if err != nil {
819+
return "", err
830820
}
831821

832-
// catch all
833-
return "", errors.New("no mfa options provided")
822+
webauthnCallback := gjson.Get(challengeResponseBody, "_links.next.href").String()
823+
req, err := http.NewRequest("POST", webauthnCallback, strings.NewReader(string(payload)))
824+
if err != nil {
825+
return "", errors.Wrap(err, "error building authentication request")
826+
}
827+
828+
req.Header.Add("Accept", "application/json")
829+
req.Header.Add("Content-Type", "application/json")
830+
res, err := oc.client.Do(req)
831+
if err != nil {
832+
return "", errors.Wrap(err, "error retrieving verify response")
833+
}
834+
835+
body, err := ioutil.ReadAll(res.Body)
836+
if err != nil {
837+
return "", errors.Wrap(err, "error retrieving body from response")
838+
}
839+
840+
return gjson.GetBytes(body, "sessionToken").String(), nil
834841
}

0 commit comments

Comments
 (0)