Skip to content

Commit 6bcf19f

Browse files
committed
rpc_proxy: special case the handling of BakeSuperMacaroon
In this commit, we special case the handling of BakeSuperMacaroon so as to allow a user to make use of `litcli bakesupermacaroon` while LiT is running in stateless init mode. The handling is as follows: - if the call to _LiT's_ BakeSuperMacaroon is made while in stateless init mode then we can assume that the macaroon provided is either: 1) an LND native macaroon which may or may not have the necessary permissions for the _LND_ "/lnrpc.Lightning/BakeMacaroon" call. 2) a baked macaroon (possibly a super macaroon) which may or may not have the permissions to the _LiT_ "/litrpc.Proxy/BakeSuperMacaroon" call. For case 1: we check that the provided macaroon has the correct perms. If it does, then we use LiT's existing connection to LND to bake the super mac. For case 2: we have a macaroon that doesnt have LND's bakemac call perms directly but does have LiT's BakeSuperMac perms. So for this, we treat the call as normal and verify using LiT's macaroon validator as normal.
1 parent d3dc753 commit 6bcf19f

File tree

1 file changed

+84
-0
lines changed

1 file changed

+84
-0
lines changed

rpc_proxy.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ const (
3434
// HeaderMacaroon is the HTTP header field name that is used to send
3535
// the macaroon.
3636
HeaderMacaroon = "Macaroon"
37+
38+
lndBakeMacMethod = "/lnrpc.Lightning/BakeMacaroon"
39+
litBakeSuperMacMethod = "/litrpc.Proxy/BakeSuperMacaroon"
3740
)
3841

3942
var (
@@ -410,6 +413,87 @@ func (p *rpcProxy) UnaryServerInterceptor(ctx context.Context, req interface{},
410413
return nil, err
411414
}
412415

416+
// We special case the handling of a call to LiT's BakeSuperMacaroon
417+
// method if we are in stateless init mode. If a user has called this
418+
// method, they are either calling with an LND macaroon or a baked
419+
// super macaroon.
420+
if p.cfg.statelessInitMode &&
421+
info.FullMethod == litBakeSuperMacMethod {
422+
423+
// Fetch permissions that are required for LND's BakeMacaroon
424+
// method. Since this will only be called in stateless-init mode
425+
// which is only possible in integrated mode, we can be sure
426+
// that the permissions returned here are the up-to-date
427+
// permissions for the LND method.
428+
requiredPerms, ok := p.permsMgr.URIPermissions(lndBakeMacMethod)
429+
if !ok {
430+
return nil, fmt.Errorf("unknown permissions for %s",
431+
lndBakeMacMethod)
432+
}
433+
permissions := make(
434+
[]*lnrpc.MacaroonPermission, len(requiredPerms),
435+
)
436+
for idx, perm := range requiredPerms {
437+
permissions[idx] = &lnrpc.MacaroonPermission{
438+
Entity: perm.Entity,
439+
Action: perm.Action,
440+
}
441+
}
442+
443+
// Next, we extract the macaroon provided by the user.
444+
macHex, err := macaroons.RawMacaroonFromContext(ctx)
445+
if err != nil {
446+
return nil, err
447+
}
448+
449+
macBytes, err := hex.DecodeString(macHex)
450+
if err != nil {
451+
return nil, err
452+
}
453+
454+
lndClient, err := p.getBasicLNDClient()
455+
if err != nil {
456+
return nil, err
457+
}
458+
459+
// Using LiT's existing connection to LND, we verify that the
460+
// provided macaroon contains the required permissions for the
461+
// LND BakeMacaroon method.
462+
resp, err := lndClient.CheckMacaroonPermissions(
463+
ctx, &lnrpc.CheckMacPermRequest{
464+
Macaroon: macBytes,
465+
Permissions: permissions,
466+
FullMethod: lndBakeMacMethod,
467+
},
468+
)
469+
470+
// There are two valid possible outcomes depending on if the
471+
// user used LND's macaroon which contains the permissions
472+
// required for LND's BakeMacaroon method or if they used a
473+
// super macaroon that contains the necessary permissions for
474+
// LiT's BakeSuperMacaroon method. If the former is the case,
475+
// and the macaroon is valid, then we can now directly call the
476+
// handler without further checking the macaroon.
477+
if err == nil && resp.Valid {
478+
// Call LiT's BakeSuperMacaroon function.
479+
return handler(ctx, req)
480+
}
481+
482+
// If we do get an error from the above call, then the later
483+
// case described above might be true: the call might have
484+
// been performed with a macaroon that has the permissions for
485+
// LiT's BakeSuperMacaroon method. In that case, we log the
486+
// error, but we pass the call on to LiT's macaroon validator
487+
// as normal.
488+
log.Warnf("The call to LiT's %s method did not contain a "+
489+
"macaroon with the permissions required for LND's %s "+
490+
"method: %v. The call will instead be verified "+
491+
"against LiT's macaroon validator to check if it has "+
492+
"direct permissions for LiT's %s method.",
493+
litBakeSuperMacMethod, lndBakeMacMethod, err,
494+
litBakeSuperMacMethod)
495+
}
496+
413497
// With the basic auth converted to a macaroon if necessary,
414498
// let's now validate the macaroon.
415499
err = p.macValidator.ValidateMacaroon(

0 commit comments

Comments
 (0)