@@ -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.
554620func dialBufConnBackend (listener * bufconn.Listener ) (* grpc.ClientConn , error ) {
0 commit comments