Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TOTP support to Okta Auth #10942

Merged
merged 7 commits into from
Feb 22, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions builtin/credential/okta/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ import (
"github.com/okta/okta-sdk-golang/v2/okta"
)

const (
mfaPushMethod = "push"
mfaTOTPMethod = "token:software:totp"
)

func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) {
b := Backend()
if err := b.Setup(ctx, conf); err != nil {
Expand Down Expand Up @@ -57,7 +62,7 @@ type backend struct {
*framework.Backend
}

func (b *backend) Login(ctx context.Context, req *logical.Request, username string, password string) ([]string, *logical.Response, []string, error) {
func (b *backend) Login(ctx context.Context, req *logical.Request, username, password, totp string) ([]string, *logical.Response, []string, error) {
kalafut marked this conversation as resolved.
Show resolved Hide resolved
cfg, err := b.Config(ctx, req.Storage)
if err != nil {
return nil, nil, nil, err
Expand Down Expand Up @@ -160,6 +165,8 @@ func (b *backend) Login(ctx context.Context, req *logical.Request, username stri
// active factor enrollment). This bypass removes visibility
// into the authenticating user's password expiry, but still ensures the
// credentials are valid and the user is not locked out.
//
// API reference: https://developer.okta.com/docs/reference/api/authn/#verify-factor
if cfg.BypassOktaMFA {
result.Status = "SUCCESS"
break
Expand All @@ -168,22 +175,39 @@ func (b *backend) Login(ctx context.Context, req *logical.Request, username stri
factorAvailable := false

var selectedFactor mfaFactor
// only okta push is currently supported

// Okta push and totp are currently supported. If a totp passcode is provided during
// login and is supported, that will be the preferred method.
for _, v := range result.Embedded.Factors {
if v.Type == "push" && v.Provider == "OKTA" {
if v.Provider != "OKTA" {
continue
}

if v.Type == mfaTOTPMethod && totp != "" {
kalafut marked this conversation as resolved.
Show resolved Hide resolved
selectedFactor = v
factorAvailable = true
break
}

if v.Type == mfaPushMethod {
selectedFactor = v
factorAvailable = true
}
}

if !factorAvailable {
return nil, logical.ErrorResponse("Okta Verify Push factor is required in order to perform MFA"), nil, nil
return nil, logical.ErrorResponse("Okta Verify Push or TOTP factor is required in order to perform MFA"), nil, nil
}

requestPath := fmt.Sprintf("authn/factors/%s/verify", selectedFactor.Id)

payload := map[string]interface{}{
"stateToken": result.StateToken,
}
if selectedFactor.Type == mfaTOTPMethod {
payload["passCode"] = totp
}

verifyReq, err := shim.NewRequest("POST", requestPath, payload)
if err != nil {
return nil, nil, nil, err
Expand Down
9 changes: 2 additions & 7 deletions builtin/credential/okta/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,8 @@ func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (*api.Secret, erro
"password": password,
}

mfa_method, ok := m["method"]
kalafut marked this conversation as resolved.
Show resolved Hide resolved
if ok {
data["method"] = mfa_method
}
mfa_passcode, ok := m["passcode"]
if ok {
data["passcode"] = mfa_passcode
if totp, ok := m["totp"]; ok {
data["totp"] = totp
}

path := fmt.Sprintf("auth/%s/login/%s", mount, username)
Expand Down
14 changes: 10 additions & 4 deletions builtin/credential/okta/path_login.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,19 @@ func pathLogin(b *backend) *framework.Path {
return &framework.Path{
Pattern: `login/(?P<username>.+)`,
Fields: map[string]*framework.FieldSchema{
"username": &framework.FieldSchema{
"username": {
Type: framework.TypeString,
Description: "Username to be used for login.",
},

"password": &framework.FieldSchema{
"password": {
Type: framework.TypeString,
Description: "Password for this user.",
},
"totp": {
Type: framework.TypeString,
Description: "TOTP passcode.",
},
},

Callbacks: map[logical.Operation]framework.OperationFunc{
Expand Down Expand Up @@ -54,8 +58,9 @@ func (b *backend) pathLoginAliasLookahead(ctx context.Context, req *logical.Requ
func (b *backend) pathLogin(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
username := d.Get("username").(string)
password := d.Get("password").(string)
totp := d.Get("totp").(string)

policies, resp, groupNames, err := b.Login(ctx, req, username, password)
policies, resp, groupNames, err := b.Login(ctx, req, username, password, totp)
// Handle an internal error
if err != nil {
return nil, err
Expand Down Expand Up @@ -117,7 +122,8 @@ func (b *backend) pathLoginRenew(ctx context.Context, req *logical.Request, d *f
return nil, err
}

loginPolicies, resp, groupNames, err := b.Login(ctx, req, username, password)
// No TOTP entry is possible on renew. If push MFA is enabled it will still be triggered, however.
kalafut marked this conversation as resolved.
Show resolved Hide resolved
loginPolicies, resp, groupNames, err := b.Login(ctx, req, username, password, "")
if err != nil || (resp != nil && resp.IsError()) {
return resp, err
}
Expand Down
1 change: 1 addition & 0 deletions website/content/api-docs/auth/okta.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ Login with the username and password.

- `username` `(string: <required>)` - Username for this user.
- `password` `(string: <required>)` - Password for the authenticating user.
- `totp` `(string: <optional>)` - Okta Verify TOTP passcode.

### Sample Payload

Expand Down
15 changes: 15 additions & 0 deletions website/content/docs/auth/okta.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,21 @@ The response will contain a token at `auth.client_token`:
}
```

### MFA

Okta Verify Push and TOTP MFA methods are supported during login. For TOTP, the current
passcode may be provided via the `totp` parameter:

```shell-session
$ vault login -method=okta username=my-username totp=123456
```

If `totp` is not set and MFA Push is configured in Okta, a Push will be sent during login.

Note that this MFA support is integrated with Okta Auth and is limited strictly to login
operations. It is not related to [Enterprise MFA](https://www.vaultproject.io/docs/enterprise/mfa).


## Configuration

Auth methods must be configured in advance before users or machines can
Expand Down