multi: upgrade macaroons to v2, replace per-method auth with interceptors

This commit reworks the macaroon authentication framework to use the
v2 macaroon format and bakery API. It also replaces the code in each
RPC method which calls the macaroon verifier with interceptors which
call the macaroon verifier instead. In addition, the operation
permissions are reworked to fit the new format of "allow" commands
(specifically, entity/operation permissions instead of method
permissions).
This commit is contained in:
Alex authored and Olaoluwa Osuntokun committed 2018-01-31 17:14:49 -08:00
1 parent 20098e8cb3
commit 21c29c33d7
11 files changed
+427 -514

No files matched your search

+10 -66
View File
@@ -5,6 +5,8 @@ import (
"fmt"
"io"
"golang.org/x/net/context"
"github.com/boltdb/bolt"
)
@@ -21,7 +23,7 @@ var (
// just 0, to emulate the memory storage that comes with bakery.
//
// TODO(aakselrod): Add support for key rotation.
defaultRootKeyID = "0"
defaultRootKeyID = []byte("0")
// macaroonBucketName is the name of the macaroon store bucket.
macaroonBucketName = []byte("macaroons")
@@ -49,13 +51,13 @@ func NewRootKeyStorage(db *bolt.DB) (*RootKeyStorage, error) {
}
// Get implements the Get method for the bakery.RootKeyStorage interface.
func (r *RootKeyStorage) Get(id string) ([]byte, error) {
func (r *RootKeyStorage) Get(_ context.Context, id []byte) ([]byte, error) {
var rootKey []byte
err := r.View(func(tx *bolt.Tx) error {
dbKey := tx.Bucket(rootKeyBucketName).Get([]byte(id))
dbKey := tx.Bucket(rootKeyBucketName).Get(id)
if len(dbKey) == 0 {
return fmt.Errorf("root key with id %s doesn't exist",
id)
string(id))
}
rootKey = make([]byte, len(dbKey))
@@ -72,12 +74,12 @@ func (r *RootKeyStorage) Get(id string) ([]byte, error) {
// RootKey implements the RootKey method for the bakery.RootKeyStorage
// interface.
// TODO(aakselrod): Add support for key rotation.
func (r *RootKeyStorage) RootKey() ([]byte, string, error) {
func (r *RootKeyStorage) RootKey(_ context.Context) ([]byte, []byte, error) {
var rootKey []byte
id := defaultRootKeyID
err := r.Update(func(tx *bolt.Tx) error {
ns := tx.Bucket(rootKeyBucketName)
rootKey = ns.Get([]byte(id))
rootKey = ns.Get(id)
// If there's no root key stored in the bucket yet, create one.
if len(rootKey) != 0 {
@@ -89,69 +91,11 @@ func (r *RootKeyStorage) RootKey() ([]byte, string, error) {
if _, err := io.ReadFull(rand.Reader, rootKey[:]); err != nil {
return err
}
return ns.Put([]byte(id), rootKey)
return ns.Put(id, rootKey)
})
if err != nil {
return nil, "", err
return nil, nil, err
}
return rootKey, id, nil
}
// Storage implements the bakery.Storage interface.
type Storage struct {
*bolt.DB
}
// NewStorage creates a Storage instance.
//
// TODO(aakselrod): Add support for encryption of data with passphrase.
func NewStorage(db *bolt.DB) (*Storage, error) {
// If the store's bucket doesn't exist, create it.
err := db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucketIfNotExists(macaroonBucketName)
return err
})
if err != nil {
return nil, err
}
// Return the DB wrapped in a Storage object.
return &Storage{db}, nil
}
// Put implements the Put method for the bakery.Storage interface.
func (s *Storage) Put(location string, item string) error {
return s.Update(func(tx *bolt.Tx) error {
return tx.Bucket(macaroonBucketName).Put([]byte(location),
[]byte(item))
})
}
// Get implements the Get method for the bakery.Storage interface.
func (s *Storage) Get(location string) (string, error) {
var item []byte
err := s.View(func(tx *bolt.Tx) error {
itemBytes := tx.Bucket(macaroonBucketName).Get([]byte(location))
if len(itemBytes) == 0 {
return fmt.Errorf("couldn't get item for location %s",
location)
}
item = make([]byte, len(itemBytes))
copy(item, itemBytes)
return nil
})
if err != nil {
return "", err
}
return string(item), nil
}
// Del implements the Del method for the bakery.Storage interface.
func (s *Storage) Del(location string) error {
return s.Update(func(tx *bolt.Tx) error {
return tx.Bucket(macaroonBucketName).Delete([]byte(location))
})
}