Merge pull request #6509 from Roasbeef/macaroons-rks
macaroons: futher abstract NewService from root key store impl
This commit is contained in:
5 files changed
+91
-24
No files matched your search
+5
-1
@@ -394,8 +394,12 @@ func (d *DefaultWalletImpl) BuildWalletConfig(ctx context.Context,
|
|||||||
var macaroonService *macaroons.Service
|
var macaroonService *macaroons.Service
|
||||||
if !d.cfg.NoMacaroons {
|
if !d.cfg.NoMacaroons {
|
||||||
// Create the macaroon authentication/authorization service.
|
// Create the macaroon authentication/authorization service.
|
||||||
|
rootKeyStore, err := macaroons.NewRootKeyStorage(dbs.MacaroonDB)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
|
}
|
||||||
macaroonService, err = macaroons.NewService(
|
macaroonService, err = macaroons.NewService(
|
||||||
dbs.MacaroonDB, "lnd", walletInitParams.StatelessInit,
|
rootKeyStore, "lnd", walletInitParams.StatelessInit,
|
||||||
macaroons.IPLockChecker,
|
macaroons.IPLockChecker,
|
||||||
macaroons.CustomChecker(interceptorChain),
|
macaroons.CustomChecker(interceptorChain),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,7 +5,9 @@
|
|||||||
|
|
||||||
* [Fixed error typo](https://github.com/lightningnetwork/lnd/pull/6659).
|
* [Fixed error typo](https://github.com/lightningnetwork/lnd/pull/6659).
|
||||||
|
|
||||||
|
* [The macaroon key store implementation was refactored to be more generally useable](https://github.com/lightningnetwork/lnd/pull/6509).
|
||||||
|
|
||||||
# Contributors (Alphabetical Order)
|
# Contributors (Alphabetical Order)
|
||||||
* Carla Kirk-Cohen
|
* Carla Kirk-Cohen
|
||||||
* ErikEk
|
* ErikEk
|
||||||
|
* Olaoluwa Osuntokun
|
||||||
+65
-17
@@ -5,7 +5,6 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/lightningnetwork/lnd/kvdb"
|
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
"gopkg.in/macaroon-bakery.v2/bakery"
|
"gopkg.in/macaroon-bakery.v2/bakery"
|
||||||
"gopkg.in/macaroon-bakery.v2/bakery/checkers"
|
"gopkg.in/macaroon-bakery.v2/bakery/checkers"
|
||||||
@@ -41,13 +40,43 @@ type MacaroonValidator interface {
|
|||||||
requiredPermissions []bakery.Op, fullMethod string) error
|
requiredPermissions []bakery.Op, fullMethod string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExtendedRootKeyStore is an interface augments the existing
|
||||||
|
// macaroons.RootKeyStorage interface by adding a number of additional utility
|
||||||
|
// methods such as encrypting and decrypting the root key given a password.
|
||||||
|
type ExtendedRootKeyStore interface {
|
||||||
|
bakery.RootKeyStore
|
||||||
|
|
||||||
|
// Close closes the RKS and zeros out any in-memory encryption keys.
|
||||||
|
Close() error
|
||||||
|
|
||||||
|
// CreateUnlock calls the underlying root key store's CreateUnlock and
|
||||||
|
// returns the result.
|
||||||
|
CreateUnlock(password *[]byte) error
|
||||||
|
|
||||||
|
// ListMacaroonIDs returns all the root key ID values except the value
|
||||||
|
// of encryptedKeyID.
|
||||||
|
ListMacaroonIDs(ctxt context.Context) ([][]byte, error)
|
||||||
|
|
||||||
|
// DeleteMacaroonID removes one specific root key ID. If the root key
|
||||||
|
// ID is found and deleted, it will be returned.
|
||||||
|
DeleteMacaroonID(ctxt context.Context, rootKeyID []byte) ([]byte, error)
|
||||||
|
|
||||||
|
// ChangePassword calls the underlying root key store's ChangePassword
|
||||||
|
// and returns the result.
|
||||||
|
ChangePassword(oldPw, newPw []byte) error
|
||||||
|
|
||||||
|
// GenerateNewRootKey calls the underlying root key store's
|
||||||
|
// GenerateNewRootKey and returns the result.
|
||||||
|
GenerateNewRootKey() error
|
||||||
|
}
|
||||||
|
|
||||||
// Service encapsulates bakery.Bakery and adds a Close() method that zeroes the
|
// Service encapsulates bakery.Bakery and adds a Close() method that zeroes the
|
||||||
// root key service encryption keys, as well as utility methods to validate a
|
// root key service encryption keys, as well as utility methods to validate a
|
||||||
// macaroon against the bakery and gRPC middleware for macaroon-based auth.
|
// macaroon against the bakery and gRPC middleware for macaroon-based auth.
|
||||||
type Service struct {
|
type Service struct {
|
||||||
bakery.Bakery
|
bakery.Bakery
|
||||||
|
|
||||||
rks *RootKeyStorage
|
rks bakery.RootKeyStore
|
||||||
|
|
||||||
// ExternalValidators is a map between an absolute gRPC URIs and the
|
// ExternalValidators is a map between an absolute gRPC URIs and the
|
||||||
// corresponding external macaroon validator to be used for that URI.
|
// corresponding external macaroon validator to be used for that URI.
|
||||||
@@ -67,17 +96,12 @@ type Service struct {
|
|||||||
// not harmful. Default checkers, such as those for `allow`, `time-before`,
|
// not harmful. Default checkers, such as those for `allow`, `time-before`,
|
||||||
// `declared`, and `error` caveats are registered automatically and don't need
|
// `declared`, and `error` caveats are registered automatically and don't need
|
||||||
// to be added.
|
// to be added.
|
||||||
func NewService(db kvdb.Backend, location string, statelessInit bool,
|
func NewService(keyStore bakery.RootKeyStore, location string,
|
||||||
checks ...Checker) (*Service, error) {
|
statelessInit bool, checks ...Checker) (*Service, error) {
|
||||||
|
|
||||||
rootKeyStore, err := NewRootKeyStorage(db)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
macaroonParams := bakery.BakeryParams{
|
macaroonParams := bakery.BakeryParams{
|
||||||
Location: location,
|
Location: location,
|
||||||
RootKeyStore: rootKeyStore,
|
RootKeyStore: keyStore,
|
||||||
// No third-party caveat support for now.
|
// No third-party caveat support for now.
|
||||||
// TODO(aakselrod): Add third-party caveat support.
|
// TODO(aakselrod): Add third-party caveat support.
|
||||||
Locator: nil,
|
Locator: nil,
|
||||||
@@ -98,7 +122,7 @@ func NewService(db kvdb.Backend, location string, statelessInit bool,
|
|||||||
|
|
||||||
return &Service{
|
return &Service{
|
||||||
Bakery: *svc,
|
Bakery: *svc,
|
||||||
rks: rootKeyStore,
|
rks: keyStore,
|
||||||
ExternalValidators: make(map[string]MacaroonValidator),
|
ExternalValidators: make(map[string]MacaroonValidator),
|
||||||
StatelessInit: statelessInit,
|
StatelessInit: statelessInit,
|
||||||
}, nil
|
}, nil
|
||||||
@@ -204,13 +228,21 @@ func (svc *Service) CheckMacAuth(ctx context.Context, macBytes []byte,
|
|||||||
// Close closes the database that underlies the RootKeyStore and zeroes the
|
// Close closes the database that underlies the RootKeyStore and zeroes the
|
||||||
// encryption keys.
|
// encryption keys.
|
||||||
func (svc *Service) Close() error {
|
func (svc *Service) Close() error {
|
||||||
return svc.rks.Close()
|
if boltRKS, ok := svc.rks.(ExtendedRootKeyStore); ok {
|
||||||
|
return boltRKS.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateUnlock calls the underlying root key store's CreateUnlock and returns
|
// CreateUnlock calls the underlying root key store's CreateUnlock and returns
|
||||||
// the result.
|
// the result.
|
||||||
func (svc *Service) CreateUnlock(password *[]byte) error {
|
func (svc *Service) CreateUnlock(password *[]byte) error {
|
||||||
return svc.rks.CreateUnlock(password)
|
if boltRKS, ok := svc.rks.(ExtendedRootKeyStore); ok {
|
||||||
|
return boltRKS.CreateUnlock(password)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMacaroon wraps around the function Oven.NewMacaroon with the defaults,
|
// NewMacaroon wraps around the function Oven.NewMacaroon with the defaults,
|
||||||
@@ -239,7 +271,11 @@ func (svc *Service) NewMacaroon(
|
|||||||
// ListMacaroonIDs returns all the root key ID values except the value of
|
// ListMacaroonIDs returns all the root key ID values except the value of
|
||||||
// encryptedKeyID.
|
// encryptedKeyID.
|
||||||
func (svc *Service) ListMacaroonIDs(ctxt context.Context) ([][]byte, error) {
|
func (svc *Service) ListMacaroonIDs(ctxt context.Context) ([][]byte, error) {
|
||||||
return svc.rks.ListMacaroonIDs(ctxt)
|
if boltRKS, ok := svc.rks.(ExtendedRootKeyStore); ok {
|
||||||
|
return boltRKS.ListMacaroonIDs(ctxt)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteMacaroonID removes one specific root key ID. If the root key ID is
|
// DeleteMacaroonID removes one specific root key ID. If the root key ID is
|
||||||
@@ -247,19 +283,31 @@ func (svc *Service) ListMacaroonIDs(ctxt context.Context) ([][]byte, error) {
|
|||||||
func (svc *Service) DeleteMacaroonID(ctxt context.Context,
|
func (svc *Service) DeleteMacaroonID(ctxt context.Context,
|
||||||
rootKeyID []byte) ([]byte, error) {
|
rootKeyID []byte) ([]byte, error) {
|
||||||
|
|
||||||
return svc.rks.DeleteMacaroonID(ctxt, rootKeyID)
|
if boltRKS, ok := svc.rks.(ExtendedRootKeyStore); ok {
|
||||||
|
return boltRKS.DeleteMacaroonID(ctxt, rootKeyID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateNewRootKey calls the underlying root key store's GenerateNewRootKey
|
// GenerateNewRootKey calls the underlying root key store's GenerateNewRootKey
|
||||||
// and returns the result.
|
// and returns the result.
|
||||||
func (svc *Service) GenerateNewRootKey() error {
|
func (svc *Service) GenerateNewRootKey() error {
|
||||||
return svc.rks.GenerateNewRootKey()
|
if boltRKS, ok := svc.rks.(ExtendedRootKeyStore); ok {
|
||||||
|
return boltRKS.GenerateNewRootKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChangePassword calls the underlying root key store's ChangePassword and
|
// ChangePassword calls the underlying root key store's ChangePassword and
|
||||||
// returns the result.
|
// returns the result.
|
||||||
func (svc *Service) ChangePassword(oldPw, newPw []byte) error {
|
func (svc *Service) ChangePassword(oldPw, newPw []byte) error {
|
||||||
return svc.rks.ChangePassword(oldPw, newPw)
|
if boltRKS, ok := svc.rks.(ExtendedRootKeyStore); ok {
|
||||||
|
return boltRKS.ChangePassword(oldPw, newPw)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RawMacaroonFromContext is a helper function that extracts a raw macaroon
|
// RawMacaroonFromContext is a helper function that extracts a raw macaroon
|
||||||
|
|||||||
@@ -59,10 +59,13 @@ func TestNewService(t *testing.T) {
|
|||||||
tempDir, db := setupTestRootKeyStorage(t)
|
tempDir, db := setupTestRootKeyStorage(t)
|
||||||
defer os.RemoveAll(tempDir)
|
defer os.RemoveAll(tempDir)
|
||||||
|
|
||||||
|
rootKeyStore, err := macaroons.NewRootKeyStorage(db)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Second, create the new service instance, unlock it and pass in a
|
// Second, create the new service instance, unlock it and pass in a
|
||||||
// checker that we expect it to add to the bakery.
|
// checker that we expect it to add to the bakery.
|
||||||
service, err := macaroons.NewService(
|
service, err := macaroons.NewService(
|
||||||
db, "lnd", false, macaroons.IPLockChecker,
|
rootKeyStore, "lnd", false, macaroons.IPLockChecker,
|
||||||
)
|
)
|
||||||
require.NoError(t, err, "Error creating new service")
|
require.NoError(t, err, "Error creating new service")
|
||||||
defer service.Close()
|
defer service.Close()
|
||||||
@@ -106,8 +109,10 @@ func TestValidateMacaroon(t *testing.T) {
|
|||||||
// First, initialize the service and unlock it.
|
// First, initialize the service and unlock it.
|
||||||
tempDir, db := setupTestRootKeyStorage(t)
|
tempDir, db := setupTestRootKeyStorage(t)
|
||||||
defer os.RemoveAll(tempDir)
|
defer os.RemoveAll(tempDir)
|
||||||
|
rootKeyStore, err := macaroons.NewRootKeyStorage(db)
|
||||||
|
require.NoError(t, err)
|
||||||
service, err := macaroons.NewService(
|
service, err := macaroons.NewService(
|
||||||
db, "lnd", false, macaroons.IPLockChecker,
|
rootKeyStore, "lnd", false, macaroons.IPLockChecker,
|
||||||
)
|
)
|
||||||
require.NoError(t, err, "Error creating new service")
|
require.NoError(t, err, "Error creating new service")
|
||||||
defer service.Close()
|
defer service.Close()
|
||||||
@@ -154,8 +159,10 @@ func TestListMacaroonIDs(t *testing.T) {
|
|||||||
|
|
||||||
// Second, create the new service instance, unlock it and pass in a
|
// Second, create the new service instance, unlock it and pass in a
|
||||||
// checker that we expect it to add to the bakery.
|
// checker that we expect it to add to the bakery.
|
||||||
|
rootKeyStore, err := macaroons.NewRootKeyStorage(db)
|
||||||
|
require.NoError(t, err)
|
||||||
service, err := macaroons.NewService(
|
service, err := macaroons.NewService(
|
||||||
db, "lnd", false, macaroons.IPLockChecker,
|
rootKeyStore, "lnd", false, macaroons.IPLockChecker,
|
||||||
)
|
)
|
||||||
require.NoError(t, err, "Error creating new service")
|
require.NoError(t, err, "Error creating new service")
|
||||||
defer service.Close()
|
defer service.Close()
|
||||||
@@ -186,8 +193,10 @@ func TestDeleteMacaroonID(t *testing.T) {
|
|||||||
|
|
||||||
// Second, create the new service instance, unlock it and pass in a
|
// Second, create the new service instance, unlock it and pass in a
|
||||||
// checker that we expect it to add to the bakery.
|
// checker that we expect it to add to the bakery.
|
||||||
|
rootKeyStore, err := macaroons.NewRootKeyStorage(db)
|
||||||
|
require.NoError(t, err)
|
||||||
service, err := macaroons.NewService(
|
service, err := macaroons.NewService(
|
||||||
db, "lnd", false, macaroons.IPLockChecker,
|
rootKeyStore, "lnd", false, macaroons.IPLockChecker,
|
||||||
)
|
)
|
||||||
require.NoError(t, err, "Error creating new service")
|
require.NoError(t, err, "Error creating new service")
|
||||||
defer service.Close()
|
defer service.Close()
|
||||||
|
|||||||
@@ -807,8 +807,12 @@ func (u *UnlockerService) ChangePassword(ctx context.Context,
|
|||||||
// then close it again.
|
// then close it again.
|
||||||
// Attempt to open the macaroon DB, unlock it and then change
|
// Attempt to open the macaroon DB, unlock it and then change
|
||||||
// the passphrase.
|
// the passphrase.
|
||||||
|
rootKeyStore, err := macaroons.NewRootKeyStorage(u.macaroonDB)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
macaroonService, err := macaroons.NewService(
|
macaroonService, err := macaroons.NewService(
|
||||||
u.macaroonDB, "lnd", in.StatelessInit,
|
rootKeyStore, "lnd", in.StatelessInit,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
Reference in new issue
Block a user