Merge pull request #6509 from Roasbeef/macaroons-rks

macaroons: futher abstract NewService from root key store impl
This commit is contained in:
Olaoluwa Osuntokun authored and GitHub committed 2022-07-06 19:00:49 -07:00
commit dc35f78ebc
5 files changed
+91 -24

No files matched your search

+5 -1
View File
@@ -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),
) )
+3 -1
View File
@@ -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
View File
@@ -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
+13 -4
View File
@@ -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()
+5 -1
View File
@@ -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