Skip to content

Commit

Permalink
supporting google authenticator with Okta auth (#14985)
Browse files Browse the repository at this point in the history
* supporting google authenticator with Okta auth

* minor fix

* CL

* feedback

* Update changelog/14985.txt

Co-authored-by: Calvin Leung Huang <[email protected]>

* updating docs

Co-authored-by: Calvin Leung Huang <[email protected]>
  • Loading branch information
hghaf099 and calvn authored Apr 14, 2022
1 parent 14b4685 commit 3def286
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 10 deletions.
18 changes: 12 additions & 6 deletions builtin/credential/okta/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"net/textproto"
"time"

"github.com/hashicorp/go-secure-stdlib/strutil"
"github.com/hashicorp/vault/helper/mfa"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/cidrutil"
Expand Down Expand Up @@ -63,7 +64,7 @@ type backend struct {
*framework.Backend
}

func (b *backend) Login(ctx context.Context, req *logical.Request, username, password, totp string) ([]string, *logical.Response, []string, error) {
func (b *backend) Login(ctx context.Context, req *logical.Request, username, password, totp, preferredProvider string) ([]string, *logical.Response, []string, error) {
cfg, err := b.Config(ctx, req.Storage)
if err != nil {
return nil, nil, nil, err
Expand Down Expand Up @@ -179,7 +180,11 @@ func (b *backend) Login(ctx context.Context, req *logical.Request, username, pas
for _, v := range result.Embedded.Factors {
v := v // create a new copy since we'll be taking the address later

if v.Provider != "OKTA" {
if preferredProvider != "" && preferredProvider != v.Provider {
continue
}

if !strutil.StrListContains(b.getSupportedProviders(), v.Provider) {
continue
}

Expand All @@ -191,17 +196,18 @@ func (b *backend) Login(ctx context.Context, req *logical.Request, username, pas
}
}

// Okta push and totp are currently supported. If a totp passcode is provided during
// login and is supported, that will be the preferred method.
// Okta push and totp, and Google totp are currently supported.
// If a totp passcode is provided during login and is supported,
// that will be the preferred method.
switch {
case totpFactor != nil && totp != "":
selectedFactor = totpFactor
case pushFactor != nil:
case pushFactor != nil && pushFactor.Provider == oktaProvider:
selectedFactor = pushFactor
case totpFactor != nil && totp == "":
return nil, logical.ErrorResponse("'totp' passcode parameter is required to perform MFA"), nil, nil
default:
return nil, logical.ErrorResponse("Okta Verify Push or TOTP factor is required in order to perform MFA"), nil, nil
return nil, logical.ErrorResponse("Okta Verify Push or TOTP or Google TOTP factor is required in order to perform MFA"), nil, nil
}

requestPath := fmt.Sprintf("authn/factors/%s/verify", selectedFactor.Id)
Expand Down
7 changes: 6 additions & 1 deletion builtin/credential/okta/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,16 @@ func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (*api.Secret, erro
"password": password,
}

// Okta totp code
// Okta or Google totp code
if totp, ok := m["totp"]; ok {
data["totp"] = totp
}

// provider is an optional parameter
if provider, ok := m["provider"]; ok {
data["provider"] = provider
}

// Legacy MFA support
mfa_method, ok := m["method"]
if ok {
Expand Down
22 changes: 20 additions & 2 deletions builtin/credential/okta/path_login.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,15 @@ import (
"github.com/go-errors/errors"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/policyutil"
"github.com/hashicorp/vault/sdk/helper/strutil"
"github.com/hashicorp/vault/sdk/logical"
)

const (
googleProvider = "GOOGLE"
oktaProvider = "OKTA"
)

func pathLogin(b *backend) *framework.Path {
return &framework.Path{
Pattern: `login/(?P<username>.+)`,
Expand All @@ -28,6 +34,10 @@ func pathLogin(b *backend) *framework.Path {
Type: framework.TypeString,
Description: "TOTP passcode.",
},
"provider": {
Type: framework.TypeString,
Description: "Preferred factor provider.",
},
},

Callbacks: map[logical.Operation]framework.OperationFunc{
Expand All @@ -40,6 +50,10 @@ func pathLogin(b *backend) *framework.Path {
}
}

func (b *backend) getSupportedProviders() []string {
return []string{googleProvider, oktaProvider}
}

func (b *backend) pathLoginAliasLookahead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
username := d.Get("username").(string)
if username == "" {
Expand All @@ -59,8 +73,12 @@ func (b *backend) pathLogin(ctx context.Context, req *logical.Request, d *framew
username := d.Get("username").(string)
password := d.Get("password").(string)
totp := d.Get("totp").(string)
preferredProvider := strings.ToUpper(d.Get("provider").(string))
if preferredProvider != "" && !strutil.StrListContains(b.getSupportedProviders(), preferredProvider) {
return logical.ErrorResponse(fmt.Sprintf("provider %s is not among the supported ones %v", preferredProvider, b.getSupportedProviders())), nil
}

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

// No TOTP entry is possible on renew. If push MFA is enabled it will still be triggered, however.
// Sending "" as the totp will prompt the push action if it is configured.
loginPolicies, resp, groupNames, err := b.Login(ctx, req, username, password, "")
loginPolicies, resp, groupNames, err := b.Login(ctx, req, username, password, "", "")
if err != nil || (resp != nil && resp.IsError()) {
return resp, err
}
Expand Down
3 changes: 3 additions & 0 deletions changelog/14985.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
auth/okta: Add support for Google provider TOTP type in the Okta auth method
```
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.
- `provider` `(string: <optional>)` - MFA TOTP factor provider. `GOOGLE` and `OKTA` are currently supported.

### Sample Payload

Expand Down
9 changes: 8 additions & 1 deletion website/content/docs/auth/okta.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,20 @@ 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
Okta Verify Push and TOTP MFA methods, and Google TOTP 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 both Okta TOTP and Google TOTP are enabled in your Okta account, make sure to pass in
the `provider` name to which the `totp` code belong.

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

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

The auth method uses the Okta [Authentication API](https://developer.okta.com/docs/reference/api/authn/).
Expand Down

0 comments on commit 3def286

Please sign in to comment.