Skip to content
This repository has been archived by the owner on May 18, 2021. It is now read-only.

Commit

Permalink
Implement support for choosing MFA Provider and FactorType
Browse files Browse the repository at this point in the history
  • Loading branch information
lsowen committed Dec 27, 2018
1 parent a9f3d61 commit 2d5016c
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 17 deletions.
4 changes: 3 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@ func init() {
for _, backendType := range keyring.AvailableBackends() {
backendsAvailable = append(backendsAvailable, string(backendType))
}
RootCmd.PersistentFlags().StringVarP(&mfaConfig.DuoDevice, "mfa-duo-device", "m", "phone1", "Device to use phone1, phone2, u2f or token")
RootCmd.PersistentFlags().StringVarP(&mfaConfig.Provider, "mfa-provider", "", "", "MFA Provider to use (eg DUO, OKTA, GOOGLE)")
RootCmd.PersistentFlags().StringVarP(&mfaConfig.FactorType, "mfa-factor-type", "", "", "MFA Factor Type to use (eg push, token:software:totp)")
RootCmd.PersistentFlags().StringVarP(&mfaConfig.DuoDevice, "mfa-duo-device", "", "phone1", "Device to use phone1, phone2, u2f or token")
RootCmd.PersistentFlags().StringVarP(&backend, "backend", "b", "", fmt.Sprintf("Secret backend to use %s", backendsAvailable))
RootCmd.PersistentFlags().BoolVarP(&debug, "debug", "d", false, "Enable debug logging")
}
60 changes: 44 additions & 16 deletions lib/okta.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,25 +238,53 @@ func (o *OktaClient) AuthenticateProfile(profileARN string, duration time.Durati
return *samlResp.Credentials, sessionCookie, nil
}

func selectMFADevice(factors []OktaUserAuthnFactor) (*OktaUserAuthnFactor, error) {
if len(factors) > 1 {
log.Info("Select a MFA from the following list")
for i, f := range factors {
log.Infof("%d: %s (%s)", i, f.Provider, f.FactorType)
}
i, err := Prompt("Select MFA method", false)
if err != nil {
return nil, err
}
factor, err := strconv.Atoi(i)
if err != nil {
return nil, err
func selectMFADeviceFromConfig(o *OktaClient) (*OktaUserAuthnFactor, error) {
log.Debugf("MFAConfig: %v\n", o.MFAConfig)
if o.MFAConfig.Provider == "" || o.MFAConfig.FactorType == "" {
return nil, nil
}

for _, f := range o.UserAuth.Embedded.Factors {
log.Debugf("%v\n", f)
if strings.EqualFold(f.Provider, o.MFAConfig.Provider) && strings.EqualFold(f.FactorType, o.MFAConfig.FactorType) {
log.Debugf("Using matching factor \"%v %v\" from config\n", f.Provider, f.FactorType)
return &f, nil
}
return &factors[factor], nil
}

return nil, fmt.Errorf("Failed to select MFA device with Provider = \"%s\", FactorType = \"%s\"", o.MFAConfig.Provider, o.MFAConfig.FactorType)
}

func (o *OktaClient) selectMFADevice() (*OktaUserAuthnFactor, error) {
factors := o.UserAuth.Embedded.Factors
if len(factors) == 0 {
return nil, errors.New("No available MFA Factors")
} else if len(factors) == 1 {
return &factors[0], nil
}
return nil, errors.New("Failed to select MFA device")

factor, err := selectMFADeviceFromConfig(o)
if err != nil {
return nil, err
}

if factor != nil {
return factor, nil
}

log.Info("Select a MFA from the following list")
for i, f := range factors {
log.Infof("%d: %s (%s)", i, f.Provider, f.FactorType)
}
i, err := Prompt("Select MFA method", false)
if err != nil {
return nil, err
}
factorIdx, err := strconv.Atoi(i)
if err != nil {
return nil, err
}
return &factors[factorIdx], nil
}

func (o *OktaClient) preChallenge(oktaFactorId, oktaFactorType string) ([]byte, error) {
Expand Down Expand Up @@ -361,7 +389,7 @@ func (o *OktaClient) challengeMFA() (err error) {
var oktaFactorType string

log.Debugf("%s", o.UserAuth.StateToken)
factor, err := selectMFADevice(o.UserAuth.Embedded.Factors)
factor, err := o.selectMFADevice()
if err != nil {
log.Debug("Failed to select MFA device")
return
Expand Down

0 comments on commit 2d5016c

Please sign in to comment.