open-vault/builtin/credential/radius/path_config.go
Madalyn 977af116c8 Enable generated items for more auth methods (#7513)
* enable auth method item configuration in go code

* properly parse and list generated items

* make sure we only set name on attrs if a label comes from openAPI

* correctly construct paths object for method index route

* set sensitive property on password for userpass

* remove debugger statements

* pass method model to list route template to use paths on model for tabs

* update tab generation in generated item list, undo enabling userpass users

* enable openapi generated itams for certs and userpass, update ldap to no longer have action on list endpoint

* add editType to DisplayAttributes, pull tokenutil fields into field group

* show sensitive message for sensitive fields displayed in fieldGroupShow component

* grab sensitive and editType fields from displayAttrs in openapi-to-attrs util

* make sure we don't ask for paths for secret backends since that isn't setup yet

* fix styling of sensitive text for fieldGroupShow component

* update openapi-to-attrs util test to no longer include label by default, change debugger to console.err in path-help, remove dynamic ui auth methods from tab count test

* properly log errors to the console

* capitalize This value is sensitive...

* get rid of extra padding on bottom of fieldgroupshow

* make auth methods clickable and use new confirm ux

* Update sdk/framework/path.go

Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>

* Update sdk/framework/path.go

Co-Authored-By: Jim Kalafut <jkalafut@hashicorp.com>

* add whitespace

* return intErr instead of err

* uncomment out helpUrl because we need it

* remove extra box class

* use const instead of let

* remove extra conditional since we already split the pathName later on

* ensure we request the correct url when listing generated items

* use const

* link to list and show pages

* remove dead code

* show nested item name instead of id

* add comments

* show tooltip for text-file inputs

* fix storybook

* remove extra filter

* add TODOs

* add comments

* comment out unused variables but leave them in function signature

* only link to auth methods that can be fully managed in the ui

* clean up comments

* only render tooltip if there is helpText

* rename id authMethodPath

* remove optionsForQuery since we don't need it

* add indentation

* standardize ConfirmMessage and show model name instead of id when editing

* standardize ConfirmMessage and show model name instead of id when editing

* add comments

* post to the correct updateUrl so we can edit users and groups

* use pop instead of slice

* add TODO for finding a better way to store ids

* ensure ids are handled the same way on list and show pages; fix editing and deleting

* add comment about difference between list and show urls

* use model.id instead of name since we do not need it

* remove dead code

* ensure list pages have page headers

* standardize using authMethodPath instead of method and remove dead code

* i love indentation

* remove more dead code

* use new Confirm

* show correct flash message when deleting an item

* update flash message for creating and updating

* use plus icon for creating group/user instead of an arrow
2019-10-17 16:19:14 -07:00

273 lines
8.1 KiB
Go

package radius
import (
"context"
"strings"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/tokenutil"
"github.com/hashicorp/vault/sdk/logical"
)
func pathConfig(b *backend) *framework.Path {
p := &framework.Path{
Pattern: "config",
Fields: map[string]*framework.FieldSchema{
"host": &framework.FieldSchema{
Type: framework.TypeString,
Description: "RADIUS server host",
DisplayAttrs: &framework.DisplayAttributes{
Name: "Host",
},
},
"port": &framework.FieldSchema{
Type: framework.TypeInt,
Default: 1812,
Description: "RADIUS server port (default: 1812)",
DisplayAttrs: &framework.DisplayAttributes{
Value: 1812,
},
},
"secret": &framework.FieldSchema{
Type: framework.TypeString,
Description: "Secret shared with the RADIUS server",
},
"unregistered_user_policies": &framework.FieldSchema{
Type: framework.TypeString,
Default: "",
Description: "Comma-separated list of policies to grant upon successful RADIUS authentication of an unregisted user (default: empty)",
DisplayAttrs: &framework.DisplayAttributes{
Name: "Policies for unregistered users",
},
},
"dial_timeout": &framework.FieldSchema{
Type: framework.TypeDurationSecond,
Default: 10,
Description: "Number of seconds before connect times out (default: 10)",
DisplayAttrs: &framework.DisplayAttributes{
Value: 10,
},
},
"read_timeout": &framework.FieldSchema{
Type: framework.TypeDurationSecond,
Default: 10,
Description: "Number of seconds before response times out (default: 10)",
DisplayAttrs: &framework.DisplayAttributes{
Value: 10,
},
},
"nas_port": &framework.FieldSchema{
Type: framework.TypeInt,
Default: 10,
Description: "RADIUS NAS port field (default: 10)",
DisplayAttrs: &framework.DisplayAttributes{
Name: "NAS Port",
Value: 10,
},
},
"nas_identifier": &framework.FieldSchema{
Type: framework.TypeString,
Default: "",
Description: "RADIUS NAS Identifier field (optional)",
DisplayAttrs: &framework.DisplayAttributes{
Name: "NAS Identifier",
},
},
},
ExistenceCheck: b.configExistenceCheck,
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.ReadOperation: b.pathConfigRead,
logical.CreateOperation: b.pathConfigCreateUpdate,
logical.UpdateOperation: b.pathConfigCreateUpdate,
},
HelpSynopsis: pathConfigHelpSyn,
HelpDescription: pathConfigHelpDesc,
DisplayAttrs: &framework.DisplayAttributes{
Action: "Configure",
},
}
tokenutil.AddTokenFields(p.Fields)
p.Fields["token_policies"].Description += ". This will apply to all tokens generated by this auth method, in addition to any configured for specific users."
return p
}
// Establishes dichotomy of request operation between CreateOperation and UpdateOperation.
// Returning 'true' forces an UpdateOperation, CreateOperation otherwise.
func (b *backend) configExistenceCheck(ctx context.Context, req *logical.Request, data *framework.FieldData) (bool, error) {
entry, err := b.Config(ctx, req)
if err != nil {
return false, err
}
return entry != nil, nil
}
/*
* Construct ConfigEntry struct using stored configuration.
*/
func (b *backend) Config(ctx context.Context, req *logical.Request) (*ConfigEntry, error) {
storedConfig, err := req.Storage.Get(ctx, "config")
if err != nil {
return nil, err
}
if storedConfig == nil {
return nil, nil
}
var result ConfigEntry
if err := storedConfig.DecodeJSON(&result); err != nil {
return nil, err
}
return &result, nil
}
func (b *backend) pathConfigRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
cfg, err := b.Config(ctx, req)
if err != nil {
return nil, err
}
if cfg == nil {
return nil, nil
}
data := map[string]interface{}{
"host": cfg.Host,
"port": cfg.Port,
"unregistered_user_policies": cfg.UnregisteredUserPolicies,
"dial_timeout": cfg.DialTimeout,
"read_timeout": cfg.ReadTimeout,
"nas_port": cfg.NasPort,
"nas_identifier": cfg.NasIdentifier,
}
cfg.PopulateTokenData(data)
return &logical.Response{
Data: data,
}, nil
}
func (b *backend) pathConfigCreateUpdate(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
// Build a ConfigEntry struct out of the supplied FieldData
cfg, err := b.Config(ctx, req)
if err != nil {
return nil, err
}
if cfg == nil {
cfg = &ConfigEntry{}
}
if err := cfg.ParseTokenFields(req, d); err != nil {
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
}
host, ok := d.GetOk("host")
if ok {
cfg.Host = strings.ToLower(host.(string))
} else if req.Operation == logical.CreateOperation {
cfg.Host = strings.ToLower(d.Get("host").(string))
}
if cfg.Host == "" {
return logical.ErrorResponse("config parameter `host` cannot be empty"), nil
}
port, ok := d.GetOk("port")
if ok {
cfg.Port = port.(int)
} else if req.Operation == logical.CreateOperation {
cfg.Port = d.Get("port").(int)
}
secret, ok := d.GetOk("secret")
if ok {
cfg.Secret = secret.(string)
} else if req.Operation == logical.CreateOperation {
cfg.Secret = d.Get("secret").(string)
}
if cfg.Secret == "" {
return logical.ErrorResponse("config parameter `secret` cannot be empty"), nil
}
policies := make([]string, 0)
unregisteredUserPoliciesRaw, ok := d.GetOk("unregistered_user_policies")
if ok {
unregisteredUserPoliciesStr := unregisteredUserPoliciesRaw.(string)
if strings.TrimSpace(unregisteredUserPoliciesStr) != "" {
policies = strings.Split(unregisteredUserPoliciesStr, ",")
for _, policy := range policies {
if policy == "root" {
return logical.ErrorResponse("root policy cannot be granted by an auth method"), nil
}
}
}
cfg.UnregisteredUserPolicies = policies
} else if req.Operation == logical.CreateOperation {
cfg.UnregisteredUserPolicies = policies
}
dialTimeout, ok := d.GetOk("dial_timeout")
if ok {
cfg.DialTimeout = dialTimeout.(int)
} else if req.Operation == logical.CreateOperation {
cfg.DialTimeout = d.Get("dial_timeout").(int)
}
readTimeout, ok := d.GetOk("read_timeout")
if ok {
cfg.ReadTimeout = readTimeout.(int)
} else if req.Operation == logical.CreateOperation {
cfg.ReadTimeout = d.Get("read_timeout").(int)
}
nasPort, ok := d.GetOk("nas_port")
if ok {
cfg.NasPort = nasPort.(int)
} else if req.Operation == logical.CreateOperation {
cfg.NasPort = d.Get("nas_port").(int)
}
nasIdentifier, ok := d.GetOk("nas_identifier")
if ok {
cfg.NasIdentifier = nasIdentifier.(string)
} else if req.Operation == logical.CreateOperation {
cfg.NasIdentifier = d.Get("nas_identifier").(string)
}
entry, err := logical.StorageEntryJSON("config", cfg)
if err != nil {
return nil, err
}
if err := req.Storage.Put(ctx, entry); err != nil {
return nil, err
}
return nil, nil
}
type ConfigEntry struct {
tokenutil.TokenParams
Host string `json:"host" structs:"host" mapstructure:"host"`
Port int `json:"port" structs:"port" mapstructure:"port"`
Secret string `json:"secret" structs:"secret" mapstructure:"secret"`
UnregisteredUserPolicies []string `json:"unregistered_user_policies" structs:"unregistered_user_policies" mapstructure:"unregistered_user_policies"`
DialTimeout int `json:"dial_timeout" structs:"dial_timeout" mapstructure:"dial_timeout"`
ReadTimeout int `json:"read_timeout" structs:"read_timeout" mapstructure:"read_timeout"`
NasPort int `json:"nas_port" structs:"nas_port" mapstructure:"nas_port"`
NasIdentifier string `json:"nas_identifier" structs:"nas_identifier" mapstructure:"nas_identifier"`
}
const pathConfigHelpSyn = `
Configure the RADIUS server to connect to, along with its options.
`
const pathConfigHelpDesc = `
This endpoint allows you to configure the RADIUS server to connect to and its
configuration options.
`