mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-11-10 06:07:16 +01:00
rpcperms: add RPC interceptor chain
This adds a new package rpcperms which houses the InterceptorChain struct. This is a central place where we'll craft interceptors to use for the GRPC server, which includes macaroon enforcement. This let us add the interceptor chain to the GRPC server before the macaroon service is ready, allowing us to avoid tearing down the GRPC server after the wallet has been unlocked.
This commit is contained in:
@@ -9,7 +9,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/lightningnetwork/lnd/channeldb/kvdb"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/metadata"
|
||||
|
||||
"gopkg.in/macaroon-bakery.v2/bakery"
|
||||
@@ -58,11 +57,11 @@ type Service struct {
|
||||
|
||||
rks *RootKeyStorage
|
||||
|
||||
// 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.
|
||||
// If no external validator for an URI is specified, the service will
|
||||
// use the internal validator.
|
||||
externalValidators map[string]MacaroonValidator
|
||||
ExternalValidators map[string]MacaroonValidator
|
||||
|
||||
// StatelessInit denotes if the service was initialized in the stateless
|
||||
// mode where no macaroon files should be created on disk.
|
||||
@@ -125,7 +124,7 @@ func NewService(dir, location string, statelessInit bool,
|
||||
return &Service{
|
||||
Bakery: *svc,
|
||||
rks: rootKeyStore,
|
||||
externalValidators: make(map[string]MacaroonValidator),
|
||||
ExternalValidators: make(map[string]MacaroonValidator),
|
||||
StatelessInit: statelessInit,
|
||||
}, nil
|
||||
}
|
||||
@@ -159,83 +158,16 @@ func (svc *Service) RegisterExternalValidator(fullMethod string,
|
||||
return fmt.Errorf("validator cannot be nil")
|
||||
}
|
||||
|
||||
_, ok := svc.externalValidators[fullMethod]
|
||||
_, ok := svc.ExternalValidators[fullMethod]
|
||||
if ok {
|
||||
return fmt.Errorf("external validator for method %s already "+
|
||||
"registered", fullMethod)
|
||||
}
|
||||
|
||||
svc.externalValidators[fullMethod] = validator
|
||||
svc.ExternalValidators[fullMethod] = validator
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnaryServerInterceptor is a GRPC interceptor that checks whether the
|
||||
// request is authorized by the included macaroons.
|
||||
func (svc *Service) UnaryServerInterceptor(
|
||||
permissionMap map[string][]bakery.Op) grpc.UnaryServerInterceptor {
|
||||
|
||||
return func(ctx context.Context, req interface{},
|
||||
info *grpc.UnaryServerInfo,
|
||||
handler grpc.UnaryHandler) (interface{}, error) {
|
||||
|
||||
uriPermissions, ok := permissionMap[info.FullMethod]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%s: unknown permissions "+
|
||||
"required for method", info.FullMethod)
|
||||
}
|
||||
|
||||
// Find out if there is an external validator registered for
|
||||
// this method. Fall back to the internal one if there isn't.
|
||||
validator, ok := svc.externalValidators[info.FullMethod]
|
||||
if !ok {
|
||||
validator = svc
|
||||
}
|
||||
|
||||
// Now that we know what validator to use, let it do its work.
|
||||
err := validator.ValidateMacaroon(
|
||||
ctx, uriPermissions, info.FullMethod,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return handler(ctx, req)
|
||||
}
|
||||
}
|
||||
|
||||
// StreamServerInterceptor is a GRPC interceptor that checks whether the
|
||||
// request is authorized by the included macaroons.
|
||||
func (svc *Service) StreamServerInterceptor(
|
||||
permissionMap map[string][]bakery.Op) grpc.StreamServerInterceptor {
|
||||
|
||||
return func(srv interface{}, ss grpc.ServerStream,
|
||||
info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
|
||||
|
||||
uriPermissions, ok := permissionMap[info.FullMethod]
|
||||
if !ok {
|
||||
return fmt.Errorf("%s: unknown permissions required "+
|
||||
"for method", info.FullMethod)
|
||||
}
|
||||
|
||||
// Find out if there is an external validator registered for
|
||||
// this method. Fall back to the internal one if there isn't.
|
||||
validator, ok := svc.externalValidators[info.FullMethod]
|
||||
if !ok {
|
||||
validator = svc
|
||||
}
|
||||
|
||||
// Now that we know what validator to use, let it do its work.
|
||||
err := validator.ValidateMacaroon(
|
||||
ss.Context(), uriPermissions, info.FullMethod,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return handler(srv, ss)
|
||||
}
|
||||
}
|
||||
|
||||
// ValidateMacaroon validates the capabilities of a given request given a
|
||||
// bakery service, context, and uri. Within the passed context.Context, we
|
||||
// expect a macaroon to be encoded as request metadata using the key
|
||||
|
||||
Reference in New Issue
Block a user