Skip to content

Commit 3683627

Browse files
author
water
committed
fix: collect all active Okta push factors and validate factor status (#31759)
1 parent c20d2fe commit 3683627

1 file changed

Lines changed: 54 additions & 4 deletions

File tree

builtin/credential/okta/backend.go

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ func (b *backend) Login(ctx context.Context, req *logical.Request, username, pas
9898
Id string `json:"id"`
9999
Type string `json:"factorType"`
100100
Provider string `json:"provider"`
101+
Status string `json:"status"`
101102
Embedded struct {
102103
Challenge struct {
103104
CorrectAnswer *int `json:"correctAnswer"`
@@ -183,7 +184,8 @@ func (b *backend) Login(ctx context.Context, req *logical.Request, username, pas
183184
break
184185
}
185186

186-
var selectedFactor, totpFactor, pushFactor *mfaFactor
187+
var selectedFactor, totpFactor *mfaFactor
188+
var pushFactors []*mfaFactor
187189

188190
// Scan for available factors
189191
for _, v := range result.Embedded.Factors {
@@ -197,11 +199,17 @@ func (b *backend) Login(ctx context.Context, req *logical.Request, username, pas
197199
continue
198200
}
199201

202+
// Skip inactive factors so they don't cause spurious auth failures
203+
// when the user has other active factors available.
204+
if v.Status != "" && v.Status != "ACTIVE" {
205+
continue
206+
}
207+
200208
switch v.Type {
201209
case mfaTOTPMethod:
202210
totpFactor = &v
203211
case mfaPushMethod:
204-
pushFactor = &v
212+
pushFactors = append(pushFactors, &v)
205213
}
206214
}
207215

@@ -211,14 +219,24 @@ func (b *backend) Login(ctx context.Context, req *logical.Request, username, pas
211219
switch {
212220
case totpFactor != nil && totp != "":
213221
selectedFactor = totpFactor
214-
case pushFactor != nil && pushFactor.Provider == oktaProvider:
215-
selectedFactor = pushFactor
222+
case len(pushFactors) > 0:
223+
// Prefer Okta Verify Push over Google Authenticator push
224+
for _, pf := range pushFactors {
225+
if pf.Provider == oktaProvider {
226+
selectedFactor = pf
227+
break
228+
}
229+
}
230+
if selectedFactor == nil {
231+
selectedFactor = pushFactors[0]
232+
}
216233
case totpFactor != nil && totp == "":
217234
return nil, logical.ErrorResponse("'totp' passcode parameter is required to perform MFA"), nil, nil
218235
default:
219236
return nil, logical.ErrorResponse("Okta Verify Push or TOTP or Google TOTP factor is required in order to perform MFA"), nil, nil
220237
}
221238

239+
verifyFactor:
222240
requestPath := fmt.Sprintf("authn/factors/%s/verify", selectedFactor.Id)
223241

224242
payload := map[string]interface{}{
@@ -278,8 +296,40 @@ func (b *backend) Login(ctx context.Context, req *logical.Request, username, pas
278296
return nil, logical.ErrorResponse("exiting pending mfa challenge"), nil, nil
279297
}
280298
case "REJECTED":
299+
// If there are more push factors, try the next one
300+
if len(pushFactors) > 1 && selectedFactor.Type == mfaPushMethod {
301+
// Remove the current factor and try the next
302+
for i, pf := range pushFactors {
303+
if pf.Id == selectedFactor.Id {
304+
pushFactors = append(pushFactors[:i], pushFactors[i+1:]...)
305+
break
306+
}
307+
}
308+
if len(pushFactors) > 0 {
309+
selectedFactor = pushFactors[0]
310+
// Reset result state for the new factor
311+
result.Status = "MFA_REQUIRED"
312+
result.FactorResult = ""
313+
goto verifyFactor
314+
}
315+
}
281316
return nil, logical.ErrorResponse("multi-factor authentication denied"), nil, nil
282317
case "TIMEOUT":
318+
// If there are more push factors, try the next one
319+
if len(pushFactors) > 1 && selectedFactor.Type == mfaPushMethod {
320+
for i, pf := range pushFactors {
321+
if pf.Id == selectedFactor.Id {
322+
pushFactors = append(pushFactors[:i], pushFactors[i+1:]...)
323+
break
324+
}
325+
}
326+
if len(pushFactors) > 0 {
327+
selectedFactor = pushFactors[0]
328+
result.Status = "MFA_REQUIRED"
329+
result.FactorResult = ""
330+
goto verifyFactor
331+
}
332+
}
283333
return nil, logical.ErrorResponse("failed to complete multi-factor authentication"), nil, nil
284334
case "SUCCESS":
285335
// Allowed

0 commit comments

Comments
 (0)