Add WithOptions methods to audit/auth enabling (#2383)

This commit is contained in:
Jeff Mitchell 2017-02-16 11:37:27 -05:00 committed by GitHub
parent 0044ea8917
commit e0c9bfd926
10 changed files with 167 additions and 17 deletions

View file

@ -3,6 +3,7 @@ package api
import ( import (
"fmt" "fmt"
"github.com/fatih/structs"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
) )
@ -71,13 +72,18 @@ func (c *Sys) ListAudit() (map[string]*Audit, error) {
return mounts, nil return mounts, nil
} }
// DEPRECATED: Use EnableAuditWithOptions instead
func (c *Sys) EnableAudit( func (c *Sys) EnableAudit(
path string, auditType string, desc string, opts map[string]string) error { path string, auditType string, desc string, opts map[string]string) error {
body := map[string]interface{}{ return c.EnableAuditWithOptions(path, &EnableAuditOptions{
"type": auditType, Type: auditType,
"description": desc, Description: desc,
"options": opts, Options: opts,
} })
}
func (c *Sys) EnableAuditWithOptions(path string, options *EnableAuditOptions) error {
body := structs.Map(options)
r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/sys/audit/%s", path)) r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/sys/audit/%s", path))
if err := r.SetJSONBody(body); err != nil { if err := r.SetJSONBody(body); err != nil {
@ -106,9 +112,17 @@ func (c *Sys) DisableAudit(path string) error {
// individually documented because the map almost directly to the raw HTTP API // individually documented because the map almost directly to the raw HTTP API
// documentation. Please refer to that documentation for more details. // documentation. Please refer to that documentation for more details.
type EnableAuditOptions struct {
Type string `json:"type" structs:"type"`
Description string `json:"description" structs:"description"`
Options map[string]string `json:"options" structs:"options"`
Local bool `json:"local" structs:"local"`
}
type Audit struct { type Audit struct {
Path string Path string
Type string Type string
Description string Description string
Options map[string]string Options map[string]string
Local bool
} }

View file

@ -3,6 +3,7 @@ package api
import ( import (
"fmt" "fmt"
"github.com/fatih/structs"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
) )
@ -42,11 +43,16 @@ func (c *Sys) ListAuth() (map[string]*AuthMount, error) {
return mounts, nil return mounts, nil
} }
// DEPRECATED: Use EnableAuthWithOptions instead
func (c *Sys) EnableAuth(path, authType, desc string) error { func (c *Sys) EnableAuth(path, authType, desc string) error {
body := map[string]string{ return c.EnableAuthWithOptions(path, &EnableAuthOptions{
"type": authType, Type: authType,
"description": desc, Description: desc,
} })
}
func (c *Sys) EnableAuthWithOptions(path string, options *EnableAuthOptions) error {
body := structs.Map(options)
r := c.c.NewRequest("POST", fmt.Sprintf("/v1/sys/auth/%s", path)) r := c.c.NewRequest("POST", fmt.Sprintf("/v1/sys/auth/%s", path))
if err := r.SetJSONBody(body); err != nil { if err := r.SetJSONBody(body); err != nil {
@ -75,10 +81,17 @@ func (c *Sys) DisableAuth(path string) error {
// individually documentd because the map almost directly to the raw HTTP API // individually documentd because the map almost directly to the raw HTTP API
// documentation. Please refer to that documentation for more details. // documentation. Please refer to that documentation for more details.
type EnableAuthOptions struct {
Type string `json:"type" structs:"type"`
Description string `json:"description" structs:"description"`
Local bool `json:"local" structs:"local"`
}
type AuthMount struct { type AuthMount struct {
Type string `json:"type" structs:"type" mapstructure:"type"` Type string `json:"type" structs:"type" mapstructure:"type"`
Description string `json:"description" structs:"description" mapstructure:"description"` Description string `json:"description" structs:"description" mapstructure:"description"`
Config AuthConfigOutput `json:"config" structs:"config" mapstructure:"config"` Config AuthConfigOutput `json:"config" structs:"config" mapstructure:"config"`
Local bool `json:"local" structs:"local" mapstructure:"local"`
} }
type AuthConfigOutput struct { type AuthConfigOutput struct {

View file

@ -123,6 +123,7 @@ type MountInput struct {
Type string `json:"type" structs:"type"` Type string `json:"type" structs:"type"`
Description string `json:"description" structs:"description"` Description string `json:"description" structs:"description"`
Config MountConfigInput `json:"config" structs:"config"` Config MountConfigInput `json:"config" structs:"config"`
Local bool `json:"local" structs:"local"`
} }
type MountConfigInput struct { type MountConfigInput struct {
@ -134,6 +135,7 @@ type MountOutput struct {
Type string `json:"type" structs:"type"` Type string `json:"type" structs:"type"`
Description string `json:"description" structs:"description"` Description string `json:"description" structs:"description"`
Config MountConfigOutput `json:"config" structs:"config"` Config MountConfigOutput `json:"config" structs:"config"`
Local bool `json:"local" structs:"local"`
} }
type MountConfigOutput struct { type MountConfigOutput struct {

View file

@ -3,6 +3,7 @@ package command
import ( import (
"testing" "testing"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/http" "github.com/hashicorp/vault/http"
"github.com/hashicorp/vault/meta" "github.com/hashicorp/vault/meta"
"github.com/hashicorp/vault/vault" "github.com/hashicorp/vault/vault"
@ -44,3 +45,42 @@ func TestAuditDisable(t *testing.T) {
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
} }
} }
func TestAuditDisableWithOptions(t *testing.T) {
core, _, token := vault.TestCoreUnsealed(t)
ln, addr := http.TestServer(t, core)
defer ln.Close()
ui := new(cli.MockUi)
c := &AuditDisableCommand{
Meta: meta.Meta{
ClientToken: token,
Ui: ui,
},
}
args := []string{
"-address", addr,
"noop",
}
// Run once to get the client
c.Run(args)
// Get the client
client, err := c.Client()
if err != nil {
t.Fatalf("err: %#v", err)
}
if err := client.Sys().EnableAuditWithOptions("noop", &api.EnableAuditOptions{
Type: "noop",
Description: "noop",
}); err != nil {
t.Fatalf("err: %#v", err)
}
// Run again
if code := c.Run(args); code != 0 {
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
}
}

View file

@ -6,6 +6,7 @@ import (
"os" "os"
"strings" "strings"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/helper/kv-builder" "github.com/hashicorp/vault/helper/kv-builder"
"github.com/hashicorp/vault/meta" "github.com/hashicorp/vault/meta"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
@ -21,9 +22,11 @@ type AuditEnableCommand struct {
func (c *AuditEnableCommand) Run(args []string) int { func (c *AuditEnableCommand) Run(args []string) int {
var desc, path string var desc, path string
var local bool
flags := c.Meta.FlagSet("audit-enable", meta.FlagSetDefault) flags := c.Meta.FlagSet("audit-enable", meta.FlagSetDefault)
flags.StringVar(&desc, "description", "", "") flags.StringVar(&desc, "description", "", "")
flags.StringVar(&path, "path", "", "") flags.StringVar(&path, "path", "", "")
flags.BoolVar(&local, "local", false, "")
flags.Usage = func() { c.Ui.Error(c.Help()) } flags.Usage = func() { c.Ui.Error(c.Help()) }
if err := flags.Parse(args); err != nil { if err := flags.Parse(args); err != nil {
return 1 return 1
@ -68,7 +71,12 @@ func (c *AuditEnableCommand) Run(args []string) int {
return 1 return 1
} }
err = client.Sys().EnableAudit(path, auditType, desc, opts) err = client.Sys().EnableAuditWithOptions(path, &api.EnableAuditOptions{
Type: auditType,
Description: desc,
Options: opts,
Local: local,
})
if err != nil { if err != nil {
c.Ui.Error(fmt.Sprintf( c.Ui.Error(fmt.Sprintf(
"Error enabling audit backend: %s", err)) "Error enabling audit backend: %s", err))
@ -113,6 +121,9 @@ Audit Enable Options:
is purely for referencing this audit backend. By is purely for referencing this audit backend. By
default this will be the backend type. default this will be the backend type.
-local Mark the mount as a local mount. Local mounts
are not replicated nor (if a secondary)
removed by replication.
` `
return strings.TrimSpace(helpText) return strings.TrimSpace(helpText)
} }

View file

@ -48,16 +48,19 @@ func (c *AuditListCommand) Run(args []string) int {
} }
sort.Strings(paths) sort.Strings(paths)
columns := []string{"Path | Type | Description | Options"} columns := []string{"Path | Type | Description | Replication Behavior | Options"}
for _, path := range paths { for _, path := range paths {
audit := audits[path] audit := audits[path]
opts := make([]string, 0, len(audit.Options)) opts := make([]string, 0, len(audit.Options))
for k, v := range audit.Options { for k, v := range audit.Options {
opts = append(opts, k+"="+v) opts = append(opts, k+"="+v)
} }
replicatedBehavior := "replicated"
if audit.Local {
replicatedBehavior = "local"
}
columns = append(columns, fmt.Sprintf( columns = append(columns, fmt.Sprintf(
"%s | %s | %s | %s", audit.Path, audit.Type, audit.Description, strings.Join(opts, " "))) "%s | %s | %s | %s | %s", audit.Path, audit.Type, audit.Description, replicatedBehavior, strings.Join(opts, " ")))
} }
c.Ui.Output(columnize.SimpleFormat(columns)) c.Ui.Output(columnize.SimpleFormat(columns))

View file

@ -3,6 +3,7 @@ package command
import ( import (
"testing" "testing"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/http" "github.com/hashicorp/vault/http"
"github.com/hashicorp/vault/meta" "github.com/hashicorp/vault/meta"
"github.com/hashicorp/vault/vault" "github.com/hashicorp/vault/vault"
@ -34,7 +35,11 @@ func TestAuditList(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("err: %#v", err) t.Fatalf("err: %#v", err)
} }
if err := client.Sys().EnableAudit("foo", "noop", "", nil); err != nil { if err := client.Sys().EnableAuditWithOptions("foo", &api.EnableAuditOptions{
Type: "noop",
Description: "noop",
Options: nil,
}); err != nil {
t.Fatalf("err: %#v", err) t.Fatalf("err: %#v", err)
} }

View file

@ -281,7 +281,7 @@ func (c *AuthCommand) listMethods() int {
} }
sort.Strings(paths) sort.Strings(paths)
columns := []string{"Path | Type | Default TTL | Max TTL | Description"} columns := []string{"Path | Type | Default TTL | Max TTL | Replication Behavior | Description"}
for _, path := range paths { for _, path := range paths {
auth := auth[path] auth := auth[path]
defTTL := "system" defTTL := "system"
@ -292,8 +292,12 @@ func (c *AuthCommand) listMethods() int {
if auth.Config.MaxLeaseTTL != 0 { if auth.Config.MaxLeaseTTL != 0 {
maxTTL = strconv.Itoa(auth.Config.MaxLeaseTTL) maxTTL = strconv.Itoa(auth.Config.MaxLeaseTTL)
} }
replicatedBehavior := "replicated"
if auth.Local {
replicatedBehavior = "local"
}
columns = append(columns, fmt.Sprintf( columns = append(columns, fmt.Sprintf(
"%s | %s | %s | %s | %s", path, auth.Type, defTTL, maxTTL, auth.Description)) "%s | %s | %s | %s | %s | %s", path, auth.Type, defTTL, maxTTL, replicatedBehavior, auth.Description))
} }
c.Ui.Output(columnize.SimpleFormat(columns)) c.Ui.Output(columnize.SimpleFormat(columns))

View file

@ -3,6 +3,7 @@ package command
import ( import (
"testing" "testing"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/http" "github.com/hashicorp/vault/http"
"github.com/hashicorp/vault/meta" "github.com/hashicorp/vault/meta"
"github.com/hashicorp/vault/vault" "github.com/hashicorp/vault/vault"
@ -52,3 +53,50 @@ func TestAuthDisable(t *testing.T) {
t.Fatal("should not have noop mount") t.Fatal("should not have noop mount")
} }
} }
func TestAuthDisableWithOptions(t *testing.T) {
core, _, token := vault.TestCoreUnsealed(t)
ln, addr := http.TestServer(t, core)
defer ln.Close()
ui := new(cli.MockUi)
c := &AuthDisableCommand{
Meta: meta.Meta{
ClientToken: token,
Ui: ui,
},
}
args := []string{
"-address", addr,
"noop",
}
// Run the command once to setup the client, it will fail
c.Run(args)
client, err := c.Client()
if err != nil {
t.Fatalf("err: %s", err)
}
if err := client.Sys().EnableAuthWithOptions("noop", &api.EnableAuthOptions{
Type: "noop",
Description: "",
}); err != nil {
t.Fatalf("err: %#v", err)
}
if code := c.Run(args); code != 0 {
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
}
mounts, err := client.Sys().ListAuth()
if err != nil {
t.Fatalf("err: %s", err)
}
if _, ok := mounts["noop"]; ok {
t.Fatal("should not have noop mount")
}
}

View file

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/meta" "github.com/hashicorp/vault/meta"
) )
@ -14,9 +15,11 @@ type AuthEnableCommand struct {
func (c *AuthEnableCommand) Run(args []string) int { func (c *AuthEnableCommand) Run(args []string) int {
var description, path string var description, path string
var local bool
flags := c.Meta.FlagSet("auth-enable", meta.FlagSetDefault) flags := c.Meta.FlagSet("auth-enable", meta.FlagSetDefault)
flags.StringVar(&description, "description", "", "") flags.StringVar(&description, "description", "", "")
flags.StringVar(&path, "path", "", "") flags.StringVar(&path, "path", "", "")
flags.BoolVar(&local, "local", false, "")
flags.Usage = func() { c.Ui.Error(c.Help()) } flags.Usage = func() { c.Ui.Error(c.Help()) }
if err := flags.Parse(args); err != nil { if err := flags.Parse(args); err != nil {
return 1 return 1
@ -44,7 +47,11 @@ func (c *AuthEnableCommand) Run(args []string) int {
return 2 return 2
} }
if err := client.Sys().EnableAuth(path, authType, description); err != nil { if err := client.Sys().EnableAuthWithOptions(path, &api.EnableAuthOptions{
Type: authType,
Description: description,
Local: local,
}); err != nil {
c.Ui.Error(fmt.Sprintf( c.Ui.Error(fmt.Sprintf(
"Error: %s", err)) "Error: %s", err))
return 2 return 2
@ -82,6 +89,9 @@ Auth Enable Options:
to the type of the mount. This will make the auth to the type of the mount. This will make the auth
provider available at "/auth/<path>" provider available at "/auth/<path>"
-local Mark the mount as a local mount. Local mounts
are not replicated nor (if a secondary)
removed by replication.
` `
return strings.TrimSpace(helpText) return strings.TrimSpace(helpText)
} }