Skip to content

Commit c13864c

Browse files
authored
Merge pull request #413 from ellemouton/addLndSubserverPerms
subserver_perms: add Lnd's registered subserver perms
2 parents 824e94a + b3ad811 commit c13864c

File tree

7 files changed

+384
-98
lines changed

7 files changed

+384
-98
lines changed

itest/litd_mode_integrated_test.go

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import (
2626
"github.com/lightninglabs/pool/poolrpc"
2727
"github.com/lightningnetwork/lnd/keychain"
2828
"github.com/lightningnetwork/lnd/lnrpc"
29+
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
30+
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
2931
"github.com/stretchr/testify/require"
3032
"golang.org/x/net/http2"
3133
"google.golang.org/grpc"
@@ -81,17 +83,33 @@ var (
8183
// gRPC request. One byte version and then 4 bytes content length.
8284
emptyGrpcWebRequest = []byte{0, 0, 0, 0, 0}
8385

84-
lndRequestFn = func(ctx context.Context,
86+
lnrpcRequestFn = func(ctx context.Context,
8587
c grpc.ClientConnInterface) (proto.Message, error) {
8688

87-
lndConn := lnrpc.NewLightningClient(c)
88-
return lndConn.GetInfo(
89+
lnrpcConn := lnrpc.NewLightningClient(c)
90+
return lnrpcConn.GetInfo(
8991
ctx, &lnrpc.GetInfoRequest{},
9092
)
9193
}
9294
lndMacaroonFn = func(cfg *LitNodeConfig) string {
9395
return cfg.AdminMacPath
9496
}
97+
routerrpcRequestFn = func(ctx context.Context,
98+
c grpc.ClientConnInterface) (proto.Message, error) {
99+
100+
routerrpcConn := routerrpc.NewRouterClient(c)
101+
return routerrpcConn.GetMissionControlConfig(
102+
ctx, &routerrpc.GetMissionControlConfigRequest{},
103+
)
104+
}
105+
walletrpcRequestFn = func(ctx context.Context,
106+
c grpc.ClientConnInterface) (proto.Message, error) {
107+
108+
walletrpcConn := walletrpc.NewWalletKitClient(c)
109+
return walletrpcConn.ListUnspent(
110+
ctx, &walletrpc.ListUnspentRequest{},
111+
)
112+
}
95113
faradayRequestFn = func(ctx context.Context,
96114
c grpc.ClientConnInterface) (proto.Message, error) {
97115

@@ -145,14 +163,32 @@ var (
145163
allowedThroughLNC bool
146164
grpcWebURI string
147165
restWebURI string
166+
restPOST bool
148167
}{{
149168
name: "lnrpc",
150169
macaroonFn: lndMacaroonFn,
151-
requestFn: lndRequestFn,
170+
requestFn: lnrpcRequestFn,
152171
successPattern: "\"identity_pubkey\":\"0",
153172
allowedThroughLNC: true,
154173
grpcWebURI: "/lnrpc.Lightning/GetInfo",
155174
restWebURI: "/v1/getinfo",
175+
}, {
176+
name: "routerrpc",
177+
macaroonFn: lndMacaroonFn,
178+
requestFn: routerrpcRequestFn,
179+
successPattern: "\"config\":{",
180+
allowedThroughLNC: true,
181+
grpcWebURI: "/routerrpc.Router/GetMissionControlConfig",
182+
restWebURI: "/v2/router/mccfg",
183+
}, {
184+
name: "walletrpc",
185+
macaroonFn: lndMacaroonFn,
186+
requestFn: walletrpcRequestFn,
187+
successPattern: "\"utxos\":[",
188+
allowedThroughLNC: true,
189+
grpcWebURI: "/walletrpc.WalletKit/ListUnspent",
190+
restWebURI: "/v2/wallet/utxos",
191+
restPOST: true,
156192
}, {
157193
name: "frdrpc",
158194
macaroonFn: faradayMacaroonFn,
@@ -322,6 +358,7 @@ func testModeIntegrated(net *NetworkHarness, t *harnessTest) {
322358
endpoint.macaroonFn(cfg),
323359
endpoint.restWebURI,
324360
endpoint.successPattern,
361+
endpoint.restPOST,
325362
)
326363
})
327364
}
@@ -529,7 +566,7 @@ func runGRPCWebAuthTest(t *testing.T, hostPort, uiPassword, grpcWebURI string) {
529566

530567
// runRESTAuthTest tests authentication of the given REST interface.
531568
func runRESTAuthTest(t *testing.T, hostPort, uiPassword, macaroonPath, restURI,
532-
successPattern string) {
569+
successPattern string, usePOST bool) {
533570

534571
basicAuth := base64.StdEncoding.EncodeToString(
535572
[]byte(fmt.Sprintf("%s:%s", uiPassword, uiPassword)),
@@ -539,13 +576,19 @@ func runRESTAuthTest(t *testing.T, hostPort, uiPassword, macaroonPath, restURI,
539576
}
540577
url := fmt.Sprintf("https://%s%s", hostPort, restURI)
541578

579+
method := "GET"
580+
if usePOST {
581+
method = "POST"
582+
}
583+
542584
// First test a REST call without authorization, which should fail.
543-
body, responseHeader, err := callURL(url, "GET", nil, nil, false)
585+
body, responseHeader, err := callURL(url, method, nil, nil, false)
544586
require.NoError(t, err)
545587

546-
require.Equal(
588+
require.Equalf(
547589
t, "application/grpc",
548590
responseHeader.Get("grpc-metadata-content-type"),
591+
"response headers: %v, body: %v", responseHeader, body,
549592
)
550593
require.Equal(
551594
t, "application/json",
@@ -558,7 +601,7 @@ func runRESTAuthTest(t *testing.T, hostPort, uiPassword, macaroonPath, restURI,
558601

559602
// Now add the UI password which should make the request succeed.
560603
body, responseHeader, err = callURL(
561-
url, "GET", nil, basicAuthHeader, false,
604+
url, method, nil, basicAuthHeader, false,
562605
)
563606
require.NoError(t, err)
564607
require.Contains(t, body, successPattern)
@@ -573,7 +616,7 @@ func runRESTAuthTest(t *testing.T, hostPort, uiPassword, macaroonPath, restURI,
573616
},
574617
}
575618
body, responseHeader, err = callURL(
576-
url, "GET", nil, macaroonHeader, false,
619+
url, method, nil, macaroonHeader, false,
577620
)
578621
require.NoError(t, err)
579622
require.Contains(t, body, successPattern)
@@ -834,7 +877,12 @@ func bakeSuperMacaroon(cfg *LitNodeConfig, readOnly bool) (string, error) {
834877
lndAdminCtx := macaroonContext(ctxt, lndAdminMacBytes)
835878
lndConn := lnrpc.NewLightningClient(rawConn)
836879

837-
superMacPermissions := terminal.GetAllPermissions(readOnly)
880+
permsMgr, err := terminal.NewPermissionsManager()
881+
if err != nil {
882+
return "", err
883+
}
884+
885+
superMacPermissions := permsMgr.ActivePermissions(readOnly)
838886
nullID := [4]byte{}
839887
superMacHex, err := terminal.BakeSuperMacaroon(
840888
lndAdminCtx, lndConn, session.NewSuperMacaroonRootKeyID(nullID),

itest/litd_mode_remote_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ func testModeRemote(net *NetworkHarness, t *harnessTest) {
125125
endpoint.macaroonFn(cfg),
126126
endpoint.restWebURI,
127127
endpoint.successPattern,
128+
endpoint.restPOST,
128129
)
129130
})
130131
}

make/release_flags.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ windows-386 \
1111
windows-amd64 \
1212
windows-arm
1313

14-
LND_RELEASE_TAGS = litd autopilotrpc signrpc walletrpc chainrpc invoicesrpc watchtowerrpc
14+
LND_RELEASE_TAGS = litd autopilotrpc signrpc walletrpc chainrpc invoicesrpc watchtowerrpc neutrinorpc peersrpc
1515

1616
# By default we will build all systems. But with the 'sys' tag, a specific
1717
# system can be specified. This is useful to release for a subset of

rpc_proxy.go

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import (
2424
"google.golang.org/grpc/metadata"
2525
"google.golang.org/grpc/status"
2626
"google.golang.org/grpc/test/bufconn"
27-
"gopkg.in/macaroon-bakery.v2/bakery"
2827
"gopkg.in/macaroon.v2"
2928
)
3029

@@ -59,8 +58,7 @@ func (e *proxyErr) Unwrap() error {
5958
// component.
6059
func newRpcProxy(cfg *Config, validator macaroons.MacaroonValidator,
6160
superMacValidator session.SuperMacaroonValidator,
62-
permissionMap map[string][]bakery.Op,
63-
bufListener *bufconn.Listener) *rpcProxy {
61+
permsMgr *PermissionsManager, bufListener *bufconn.Listener) *rpcProxy {
6462

6563
// The gRPC web calls are protected by HTTP basic auth which is defined
6664
// by base64(username:password). Because we only have a password, we
@@ -77,7 +75,7 @@ func newRpcProxy(cfg *Config, validator macaroons.MacaroonValidator,
7775
p := &rpcProxy{
7876
cfg: cfg,
7977
basicAuth: basicAuth,
80-
permissionMap: permissionMap,
78+
permsMgr: permsMgr,
8179
macValidator: validator,
8280
superMacValidator: superMacValidator,
8381
bufListener: bufListener,
@@ -146,9 +144,9 @@ func newRpcProxy(cfg *Config, validator macaroons.MacaroonValidator,
146144
// +---------------------+
147145
//
148146
type rpcProxy struct {
149-
cfg *Config
150-
basicAuth string
151-
permissionMap map[string][]bakery.Op
147+
cfg *Config
148+
basicAuth string
149+
permsMgr *PermissionsManager
152150

153151
macValidator macaroons.MacaroonValidator
154152
superMacValidator session.SuperMacaroonValidator
@@ -345,17 +343,17 @@ func (p *rpcProxy) makeDirector(allowLitRPC bool) func(ctx context.Context,
345343
// handled by the integrated daemons that are hooking into lnd's
346344
// gRPC server.
347345
switch {
348-
case isFaradayURI(requestURI) && p.cfg.faradayRemote:
346+
case p.permsMgr.IsFaradayURI(requestURI) && p.cfg.faradayRemote:
349347
return outCtx, p.faradayConn, nil
350348

351-
case isLoopURI(requestURI) && p.cfg.loopRemote:
349+
case p.permsMgr.IsLoopURI(requestURI) && p.cfg.loopRemote:
352350
return outCtx, p.loopConn, nil
353351

354-
case isPoolURI(requestURI) && p.cfg.poolRemote:
352+
case p.permsMgr.IsPoolURI(requestURI) && p.cfg.poolRemote:
355353
return outCtx, p.poolConn, nil
356354

357355
// Calls to LiT session RPC aren't allowed in some cases.
358-
case isLitURI(requestURI) && !allowLitRPC:
356+
case p.permsMgr.IsLitURI(requestURI) && !allowLitRPC:
359357
return outCtx, nil, status.Errorf(
360358
codes.Unimplemented, "unknown service %s",
361359
requestURI,
@@ -373,7 +371,7 @@ func (p *rpcProxy) UnaryServerInterceptor(ctx context.Context, req interface{},
373371
info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{},
374372
error) {
375373

376-
uriPermissions, ok := p.permissionMap[info.FullMethod]
374+
uriPermissions, ok := p.permsMgr.URIPermissions(info.FullMethod)
377375
if !ok {
378376
return nil, fmt.Errorf("%s: unknown permissions "+
379377
"required for method", info.FullMethod)
@@ -414,7 +412,7 @@ func (p *rpcProxy) StreamServerInterceptor(srv interface{},
414412
ss grpc.ServerStream, info *grpc.StreamServerInfo,
415413
handler grpc.StreamHandler) error {
416414

417-
uriPermissions, ok := p.permissionMap[info.FullMethod]
415+
uriPermissions, ok := p.permsMgr.URIPermissions(info.FullMethod)
418416
if !ok {
419417
return fmt.Errorf("%s: unknown permissions required "+
420418
"for method", info.FullMethod)
@@ -503,31 +501,31 @@ func (p *rpcProxy) basicAuthToMacaroon(basicAuth, requestURI string,
503501
macData []byte
504502
)
505503
switch {
506-
case isLndURI(requestURI):
504+
case p.permsMgr.IsLndURI(requestURI):
507505
_, _, _, macPath, macData = p.cfg.lndConnectParams()
508506

509-
case isFaradayURI(requestURI):
507+
case p.permsMgr.IsFaradayURI(requestURI):
510508
if p.cfg.faradayRemote {
511509
macPath = p.cfg.Remote.Faraday.MacaroonPath
512510
} else {
513511
macPath = p.cfg.Faraday.MacaroonPath
514512
}
515513

516-
case isLoopURI(requestURI):
514+
case p.permsMgr.IsLoopURI(requestURI):
517515
if p.cfg.loopRemote {
518516
macPath = p.cfg.Remote.Loop.MacaroonPath
519517
} else {
520518
macPath = p.cfg.Loop.MacaroonPath
521519
}
522520

523-
case isPoolURI(requestURI):
521+
case p.permsMgr.IsPoolURI(requestURI):
524522
if p.cfg.poolRemote {
525523
macPath = p.cfg.Remote.Pool.MacaroonPath
526524
} else {
527525
macPath = p.cfg.Pool.MacaroonPath
528526
}
529527

530-
case isLitURI(requestURI):
528+
case p.permsMgr.IsLitURI(requestURI):
531529
macPath = p.cfg.MacaroonPath
532530

533531
default:
@@ -580,7 +578,7 @@ func (p *rpcProxy) basicAuthToMacaroon(basicAuth, requestURI string,
580578
func (p *rpcProxy) convertSuperMacaroon(ctx context.Context, macHex string,
581579
fullMethod string) ([]byte, error) {
582580

583-
requiredPermissions, ok := p.permissionMap[fullMethod]
581+
requiredPermissions, ok := p.permsMgr.URIPermissions(fullMethod)
584582
if !ok {
585583
return nil, fmt.Errorf("%s: unknown permissions required for "+
586584
"method", fullMethod)
@@ -605,17 +603,17 @@ func (p *rpcProxy) convertSuperMacaroon(ctx context.Context, macHex string,
605603
// Is this actually a request that goes to a daemon that is running
606604
// remotely?
607605
switch {
608-
case isFaradayURI(fullMethod) && p.cfg.faradayRemote:
606+
case p.permsMgr.IsFaradayURI(fullMethod) && p.cfg.faradayRemote:
609607
return readMacaroon(lncfg.CleanAndExpandPath(
610608
p.cfg.Remote.Faraday.MacaroonPath,
611609
))
612610

613-
case isLoopURI(fullMethod) && p.cfg.loopRemote:
611+
case p.permsMgr.IsLoopURI(fullMethod) && p.cfg.loopRemote:
614612
return readMacaroon(lncfg.CleanAndExpandPath(
615613
p.cfg.Remote.Loop.MacaroonPath,
616614
))
617615

618-
case isPoolURI(fullMethod) && p.cfg.poolRemote:
616+
case p.permsMgr.IsPoolURI(fullMethod) && p.cfg.poolRemote:
619617
return readMacaroon(lncfg.CleanAndExpandPath(
620618
p.cfg.Remote.Pool.MacaroonPath,
621619
))

session_rpcserver.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ type sessionRpcServerConfig struct {
3939
superMacBaker func(ctx context.Context, rootKeyID uint64,
4040
recipe *session.MacaroonRecipe) (string, error)
4141
firstConnectionDeadline time.Duration
42+
permMgr *PermissionsManager
4243
}
4344

4445
// newSessionRPCServer creates a new sessionRpcServer using the passed config.
@@ -205,7 +206,7 @@ func (s *sessionRpcServer) resumeSession(sess *session.Session) error {
205206
mac, err := s.cfg.superMacBaker(
206207
context.Background(), sess.MacaroonRootKey,
207208
&session.MacaroonRecipe{
208-
Permissions: GetAllPermissions(readOnly),
209+
Permissions: s.cfg.permMgr.ActivePermissions(readOnly),
209210
Caveats: caveats,
210211
},
211212
)

0 commit comments

Comments
 (0)