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

Updating Okta lib for credential backend #3245

Merged
merged 3 commits into from
Aug 31, 2017
Merged
Show file tree
Hide file tree
Changes from all 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
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