Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
250 changes: 170 additions & 80 deletions itest/litd_mode_integrated_test.go

Large diffs are not rendered by default.

22 changes: 10 additions & 12 deletions itest/litd_mode_remote_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ func remoteTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
runGRPCAuthTest(
ttt, cfg.LitAddr(), cfg.LitTLSCertPath,
endpoint.macaroonFn(cfg),
endpoint.noAuth,
endpoint.requestFn,
endpoint.successPattern,
endpointEnabled,
"unknown permissions required for "+
"method",
"unknown request",
)
})
}
Expand All @@ -90,11 +90,11 @@ func remoteTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
runUIPasswordCheck(
ttt, cfg.LitAddr(), cfg.LitTLSCertPath,
cfg.UIPassword, endpoint.requestFn,
endpoint.noAuth,
shouldFailWithoutMacaroon,
endpoint.successPattern,
endpointEnabled,
"unknown permissions required for "+
"method",
"unknown request",
)
})
}
Expand All @@ -117,8 +117,7 @@ func remoteTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
ttt, cfg.LitAddr(), cfg.UIPassword,
endpoint.grpcWebURI, withoutUIPassword,
endpointEnabled,
"unknown permissions required for "+
"method",
"unknown request", endpoint.noAuth,
)
})
}
Expand All @@ -142,12 +141,11 @@ func remoteTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
tt.Run(endpoint.name+" lit port", func(ttt *testing.T) {
runGRPCAuthTest(
ttt, cfg.LitAddr(), cfg.LitTLSCertPath,
superMacFile,
superMacFile, endpoint.noAuth,
endpoint.requestFn,
endpoint.successPattern,
endpointEnabled,
"unknown permissions required for "+
"method",
"unknown request",
)
})
}
Expand All @@ -168,7 +166,7 @@ func remoteTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
endpoint.restWebURI,
endpoint.successPattern,
endpoint.restPOST, withoutUIPassword,
endpointDisabled,
endpointDisabled, endpoint.noAuth,
)
})
}
Expand Down Expand Up @@ -199,7 +197,7 @@ func remoteTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
endpoint.successPattern,
endpoint.allowedThroughLNC,
"unknown service",
endpointDisabled,
endpointDisabled, endpoint.noAuth,
)
})
}
Expand Down Expand Up @@ -244,7 +242,7 @@ func remoteTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
ttt, rawLNCConn, endpoint.requestFn,
endpoint.successPattern,
allowed, "permission denied",
endpointDisabled,
endpointDisabled, endpoint.noAuth,
)
})
}
Expand Down
32 changes: 29 additions & 3 deletions perms/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,13 @@ func NewManager(withAllSubServers bool) (*Manager, error) {
permissions := make(map[string]map[string][]bakery.Op)
permissions[litPerms] = RequiredPermissions
permissions[lndPerms] = lnd.MainRPCServerPermissions()
for k, v := range whiteListedLNDMethods {
permissions[lndPerms][k] = v

for url := range whiteListedLitMethods {
permissions[litPerms][url] = []bakery.Op{}
}

for url := range whiteListedLNDMethods {
permissions[lndPerms][url] = []bakery.Op{}
}

// Collect all LND sub-server permissions along with the name of the
Expand Down Expand Up @@ -96,10 +101,22 @@ func NewManager(withAllSubServers bool) (*Manager, error) {
}, nil
}

// IsWhiteListedURL returns true if the given URL has been whitelisted meaning
// that it does not require a macaroon for validation. A URL is considered
// white-listed if it has no operations associated with a URL.
func (pm *Manager) IsWhiteListedURL(url string) bool {
pm.permsMu.Lock()
defer pm.permsMu.Unlock()

ops, ok := pm.perms[url]

return ok && len(ops) == 0
}

// RegisterSubServer adds the permissions of a given sub-server to the set
// managed by the Manager.
func (pm *Manager) RegisterSubServer(name string,
permissions map[string][]bakery.Op) {
permissions map[string][]bakery.Op, whiteListURLs map[string]struct{}) {

pm.permsMu.Lock()
defer pm.permsMu.Unlock()
Expand All @@ -109,6 +126,15 @@ func (pm *Manager) RegisterSubServer(name string,
for uri, ops := range permissions {
pm.perms[uri] = ops
}

for url := range whiteListURLs {
pm.perms[url] = nil

if pm.fixedPerms[name] == nil {
pm.fixedPerms[name] = make(map[string][]bakery.Op)
}
pm.fixedPerms[name][url] = []bakery.Op{}
}
}

// OnLNDBuildTags should be called once a list of LND build tags has been
Expand Down
6 changes: 5 additions & 1 deletion perms/permissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ var (

// whiteListedLNDMethods is a map of all lnd RPC methods that don't
// require any macaroon authentication.
whiteListedLNDMethods = map[string][]bakery.Op{
whiteListedLNDMethods = map[string]struct{}{
"/lnrpc.WalletUnlocker/GenSeed": {},
"/lnrpc.WalletUnlocker/InitWallet": {},
"/lnrpc.WalletUnlocker/UnlockWallet": {},
Expand All @@ -92,6 +92,10 @@ var (
"/lnrpc.State/GetState": {},
}

// whiteListedLitMethods is a map of all LiT's RPC methods that don't
// require any macaroon authentication.
whiteListedLitMethods = map[string]struct{}{}

// lndSubServerNameToTag is a map from the name of an LND subserver to
// the name of the LND tag that corresponds to the subserver. This map
// only contains the subserver-to-tag pairs for the pairs where the
Expand Down
24 changes: 13 additions & 11 deletions rpc_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,15 @@ const (
HeaderMacaroon = "Macaroon"
)

// ErrWaitingToStart is returned if Lit's rpcProxy is not yet ready to handle
// calls.
var ErrWaitingToStart = fmt.Errorf("waiting for the RPC server to start")
var (
// ErrWaitingToStart is returned if Lit's rpcProxy is not yet ready to
// handle calls.
ErrWaitingToStart = fmt.Errorf("waiting for the RPC server to start")

// ErrUnknownRequest is an error returned when the request URI is
// unknown if the permissions for the request are unknown.
ErrUnknownRequest = fmt.Errorf("unknown request")
)

// proxyErr is an error type that adds more context to an error occurring in the
// proxy.
Expand Down Expand Up @@ -375,8 +381,7 @@ func (p *rpcProxy) UnaryServerInterceptor(ctx context.Context, req interface{},

uriPermissions, ok := p.permsMgr.URIPermissions(info.FullMethod)
if !ok {
return nil, fmt.Errorf("%s: unknown permissions "+
"required for method", info.FullMethod)
return nil, ErrUnknownRequest
}

// For now, basic authentication is just a quick fix until we
Expand Down Expand Up @@ -420,8 +425,7 @@ func (p *rpcProxy) StreamServerInterceptor(srv interface{},

uriPermissions, ok := p.permsMgr.URIPermissions(info.FullMethod)
if !ok {
return fmt.Errorf("%s: unknown permissions required "+
"for method", info.FullMethod)
return ErrUnknownRequest
}

// For now, basic authentication is just a quick fix until we
Expand Down Expand Up @@ -521,8 +525,7 @@ func (p *rpcProxy) basicAuthToMacaroon(basicAuth, requestURI string,
macPath = p.cfg.MacaroonPath

default:
return nil, fmt.Errorf("unknown gRPC web request: %v",
requestURI)
return nil, ErrUnknownRequest
}

switch {
Expand Down Expand Up @@ -572,8 +575,7 @@ func (p *rpcProxy) convertSuperMacaroon(ctx context.Context, macHex string,

requiredPermissions, ok := p.permsMgr.URIPermissions(fullMethod)
if !ok {
return nil, fmt.Errorf("%s: unknown permissions required for "+
"method", fullMethod)
return nil, ErrUnknownRequest
}

// We have a super macaroon, from here on out we'll return errors if
Expand Down
8 changes: 8 additions & 0 deletions subservers/faraday.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,11 @@ func (f *faradaySubServer) MacPath() string {
func (f *faradaySubServer) Permissions() map[string][]bakery.Op {
return perms.RequiredPermissions
}

// WhiteListedURLs returns a map of all the sub-server's URLs that can be
// accessed without a macaroon.
//
// NOTE: this is part of the SubServer interface.
func (f *faradaySubServer) WhiteListedURLs() map[string]struct{} {
return nil
}
4 changes: 4 additions & 0 deletions subservers/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,8 @@ type SubServer interface {
// Permissions returns a map of all RPC methods and their required
// macaroon permissions to access the sub-server.
Permissions() map[string][]bakery.Op

// WhiteListedURLs returns a map of all the sub-server's URLs that can
// be accessed without a macaroon.
WhiteListedURLs() map[string]struct{}
}
8 changes: 8 additions & 0 deletions subservers/loop.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,11 @@ func (l *loopSubServer) MacPath() string {
func (l *loopSubServer) Permissions() map[string][]bakery.Op {
return perms.RequiredPermissions
}

// WhiteListedURLs returns a map of all the sub-server's URLs that can be
// accessed without a macaroon.
//
// NOTE: this is part of the SubServer interface.
func (l *loopSubServer) WhiteListedURLs() map[string]struct{} {
return nil
}
4 changes: 3 additions & 1 deletion subservers/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ func (s *Manager) AddServer(ss SubServer) {
quit: make(chan struct{}),
})

s.permsMgr.RegisterSubServer(ss.Name(), ss.Permissions())
s.permsMgr.RegisterSubServer(
ss.Name(), ss.Permissions(), ss.WhiteListedURLs(),
)
}

// StartIntegratedServers starts all the manager's sub-servers that should be
Expand Down
8 changes: 8 additions & 0 deletions subservers/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,11 @@ func (p *poolSubServer) MacPath() string {
func (p *poolSubServer) Permissions() map[string][]bakery.Op {
return perms.RequiredPermissions
}

// WhiteListedURLs returns a map of all the sub-server's URLs that can be
// accessed without a macaroon.
//
// NOTE: this is part of the SubServer interface.
func (p *poolSubServer) WhiteListedURLs() map[string]struct{} {
return nil
}
16 changes: 16 additions & 0 deletions subservers/taproot-assets.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,19 @@ func (t *taprootAssetsSubServer) MacPath() string {
func (t *taprootAssetsSubServer) Permissions() map[string][]bakery.Op {
return perms.RequiredPermissions
}

// WhiteListedURLs returns a map of all the sub-server's URLs that can be
// accessed without a macaroon.
//
// NOTE: this is part of the SubServer interface.
func (t *taprootAssetsSubServer) WhiteListedURLs() map[string]struct{} {
// If the taproot-asset daemon is running in integrated mode, then we
// use cfg.RpcConf.AllowPublicStats to determine if the public stats
// endpoints should be included in the whitelist. If it is running in
// remote mode, however, then we don't know if the public stats are
// allowed, and so we just allow the request through since the remote
// daemon will handle blocking the call if it is not whitelisted there.
return perms.MacaroonWhitelist(
t.cfg.RpcConf.AllowPublicStats || t.remote,
)
}
7 changes: 7 additions & 0 deletions terminal.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ var (
lndRESTRegistrations = []restRegistration{
lnrpc.RegisterLightningHandlerFromEndpoint,
lnrpc.RegisterWalletUnlockerHandlerFromEndpoint,
lnrpc.RegisterStateHandlerFromEndpoint,
autopilotrpc.RegisterAutopilotHandlerFromEndpoint,
chainrpc.RegisterChainNotifierHandlerFromEndpoint,
invoicesrpc.RegisterInvoicesHandlerFromEndpoint,
Expand Down Expand Up @@ -963,6 +964,12 @@ func (g *LightningTerminal) RegisterRestSubserver(ctx context.Context,
func (g *LightningTerminal) ValidateMacaroon(ctx context.Context,
requiredPermissions []bakery.Op, fullMethod string) error {

// If the URL being queried has been whitelisted, then no macaroon
// validation is required for the query.
if g.permsMgr.IsWhiteListedURL(fullMethod) {
return nil
}

macHex, err := macaroons.RawMacaroonFromContext(ctx)
if err != nil {
return err
Expand Down