Skip to content

Commit

Permalink
fix: onboarding states generation
Browse files Browse the repository at this point in the history
This commit fixes the following issues:

- Generation of onboarding states on registration does not consider all possible
values for the acquire_on_registration configuration option.
- Generation of onboarding states on login does not consider WebAuthn
availability/capability.
  • Loading branch information
lfleischmann authored Aug 1, 2024
1 parent 1d004e3 commit c86aaa9
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 73 deletions.
109 changes: 60 additions & 49 deletions backend/flow_api/flow/login/hook_schedule_onboarding_states.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,57 +47,68 @@ func (h ScheduleOnboardingStates) determineCredentialOnboardingStates(c flowpilo
cfg := deps.Cfg
result := make([]flowpilot.StateName, 0)

alwaysAcquirePasskey := cfg.Passkey.Enabled && cfg.Passkey.AcquireOnLogin == "always"
alwaysAcquirePassword := cfg.Password.Enabled && cfg.Password.AcquireOnLogin == "always"
conditionalAcquirePasskey := cfg.Passkey.Enabled && cfg.Passkey.AcquireOnLogin == "conditional"
conditionalAcquirePassword := cfg.Password.Enabled && cfg.Password.AcquireOnLogin == "conditional"
neverAcquirePasskey := !cfg.Passkey.Enabled || cfg.Passkey.AcquireOnLogin == "never"
neverAcquirePassword := !cfg.Password.Enabled || cfg.Password.AcquireOnLogin == "never"

if alwaysAcquirePasskey && alwaysAcquirePassword {
if !hasPasskey && !hasPassword {
if !cfg.Password.Optional && cfg.Passkey.Optional {
result = append(result, shared.StatePasswordCreation, shared.StateOnboardingCreatePasskey)
} else {
result = append(result, shared.StateOnboardingCreatePasskey, shared.StatePasswordCreation)
webauthnAvailable := c.Stash().Get(shared.StashPathWebauthnAvailable).Bool()
passkeyEnabled := webauthnAvailable && deps.Cfg.Passkey.Enabled
passwordEnabled := deps.Cfg.Password.Enabled
passwordAndPasskeyEnabled := passkeyEnabled && passwordEnabled

alwaysAcquirePasskey := cfg.Passkey.AcquireOnLogin == "always"
alwaysAcquirePassword := cfg.Password.AcquireOnLogin == "always"
conditionalAcquirePasskey := cfg.Passkey.AcquireOnLogin == "conditional"
conditionalAcquirePassword := cfg.Password.AcquireOnLogin == "conditional"
neverAcquirePasskey := cfg.Passkey.AcquireOnLogin == "never"
neverAcquirePassword := cfg.Password.AcquireOnLogin == "never"

if passwordAndPasskeyEnabled {
if alwaysAcquirePasskey && alwaysAcquirePassword {
if !hasPasskey && !hasPassword {
if !cfg.Password.Optional && cfg.Passkey.Optional {
result = append(result, shared.StatePasswordCreation, shared.StateOnboardingCreatePasskey)
} else {
result = append(result, shared.StateOnboardingCreatePasskey, shared.StatePasswordCreation)
}
} else if hasPasskey && !hasPassword {
result = append(result, shared.StatePasswordCreation)
} else if !hasPasskey && hasPassword {
result = append(result, shared.StateOnboardingCreatePasskey)
}
} else if alwaysAcquirePasskey && conditionalAcquirePassword {
if !hasPasskey && !hasPassword {
result = append(result, shared.StateOnboardingCreatePasskey) // skip should lead to password onboarding
} else if !hasPasskey && hasPassword {
result = append(result, shared.StateOnboardingCreatePasskey)
}
} else if conditionalAcquirePasskey && alwaysAcquirePassword {
if !hasPasskey && !hasPassword {
result = append(result, shared.StatePasswordCreation) // skip should lead to passkey onboarding
} else if hasPasskey && !hasPassword {
result = append(result, shared.StatePasswordCreation)
}
} else if conditionalAcquirePasskey && conditionalAcquirePassword {
if !hasPasskey && !hasPassword {
result = append(result, shared.StateCredentialOnboardingChooser) // credential_onboarding_chooser can be skipped
}
} else if conditionalAcquirePasskey && neverAcquirePassword {
if !hasPasskey && !hasPassword {
result = append(result, shared.StateOnboardingCreatePasskey)
}
} else if neverAcquirePasskey && conditionalAcquirePassword {
if !hasPasskey && !hasPassword {
result = append(result, shared.StatePasswordCreation)
}
} else if neverAcquirePasskey && alwaysAcquirePassword {
if !hasPassword {
result = append(result, shared.StatePasswordCreation)
}
} else if alwaysAcquirePasskey && neverAcquirePassword {
if !hasPasskey {
result = append(result, shared.StateOnboardingCreatePasskey)
}
} else if hasPasskey && !hasPassword {
result = append(result, shared.StatePasswordCreation)
} else if !hasPasskey && hasPassword {
result = append(result, shared.StateOnboardingCreatePasskey)
}
} else if alwaysAcquirePasskey && conditionalAcquirePassword {
if !hasPasskey && !hasPassword {
result = append(result, shared.StateOnboardingCreatePasskey) // skip should lead to password onboarding
} else if !hasPasskey && hasPassword {
result = append(result, shared.StateOnboardingCreatePasskey)
}
} else if conditionalAcquirePasskey && alwaysAcquirePassword {
if !hasPasskey && !hasPassword {
result = append(result, shared.StatePasswordCreation) // skip should lead to passkey onboarding
} else if hasPasskey && !hasPassword {
result = append(result, shared.StatePasswordCreation)
}
} else if conditionalAcquirePasskey && conditionalAcquirePassword {
if !hasPasskey && !hasPassword {
result = append(result, shared.StateCredentialOnboardingChooser) // credential_onboarding_chooser can be skipped
}
} else if conditionalAcquirePasskey && neverAcquirePassword {
if !hasPasskey && !hasPassword {
result = append(result, shared.StateOnboardingCreatePasskey)
}
} else if neverAcquirePasskey && conditionalAcquirePassword {
if !hasPasskey && !hasPassword {
result = append(result, shared.StatePasswordCreation)
}
} else if neverAcquirePasskey && alwaysAcquirePassword {
if !hasPassword {
result = append(result, shared.StatePasswordCreation)
}
} else if alwaysAcquirePasskey && neverAcquirePassword {
if !hasPasskey {
result = append(result, shared.StateOnboardingCreatePasskey)
}
} else if passkeyEnabled && (alwaysAcquirePasskey || conditionalAcquirePasskey) {
result = append(result, shared.StateOnboardingCreatePasskey)
} else if passwordEnabled && (alwaysAcquirePassword || conditionalAcquirePassword) {
result = append(result, shared.StatePasswordCreation)
}

return result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,42 +166,50 @@ func (a RegisterLoginIdentifier) Execute(c flowpilot.ExecutionContext) error {
func (a RegisterLoginIdentifier) generateRegistrationStates(c flowpilot.ExecutionContext) []flowpilot.StateName {
deps := a.GetDeps(c)

stateNames := make([]flowpilot.StateName, 0)
result := make([]flowpilot.StateName, 0)

emailExists := len(c.Input().Get("email").String()) > 0
if emailExists && deps.Cfg.Email.RequireVerification {
stateNames = append(stateNames, shared.StatePasscodeConfirmation)
result = append(result, shared.StatePasscodeConfirmation)
}

webauthnAvailable := c.Stash().Get(shared.StashPathWebauthnAvailable).Bool()
passkeyEnabled := webauthnAvailable && deps.Cfg.Passkey.Enabled
passwordEnabled := deps.Cfg.Password.Enabled
bothEnabled := passkeyEnabled && passwordEnabled

alwaysPasskey := deps.Cfg.Passkey.AcquireOnRegistration == "always"
conditionalPasskey := deps.Cfg.Passkey.AcquireOnRegistration == "conditional"
alwaysPassword := deps.Cfg.Password.AcquireOnRegistration == "always"
conditionalPassword := deps.Cfg.Password.AcquireOnRegistration == "conditional"

if bothEnabled {
if conditionalPasskey && conditionalPassword {
stateNames = append(stateNames, shared.StateCredentialOnboardingChooser)
} else if alwaysPasskey && !alwaysPassword {
stateNames = append(stateNames, shared.StateOnboardingCreatePasskey)
} else if !alwaysPasskey && alwaysPassword {
stateNames = append(stateNames, shared.StatePasswordCreation)
} else if alwaysPassword && alwaysPasskey {
passwordAndPasskeyEnabled := passkeyEnabled && passwordEnabled

alwaysAcquirePasskey := deps.Cfg.Passkey.AcquireOnRegistration == "always"
conditionalAcquirePasskey := deps.Cfg.Passkey.AcquireOnRegistration == "conditional"
alwaysAcquirePassword := deps.Cfg.Password.AcquireOnRegistration == "always"
conditionalAcquirePassword := deps.Cfg.Password.AcquireOnRegistration == "conditional"
neverAcquirePasskey := deps.Cfg.Passkey.AcquireOnLogin == "never"
neverAcquirePassword := deps.Cfg.Password.AcquireOnLogin == "never"

if passwordAndPasskeyEnabled {
if alwaysAcquirePasskey && alwaysAcquirePassword {
if !deps.Cfg.Password.Optional && deps.Cfg.Passkey.Optional {
stateNames = append(stateNames, shared.StatePasswordCreation, shared.StateOnboardingCreatePasskey)
result = append(result, shared.StatePasswordCreation, shared.StateOnboardingCreatePasskey)
} else {
stateNames = append(stateNames, shared.StateOnboardingCreatePasskey, shared.StatePasswordCreation)
result = append(result, shared.StateOnboardingCreatePasskey, shared.StatePasswordCreation)
}
} else if alwaysAcquirePasskey && conditionalAcquirePassword {
result = append(result, shared.StateOnboardingCreatePasskey)
} else if conditionalAcquirePasskey && alwaysAcquirePassword {
result = append(result, shared.StatePasswordCreation)
} else if conditionalAcquirePasskey && conditionalAcquirePassword {
result = append(result, shared.StateCredentialOnboardingChooser)
} else if conditionalAcquirePasskey && neverAcquirePassword {
result = append(result, shared.StateOnboardingCreatePasskey)
} else if neverAcquirePasskey && (alwaysAcquirePassword || conditionalAcquirePassword) {
result = append(result, shared.StatePasswordCreation)
} else if (alwaysAcquirePasskey || conditionalAcquirePasskey) && neverAcquirePassword {
result = append(result, shared.StateOnboardingCreatePasskey)
}
} else if passkeyEnabled && (alwaysPasskey || conditionalPasskey) {
stateNames = append(stateNames, shared.StateOnboardingCreatePasskey)
} else if passwordEnabled && (alwaysPassword || conditionalPassword) {
stateNames = append(stateNames, shared.StatePasswordCreation)
} else if passkeyEnabled && (alwaysAcquirePasskey || conditionalAcquirePasskey) {
result = append(result, shared.StateOnboardingCreatePasskey)
} else if passwordEnabled && (alwaysAcquirePassword || conditionalAcquirePassword) {
result = append(result, shared.StatePasswordCreation)
}

return stateNames
return result
}

0 comments on commit c86aaa9

Please sign in to comment.