Skip to content

Commit a8309a9

Browse files
committed
rpc_proxy: convert super macaroon into daemon mac
If a daemon is running in remote mode, we need to convert a super macaroon into the daemon specific macaroon before sending it to the remote daemon, since the super macaroon is issued by lnd and can only be validated by lnd's macaroon root key.
1 parent 4e3cb10 commit a8309a9

File tree

1 file changed

+68
-2
lines changed

1 file changed

+68
-2
lines changed

rpc_proxy.go

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,9 +307,11 @@ func (p *rpcProxy) director(ctx context.Context,
307307

308308
outCtx := metadata.NewOutgoingContext(ctx, mdCopy)
309309

310-
// Is there a basic auth set?
310+
// Is there a basic auth or super macaroon set?
311311
authHeaders := md.Get("authorization")
312-
if len(authHeaders) == 1 {
312+
macHeader := md.Get(HeaderMacaroon)
313+
switch {
314+
case len(authHeaders) == 1:
313315
macBytes, err := p.basicAuthToMacaroon(
314316
authHeaders[0], requestURI, nil,
315317
)
@@ -319,6 +321,20 @@ func (p *rpcProxy) director(ctx context.Context,
319321
if len(macBytes) > 0 {
320322
mdCopy.Set(HeaderMacaroon, hex.EncodeToString(macBytes))
321323
}
324+
325+
case len(macHeader) == 1 && session.IsSuperMacaroon(macHeader[0]):
326+
// If we have a macaroon, and it's a super macaroon, then we
327+
// need to convert it into the actual daemon macaroon if they're
328+
// running in remote mode.
329+
macBytes, err := p.convertSuperMacaroon(
330+
ctx, macHeader[0], requestURI,
331+
)
332+
if err != nil {
333+
return outCtx, nil, err
334+
}
335+
if len(macBytes) > 0 {
336+
mdCopy.Set(HeaderMacaroon, hex.EncodeToString(macBytes))
337+
}
322338
}
323339

324340
// Direct the call to the correct backend. All gRPC calls end up here
@@ -549,6 +565,56 @@ func (p *rpcProxy) basicAuthToMacaroon(basicAuth, requestURI string,
549565
}
550566
}
551567

568+
// convertSuperMacaroon converts a super macaroon into a daemon specific
569+
// macaroon, but only if the super macaroon contains all required permissions
570+
// and the target daemon is actually running in remote mode.
571+
func (p *rpcProxy) convertSuperMacaroon(ctx context.Context, macHex string,
572+
fullMethod string) ([]byte, error) {
573+
574+
requiredPermissions, ok := p.permissionMap[fullMethod]
575+
if !ok {
576+
return nil, fmt.Errorf("%s: unknown permissions required for "+
577+
"method", fullMethod)
578+
}
579+
580+
// We have a super macaroon, from here on out we'll return errors if
581+
// something isn't the way we expect it to be.
582+
macBytes, err := hex.DecodeString(macHex)
583+
if err != nil {
584+
return nil, err
585+
}
586+
587+
// Make sure the super macaroon is valid and contains all the required
588+
// permissions.
589+
err = p.superMacValidator(
590+
ctx, macBytes, requiredPermissions, fullMethod,
591+
)
592+
if err != nil {
593+
return nil, err
594+
}
595+
596+
// Is this actually a request that goes to a daemon that is running
597+
// remotely?
598+
switch {
599+
case isFaradayURI(fullMethod) && p.cfg.faradayRemote:
600+
return readMacaroon(lncfg.CleanAndExpandPath(
601+
p.cfg.Remote.Faraday.MacaroonPath,
602+
))
603+
604+
case isLoopURI(fullMethod) && p.cfg.loopRemote:
605+
return readMacaroon(lncfg.CleanAndExpandPath(
606+
p.cfg.Remote.Loop.MacaroonPath,
607+
))
608+
609+
case isPoolURI(fullMethod) && p.cfg.poolRemote:
610+
return readMacaroon(lncfg.CleanAndExpandPath(
611+
p.cfg.Remote.Pool.MacaroonPath,
612+
))
613+
}
614+
615+
return nil, nil
616+
}
617+
552618
// dialBufConnBackend dials an in-memory connection to an RPC listener and
553619
// ignores any TLS certificate mismatches.
554620
func dialBufConnBackend(listener *bufconn.Listener) (*grpc.ClientConn, error) {

0 commit comments

Comments
 (0)