Skip to content

Commit 45e15c1

Browse files
committed
rpc_proxy+terminal: fix error handling with stateless init
This is a follow-up commit that fixes an issue introduced with stateless init where an error would be interpreted incorrectly.
1 parent fadc09a commit 45e15c1

File tree

2 files changed

+82
-21
lines changed

2 files changed

+82
-21
lines changed

rpc_proxy.go

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ func (p *rpcProxy) director(ctx context.Context,
300300
authHeaders := md.Get("authorization")
301301
if len(authHeaders) == 1 {
302302
macBytes, err := p.basicAuthToMacaroon(
303-
authHeaders[0], requestURI,
303+
authHeaders[0], requestURI, nil,
304304
)
305305
if err != nil {
306306
return outCtx, nil, err
@@ -350,10 +350,17 @@ func (p *rpcProxy) UnaryServerInterceptor(
350350
// have proper macaroon support implemented in the UI. We allow
351351
// gRPC web requests to have it and "convert" the auth into a
352352
// proper macaroon now.
353-
newCtx, err := p.convertBasicAuth(ctx, info.FullMethod)
353+
newCtx, err := p.convertBasicAuth(ctx, info.FullMethod, nil)
354354
if err != nil {
355-
return nil, fmt.Errorf("error upgrading basic auth: %v",
356-
err)
355+
// Make sure we handle the case where the super macaroon
356+
// is still empty on startup.
357+
if pErr, ok := err.(*proxyErr); ok &&
358+
pErr.proxyContext == "supermacaroon" {
359+
360+
return nil, fmt.Errorf("super macaroon error: "+
361+
"%v", pErr)
362+
}
363+
return nil, err
357364
}
358365

359366
// With the basic auth converted to a macaroon if necessary,
@@ -387,9 +394,19 @@ func (p *rpcProxy) StreamServerInterceptor(
387394
// have proper macaroon support implemented in the UI. We allow
388395
// gRPC web requests to have it and "convert" the auth into a
389396
// proper macaroon now.
390-
ctx, err := p.convertBasicAuth(ss.Context(), info.FullMethod)
397+
ctx, err := p.convertBasicAuth(
398+
ss.Context(), info.FullMethod, nil,
399+
)
391400
if err != nil {
392-
return fmt.Errorf("error upgrading basic auth: %v", err)
401+
// Make sure we handle the case where the super macaroon
402+
// is still empty on startup.
403+
if pErr, ok := err.(*proxyErr); ok &&
404+
pErr.proxyContext == "supermacaroon" {
405+
406+
return fmt.Errorf("super macaroon error: "+
407+
"%v", pErr)
408+
}
409+
return err
393410
}
394411

395412
// With the basic auth converted to a macaroon if necessary,
@@ -408,21 +425,23 @@ func (p *rpcProxy) StreamServerInterceptor(
408425
// convertBasicAuth tries to convert the HTTP authorization header into a
409426
// macaroon based authentication header.
410427
func (p *rpcProxy) convertBasicAuth(ctx context.Context,
411-
requestURI string) (context.Context, error) {
428+
requestURI string, ctxErr error) (context.Context, error) {
412429

413430
md, ok := metadata.FromIncomingContext(ctx)
414431
if !ok {
415-
return ctx, nil
432+
return ctx, ctxErr
416433
}
417434

418435
authHeaders := md.Get("authorization")
419436
if len(authHeaders) == 0 {
420437
// No basic auth provided, we don't add a macaroon and let the
421438
// gRPC security interceptor reject the request.
422-
return ctx, nil
439+
return ctx, ctxErr
423440
}
424441

425-
macBytes, err := p.basicAuthToMacaroon(authHeaders[0], requestURI)
442+
macBytes, err := p.basicAuthToMacaroon(
443+
authHeaders[0], requestURI, ctxErr,
444+
)
426445
if err != nil || len(macBytes) == 0 {
427446
return ctx, err
428447
}
@@ -434,8 +453,8 @@ func (p *rpcProxy) convertBasicAuth(ctx context.Context,
434453
// basicAuthToMacaroon checks that the incoming request context has the expected
435454
// and valid basic authentication header then attaches the correct macaroon to
436455
// the context so it can be forwarded to the actual gRPC server.
437-
func (p *rpcProxy) basicAuthToMacaroon(basicAuth, requestURI string) ([]byte,
438-
error) {
456+
func (p *rpcProxy) basicAuthToMacaroon(basicAuth, requestURI string,
457+
ctxErr error) ([]byte, error) {
439458

440459
// The user specified an authorization header so this is very likely a
441460
// gRPC Web call from the UI. But we only attach the macaroon if the
@@ -444,10 +463,10 @@ func (p *rpcProxy) basicAuthToMacaroon(basicAuth, requestURI string) ([]byte,
444463
// from the lnd backend.
445464
authHeaderParts := strings.Split(basicAuth, " ")
446465
if len(authHeaderParts) != 2 {
447-
return nil, nil
466+
return nil, ctxErr
448467
}
449468
if authHeaderParts[1] != p.basicAuth {
450-
return nil, nil
469+
return nil, ctxErr
451470
}
452471

453472
var (
@@ -491,7 +510,20 @@ func (p *rpcProxy) basicAuthToMacaroon(basicAuth, requestURI string) ([]byte,
491510
// If we have a super macaroon, we can use that one directly since it
492511
// will contain all permissions we need.
493512
case len(p.superMacaroon) > 0:
494-
return hex.DecodeString(p.superMacaroon)
513+
superMacData, err := hex.DecodeString(p.superMacaroon)
514+
515+
// Make sure we can avoid running into an empty macaroon here if
516+
// something went wrong with the decoding process (if we're
517+
// still starting up).
518+
if err != nil {
519+
return nil, &proxyErr{
520+
proxyContext: "supermacaroon",
521+
wrapped: fmt.Errorf("couldn't decode "+
522+
"super macaroon: %v", err),
523+
}
524+
}
525+
526+
return superMacData, nil
495527

496528
// If we have macaroon data directly, just encode them. This could be
497529
// for initial requests to lnd while we don't have the super macaroon
@@ -507,7 +539,10 @@ func (p *rpcProxy) basicAuthToMacaroon(basicAuth, requestURI string) ([]byte,
507539
return readMacaroon(lncfg.CleanAndExpandPath(macPath))
508540
}
509541

510-
return nil, fmt.Errorf("unknown macaroon to use")
542+
return nil, &proxyErr{
543+
proxyContext: "auth",
544+
wrapped: fmt.Errorf("unknown macaroon to use"),
545+
}
511546
}
512547

513548
// dialBufConnBackend dials an in-memory connection to an RPC listener and

terminal.go

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -706,9 +706,16 @@ func (g *LightningTerminal) ValidateMacaroon(ctx context.Context,
706706
"syncing")
707707
}
708708

709-
return g.faradayServer.ValidateMacaroon(
709+
err = g.faradayServer.ValidateMacaroon(
710710
ctx, requiredPermissions, fullMethod,
711711
)
712+
if err != nil {
713+
return &proxyErr{
714+
proxyContext: "faraday",
715+
wrapped: fmt.Errorf("invalid macaroon: %v",
716+
err),
717+
}
718+
}
712719

713720
case isLoopURI(fullMethod):
714721
// In remote mode we just pass through the request, the remote
@@ -723,9 +730,16 @@ func (g *LightningTerminal) ValidateMacaroon(ctx context.Context,
723730
"syncing")
724731
}
725732

726-
return g.loopServer.ValidateMacaroon(
733+
err = g.loopServer.ValidateMacaroon(
727734
ctx, requiredPermissions, fullMethod,
728735
)
736+
if err != nil {
737+
return &proxyErr{
738+
proxyContext: "loop",
739+
wrapped: fmt.Errorf("invalid macaroon: %v",
740+
err),
741+
}
742+
}
729743

730744
case isPoolURI(fullMethod):
731745
// In remote mode we just pass through the request, the remote
@@ -740,14 +754,26 @@ func (g *LightningTerminal) ValidateMacaroon(ctx context.Context,
740754
"syncing")
741755
}
742756

743-
return g.poolServer.ValidateMacaroon(
757+
err = g.poolServer.ValidateMacaroon(
744758
ctx, requiredPermissions, fullMethod,
745759
)
760+
if err != nil {
761+
return &proxyErr{
762+
proxyContext: "pool",
763+
wrapped: fmt.Errorf("invalid macaroon: %v",
764+
err),
765+
}
766+
}
746767

747768
case isLitURI(fullMethod):
748-
_, err := g.rpcProxy.convertBasicAuth(ctx, fullMethod)
769+
wrap := fmt.Errorf("invalid basic auth")
770+
_, err := g.rpcProxy.convertBasicAuth(ctx, fullMethod, wrap)
749771
if err != nil {
750-
return err
772+
return &proxyErr{
773+
proxyContext: "lit",
774+
wrapped: fmt.Errorf("invalid auth: %v",
775+
err),
776+
}
751777
}
752778
}
753779

0 commit comments

Comments
 (0)