diff --git a/api/sys_policy.go b/api/sys_policy.go index 635bc7c28a..ea57a69ad8 100644 --- a/api/sys_policy.go +++ b/api/sys_policy.go @@ -20,6 +20,9 @@ func (c *Sys) ListPolicies() ([]string, error) { func (c *Sys) GetPolicy(name string) (string, error) { r := c.c.NewRequest("GET", fmt.Sprintf("/v1/sys/policy/%s", name)) resp, err := c.c.RawRequest(r) + if resp.StatusCode == 404 { + return "", nil + } if err != nil { return "", err } diff --git a/cli/commands.go b/cli/commands.go index 303a69b5d0..dd2fbebfcb 100644 --- a/cli/commands.go +++ b/cli/commands.go @@ -115,6 +115,12 @@ func Commands(metaPtr *command.Meta) map[string]cli.CommandFactory { }, nil }, + "policy-delete": func() (cli.Command, error) { + return &command.PolicyDeleteCommand{ + Meta: meta, + }, nil + }, + "policy-write": func() (cli.Command, error) { return &command.PolicyWriteCommand{ Meta: meta, diff --git a/command/policy_delete.go b/command/policy_delete.go new file mode 100644 index 0000000000..9a1fb36c2b --- /dev/null +++ b/command/policy_delete.go @@ -0,0 +1,77 @@ +package command + +import ( + "fmt" + "strings" +) + +// PolicyDeleteCommand is a Command that enables a new endpoint. +type PolicyDeleteCommand struct { + Meta +} + +func (c *PolicyDeleteCommand) Run(args []string) int { + flags := c.Meta.FlagSet("policy-delete", FlagSetDefault) + flags.Usage = func() { c.Ui.Error(c.Help()) } + if err := flags.Parse(args); err != nil { + return 1 + } + + args = flags.Args() + if len(args) != 1 { + flags.Usage() + c.Ui.Error(fmt.Sprintf( + "\npolicy-delete expects exactly one argument")) + return 1 + } + + client, err := c.Client() + if err != nil { + c.Ui.Error(fmt.Sprintf( + "Error initializing client: %s", err)) + return 2 + } + + name := args[0] + if err := client.Sys().DeletePolicy(name); err != nil { + c.Ui.Error(fmt.Sprintf( + "Error: %s", err)) + return 1 + } + + c.Ui.Output(fmt.Sprintf("Policy '%s' deleted.", name)) + return 0 +} + +func (c *PolicyDeleteCommand) Synopsis() string { + return "Delete a policy from the server" +} + +func (c *PolicyDeleteCommand) Help() string { + helpText := ` +Usage: vault policy-delete [options] name + + Delete a policy with the given name. + + One the policy is deleted, all users associated with the policy will + be affected immediately. When a user is associated with a policy that + doesn't exist, it is identical to not being associated with that policy. + +General Options: + + -address=TODO The address of the Vault server. + + -ca-cert=path Path to a PEM encoded CA cert file to use to + verify the Vault server SSL certificate. + + -ca-path=path Path to a directory of PEM encoded CA cert files + to verify the Vault server SSL certificate. If both + -ca-cert and -ca-path are specified, -ca-path is used. + + -insecure Do not verify TLS certificate. This is highly + not recommended. This is especially not recommended + for unsealing a vault. + +` + return strings.TrimSpace(helpText) +} diff --git a/command/policy_delete_test.go b/command/policy_delete_test.go new file mode 100644 index 0000000000..15e0e8c8bd --- /dev/null +++ b/command/policy_delete_test.go @@ -0,0 +1,60 @@ +package command + +import ( + "testing" + + "github.com/hashicorp/vault/http" + "github.com/hashicorp/vault/vault" + "github.com/mitchellh/cli" +) + +func TestPolicyDelete(t *testing.T) { + core, _, token := vault.TestCoreUnsealed(t) + ln, addr := http.TestServer(t, core) + defer ln.Close() + + ui := new(cli.MockUi) + c := &PolicyDeleteCommand{ + Meta: Meta{ + ClientToken: token, + Ui: ui, + }, + } + + args := []string{ + "-address", addr, + "foo", + } + + // Run once so the client is setup, ignore errors + c.Run(args) + + // Get the client so we can write data + client, err := c.Client() + if err != nil { + t.Fatalf("err: %s", err) + } + if err := client.Sys().PutPolicy("foo", testPolicyDeleteRules); err != nil { + t.Fatalf("err: %s", err) + } + + // Test that the delete works + if code := c.Run(args); code != 0 { + t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) + } + + // Test the policy is gone + rules, err := client.Sys().GetPolicy("foo") + if err != nil { + t.Fatalf("err: %s", err) + } + if rules != "" { + t.Fatalf("bad: %#v", rules) + } +} + +const testPolicyDeleteRules = ` +path "sys" { + policy = "deny" +} +` diff --git a/http/sys_policy.go b/http/sys_policy.go index db010e0a59..d17d75be56 100644 --- a/http/sys_policy.go +++ b/http/sys_policy.go @@ -95,6 +95,10 @@ func handleSysReadPolicy(core *vault.Core, w http.ResponseWriter, r *http.Reques if !ok { return } + if resp == nil { + respondError(w, http.StatusNotFound, nil) + return + } respondOk(w, resp.Data) }