vault: Adding PolicyStore

This commit is contained in:
Armon Dadgar 2015-03-18 12:17:03 -07:00
parent 061b6b24f1
commit 51ce336753
3 changed files with 210 additions and 0 deletions

View File

@ -83,7 +83,10 @@ func TestACL_Layered(t *testing.T) {
if err != nil {
t.Fatalf("err: %v", err)
}
testLayeredACL(t, acl)
}
func testLayeredACL(t *testing.T, acl *ACL) {
if acl.RootPrivilege("sys/mount/foo") {
t.Fatalf("unexpected root")
}

105
vault/policy_store.go Normal file
View File

@ -0,0 +1,105 @@
package vault
import (
"fmt"
"log"
"os"
"github.com/hashicorp/vault/logical"
)
// PolicyStore is used to provide durable storage of policy, and to
// manage ACLs associated with them.
type PolicyStore struct {
view *BarrierView
logger *log.Logger
}
// NewPolicyStore creates a new PolicyStore that is backed
// using a given view. It used used to durable store and manage named policy.
func NewPolicyStore(view *BarrierView, logger *log.Logger) *PolicyStore {
if logger == nil {
logger = log.New(os.Stderr, "", log.LstdFlags)
}
p := &PolicyStore{
view: view,
logger: logger,
}
return p
}
// SetPolicy is used to create or update the given policy
func (ps *PolicyStore) SetPolicy(p *Policy) error {
if p.Name == "root" {
return fmt.Errorf("cannot update root policy")
}
if p.Name == "" {
return fmt.Errorf("policy name missing")
}
entry := &logical.StorageEntry{
Key: p.Name,
Value: []byte(p.Raw),
}
if err := ps.view.Put(entry); err != nil {
return fmt.Errorf("failed to persist policy: %v", err)
}
return nil
}
// GetPolicy is used to fetch the named policy
func (ps *PolicyStore) GetPolicy(name string) (*Policy, error) {
// TODO: Cache policy
// Load the policy in
out, err := ps.view.Get(name)
if err != nil {
return nil, fmt.Errorf("failed to read policy: %v", err)
}
if out == nil {
return nil, nil
}
// Parse into a policy object
p, err := Parse(string(out.Value))
if err != nil {
return nil, fmt.Errorf("failed to parse policy: %v", err)
}
return p, nil
}
// ListPolicies is used to list the available policies
func (ps *PolicyStore) ListPolicies() ([]string, error) {
// Scan the view, since the policy names are the same as the
// key names.
return CollectKeys(ps.view)
}
// DeletePolicy is used to delete the named policy
func (ps *PolicyStore) DeletePolicy(name string) error {
if err := ps.view.Delete(name); err != nil {
return fmt.Errorf("failed to delete policy: %v", err)
}
return nil
}
// ACL is used to return an ACL which is built using the
// named policies.
func (ps *PolicyStore) ACL(names ...string) (*ACL, error) {
// TODO: Cache ACLs
// Fetch the policies
var policy []*Policy
for _, name := range names {
p, err := ps.GetPolicy(name)
if err != nil {
return nil, fmt.Errorf("failed to get policy '%s': %v", name, err)
}
policy = append(policy, p)
}
// Construct the ACL
acl, err := NewACL(policy)
if err != nil {
return nil, fmt.Errorf("failed to construct ACL: %v", err)
}
return acl, nil
}

102
vault/policy_store_test.go Normal file
View File

@ -0,0 +1,102 @@
package vault
import (
"reflect"
"testing"
)
func mockPolicyStore(t *testing.T) *PolicyStore {
_, barrier, _ := mockBarrier(t)
view := NewBarrierView(barrier, "foo/")
p := NewPolicyStore(view, nil)
return p
}
func TestPolicyStore_CRUD(t *testing.T) {
ps := mockPolicyStore(t)
// Get should return nothing
p, err := ps.GetPolicy("dev")
if err != nil {
t.Fatalf("err: %v", err)
}
if p != nil {
t.Fatalf("bad: %v", p)
}
// Delete should be no-op
err = ps.DeletePolicy("dev")
if err != nil {
t.Fatalf("err: %v", err)
}
// List should be blank
out, err := ps.ListPolicies()
if err != nil {
t.Fatalf("err: %v", err)
}
if len(out) != 0 {
t.Fatalf("bad: %v", out)
}
// Set should work
policy, _ := Parse(aclPolicy)
err = ps.SetPolicy(policy)
if err != nil {
t.Fatalf("err: %v", err)
}
// Get should work
p, err = ps.GetPolicy("dev")
if err != nil {
t.Fatalf("err: %v", err)
}
if !reflect.DeepEqual(p, policy) {
t.Fatalf("bad: %v", p)
}
// List should be one element
out, err = ps.ListPolicies()
if err != nil {
t.Fatalf("err: %v", err)
}
if len(out) != 1 || out[0] != "dev" {
t.Fatalf("bad: %v", out)
}
// Delete should be clear the entry
err = ps.DeletePolicy("dev")
if err != nil {
t.Fatalf("err: %v", err)
}
// Get should fail
p, err = ps.GetPolicy("dev")
if err != nil {
t.Fatalf("err: %v", err)
}
if p != nil {
t.Fatalf("bad: %v", p)
}
}
func TestPolicyStore_ACL(t *testing.T) {
ps := mockPolicyStore(t)
policy, _ := Parse(aclPolicy)
err := ps.SetPolicy(policy)
if err != nil {
t.Fatalf("err: %v", err)
}
policy, _ = Parse(aclPolicy2)
err = ps.SetPolicy(policy)
if err != nil {
t.Fatalf("err: %v", err)
}
acl, err := ps.ACL("dev", "ops")
if err != nil {
t.Fatalf("err: %v", err)
}
testLayeredACL(t, acl)
}