Skip to content

Commit

Permalink
Updating Okta lib for credential backend (#3245)
Browse files Browse the repository at this point in the history
* migrating to chrismalek/oktasdk-go Okta library

* updating path docs

* updating bool reference from config
  • Loading branch information
chrishoffman authored and jefferai committed Aug 31, 2017
1 parent 0d985f6 commit e54a3db
Show file tree
Hide file tree
Showing 18 changed files with 1,788 additions and 391 deletions.
50 changes: 30 additions & 20 deletions builtin/credential/okta/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package okta
import (
"fmt"

"github.com/chrismalek/oktasdk-go/okta"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
)
Expand Down Expand Up @@ -56,18 +57,44 @@ func (b *backend) Login(req *logical.Request, username string, password string)
}

client := cfg.OktaClient()
auth, err := client.Authenticate(username, password)

type embeddedResult struct {
User okta.User `json:"user"`
}

type authResult struct {
Embedded embeddedResult `json:"_embedded"`
}

authReq, err := client.NewRequest("POST", "authn", map[string]interface{}{
"username": username,
"password": password,
})
if err != nil {
return nil, nil, err
}

var result authResult
rsp, err := client.Do(authReq, &result)
if err != nil {
return nil, logical.ErrorResponse(fmt.Sprintf("Okta auth failed: %v", err)), nil
}
if auth == nil {
if rsp == nil {
return nil, logical.ErrorResponse("okta auth backend unexpected failure"), nil
}

oktaGroups, err := b.getOktaGroups(cfg, auth.Embedded.User.ID)
oktaUser := &result.Embedded.User
rsp, err = client.Users.PopulateGroups(oktaUser)
if err != nil {
return nil, logical.ErrorResponse(err.Error()), nil
}
if rsp == nil {
return nil, logical.ErrorResponse("okta auth backend unexpected failure"), nil
}
oktaGroups := make([]string, 0, len(oktaUser.Groups))
for _, group := range oktaUser.Groups {
oktaGroups = append(oktaGroups, group.Profile.Name)
}
if b.Logger().IsDebug() {
b.Logger().Debug("auth/okta: Groups fetched from Okta", "num_groups", len(oktaGroups), "groups", oktaGroups)
}
Expand Down Expand Up @@ -130,23 +157,6 @@ func (b *backend) Login(req *logical.Request, username string, password string)
return policies, oktaResponse, nil
}

func (b *backend) getOktaGroups(cfg *ConfigEntry, userID string) ([]string, error) {
if cfg.Token != "" {
client := cfg.OktaClient()
groups, err := client.Groups(userID)
if err != nil {
return nil, err
}

oktaGroups := make([]string, 0, len(*groups))
for _, group := range *groups {
oktaGroups = append(oktaGroups, group.Profile.Name)
}
return oktaGroups, err
}
return nil, nil
}

const backendHelp = `
The Okta credential provider allows authentication querying,
checking username and password, and associating policies. If an api token is configure
Expand Down
85 changes: 61 additions & 24 deletions builtin/credential/okta/path_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package okta
import (
"fmt"
"net/url"
"strings"

"time"

"github.com/chrismalek/oktasdk-go/okta"
"github.com/hashicorp/go-cleanhttp"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
"github.com/sstarcher/go-okta"
)

func pathConfig(b *backend) *framework.Path {
Expand All @@ -17,16 +19,29 @@ func pathConfig(b *backend) *framework.Path {
Fields: map[string]*framework.FieldSchema{
"organization": &framework.FieldSchema{
Type: framework.TypeString,
Description: "Okta organization to authenticate against",
Description: "Okta organization to authenticate against (DEPRECATED)",
},
"org_name": &framework.FieldSchema{
Type: framework.TypeString,
Description: "Name of the organization to be used in the Okta API.",
},
"token": &framework.FieldSchema{
Type: framework.TypeString,
Description: "Okta admin API token",
Description: "Okta admin API token (DEPRECATED)",
},
"api_token": &framework.FieldSchema{
Type: framework.TypeString,
Description: "Okta API key.",
},
"base_url": &framework.FieldSchema{
Type: framework.TypeString,
Description: `The API endpoint to use. Useful if you
are using Okta development accounts.`,
are using Okta development accounts. (DEPRECATED)`,
},
"production": &framework.FieldSchema{
Type: framework.TypeBool,
Default: true,
Description: `If set, production API URL prefix will be used to communicate with Okta and if not set, a preview production API URL prefix will be used. Defaults to true.`,
},
"ttl": &framework.FieldSchema{
Type: framework.TypeDurationSecond,
Expand Down Expand Up @@ -84,11 +99,15 @@ func (b *backend) pathConfigRead(
resp := &logical.Response{
Data: map[string]interface{}{
"organization": cfg.Org,
"base_url": cfg.BaseURL,
"org_name": cfg.Org,
"production": *cfg.Production,
"ttl": cfg.TTL,
"max_ttl": cfg.MaxTTL,
},
}
if cfg.BaseURL != "" {
resp.Data["base_url"] = cfg.BaseURL
}

return resp, nil
}
Expand All @@ -106,18 +125,32 @@ func (b *backend) pathConfigWrite(
cfg = &ConfigEntry{}
}

org, ok := d.GetOk("organization")
org, ok := d.GetOk("org_name")
if ok {
cfg.Org = org.(string)
} else if req.Operation == logical.CreateOperation {
cfg.Org = d.Get("organization").(string)
}
if cfg.Org == "" {
org, ok = d.GetOk("organization")
if ok {
cfg.Org = org.(string)
}
}
if cfg.Org == "" && req.Operation == logical.CreateOperation {
return logical.ErrorResponse("org_name is missing"), nil
}

token, ok := d.GetOk("token")
token, ok := d.GetOk("api_token")
if ok {
cfg.Token = token.(string)
} else if req.Operation == logical.CreateOperation {
cfg.Token = d.Get("token").(string)
}
if cfg.Token == "" {
token, ok = d.GetOk("token")
if ok {
cfg.Token = token.(string)
}
}
if cfg.Token == "" && req.Operation == logical.CreateOperation {
return logical.ErrorResponse("api_token is missing"), nil
}

baseURL, ok := d.GetOk("base_url")
Expand All @@ -134,6 +167,9 @@ func (b *backend) pathConfigWrite(
cfg.BaseURL = d.Get("base_url").(string)
}

productionRaw := d.Get("production").(bool)
cfg.Production = &productionRaw

ttl, ok := d.GetOk("ttl")
if ok {
cfg.TTL = time.Duration(ttl.(int)) * time.Second
Expand Down Expand Up @@ -171,25 +207,26 @@ func (b *backend) pathConfigExistenceCheck(

// OktaClient creates a basic okta client connection
func (c *ConfigEntry) OktaClient() *okta.Client {
client := okta.NewClient(c.Org)
if c.BaseURL != "" {
client.Url = c.BaseURL
production := true
if c.Production != nil {
production = *c.Production
}

if c.Token != "" {
client.ApiToken = c.Token
if c.BaseURL != "" {
if strings.Contains(c.BaseURL, "oktapreview.com") {
production = false
}
}

return client
return okta.NewClient(cleanhttp.DefaultClient(), c.Org, c.Token, production)
}

// ConfigEntry for Okta
type ConfigEntry struct {
Org string `json:"organization"`
Token string `json:"token"`
BaseURL string `json:"base_url"`
TTL time.Duration `json:"ttl"`
MaxTTL time.Duration `json:"max_ttl"`
Org string `json:"organization"`
Token string `json:"token"`
BaseURL string `json:"base_url"`
Production *bool `json:"is_production,omitempty"`
TTL time.Duration `json:"ttl"`
MaxTTL time.Duration `json:"max_ttl"`
}

const pathConfigHelp = `
Expand Down
21 changes: 21 additions & 0 deletions vendor/github.com/chrismalek/oktasdk-go/LICENSE.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit e54a3db

Please sign in to comment.