@@ -102,6 +102,17 @@ var (
102102 lndMacaroonFn = func (cfg * LitNodeConfig ) string {
103103 return cfg .AdminMacPath
104104 }
105+ lnrpcStateRequestFn = func (ctx context.Context ,
106+ c grpc.ClientConnInterface ) (proto.Message , error ) {
107+
108+ lnrpcConn := lnrpc .NewStateClient (c )
109+ return lnrpcConn .GetState (
110+ ctx , & lnrpc.GetStateRequest {},
111+ )
112+ }
113+ emptyMacaroonFn = func (_ * LitNodeConfig ) string {
114+ return ""
115+ }
105116 routerrpcRequestFn = func (ctx context.Context ,
106117 c grpc.ClientConnInterface ) (proto.Message , error ) {
107118
@@ -196,6 +207,9 @@ var (
196207 restWebURI string
197208 restPOST bool
198209 canDisable bool
210+
211+ // noAuth is true if the call does not require a macaroon.
212+ noAuth bool
199213 }{{
200214 name : "lnrpc" ,
201215 macaroonFn : lndMacaroonFn ,
@@ -204,6 +218,15 @@ var (
204218 allowedThroughLNC : true ,
205219 grpcWebURI : "/lnrpc.Lightning/GetInfo" ,
206220 restWebURI : "/v1/getinfo" ,
221+ }, {
222+ name : "lnrpc-whitelist" ,
223+ macaroonFn : emptyMacaroonFn ,
224+ requestFn : lnrpcStateRequestFn ,
225+ successPattern : "\" state\" :" ,
226+ allowedThroughLNC : true ,
227+ grpcWebURI : "/lnrpc.State/GetState" ,
228+ restWebURI : "/v1/state" ,
229+ noAuth : true ,
207230 }, {
208231 name : "routerrpc" ,
209232 macaroonFn : lndMacaroonFn ,
@@ -408,6 +431,7 @@ func integratedTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
408431 runGRPCAuthTest (
409432 ttt , cfg .RPCAddr (), cfg .TLSCertPath ,
410433 endpoint .macaroonFn (cfg ),
434+ endpoint .noAuth ,
411435 endpoint .requestFn ,
412436 endpoint .successPattern ,
413437 endpointDisabled ,
@@ -419,6 +443,7 @@ func integratedTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
419443 runGRPCAuthTest (
420444 ttt , cfg .LitAddr (), cfg .LitTLSCertPath ,
421445 endpoint .macaroonFn (cfg ),
446+ endpoint .noAuth ,
422447 endpoint .requestFn ,
423448 endpoint .successPattern ,
424449 endpointDisabled ,
@@ -441,6 +466,7 @@ func integratedTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
441466 runUIPasswordCheck (
442467 ttt , cfg .RPCAddr (), cfg .TLSCertPath ,
443468 cfg .UIPassword , endpoint .requestFn ,
469+ endpoint .noAuth ,
444470 true , endpoint .successPattern ,
445471 endpointDisabled ,
446472 "Unimplemented desc = unknown service" ,
@@ -456,6 +482,7 @@ func integratedTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
456482 runUIPasswordCheck (
457483 ttt , cfg .LitAddr (), cfg .LitTLSCertPath ,
458484 cfg .UIPassword , endpoint .requestFn ,
485+ endpoint .noAuth ,
459486 shouldFailWithoutMacaroon ,
460487 endpoint .successPattern ,
461488 endpointDisabled ,
@@ -486,7 +513,7 @@ func integratedTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
486513 endpoint .grpcWebURI ,
487514 withoutUIPassword , endpointDisabled ,
488515 "unknown permissions required for " +
489- "method" ,
516+ "method" , endpoint . noAuth ,
490517 )
491518 })
492519 }
@@ -510,7 +537,7 @@ func integratedTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
510537 tt .Run (endpoint .name + " lnd port" , func (ttt * testing.T ) {
511538 runGRPCAuthTest (
512539 ttt , cfg .RPCAddr (), cfg .TLSCertPath ,
513- superMacFile ,
540+ superMacFile , endpoint . noAuth ,
514541 endpoint .requestFn ,
515542 endpoint .successPattern ,
516543 endpointDisabled ,
@@ -521,7 +548,7 @@ func integratedTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
521548 tt .Run (endpoint .name + " lit port" , func (ttt * testing.T ) {
522549 runGRPCAuthTest (
523550 ttt , cfg .LitAddr (), cfg .LitTLSCertPath ,
524- superMacFile ,
551+ superMacFile , endpoint . noAuth ,
525552 endpoint .requestFn ,
526553 endpoint .successPattern ,
527554 endpointDisabled ,
@@ -548,6 +575,7 @@ func integratedTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
548575 endpoint .successPattern ,
549576 endpoint .restPOST ,
550577 withoutUIPassword , endpointDisabled ,
578+ endpoint .noAuth ,
551579 )
552580 })
553581 }
@@ -578,7 +606,7 @@ func integratedTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
578606 endpoint .successPattern ,
579607 endpoint .allowedThroughLNC ,
580608 "unknown service" ,
581- endpointDisabled ,
609+ endpointDisabled , endpoint . noAuth ,
582610 )
583611 })
584612 }
@@ -644,7 +672,7 @@ func integratedTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
644672 ttt , rawLNCConn , endpoint .requestFn ,
645673 endpoint .successPattern ,
646674 allowed , "permission denied" ,
647- endpointDisabled ,
675+ endpointDisabled , endpoint . noAuth ,
648676 )
649677 })
650678 }
@@ -709,7 +737,7 @@ func runCertificateCheck(t *testing.T, node *HarnessNode) {
709737
710738// runGRPCAuthTest tests authentication of the given gRPC interface.
711739func runGRPCAuthTest (t * testing.T , hostPort , tlsCertPath , macPath string ,
712- makeRequest requestFn , successContent string , disabled bool ,
740+ noMac bool , makeRequest requestFn , successContent string , disabled bool ,
713741 disabledErr string ) {
714742
715743 ctxb := context .Background ()
@@ -720,6 +748,21 @@ func runGRPCAuthTest(t *testing.T, hostPort, tlsCertPath, macPath string,
720748 require .NoError (t , err )
721749 defer rawConn .Close ()
722750
751+ if noMac {
752+ resp , err := makeRequest (ctxt , rawConn )
753+ if disabled {
754+ require .ErrorContains (t , err , disabledErr )
755+ return
756+ }
757+ require .NoError (t , err )
758+
759+ json , err := marshalOptions .Marshal (resp )
760+ require .NoError (t , err )
761+ require .Contains (t , string (json ), successContent )
762+
763+ return
764+ }
765+
723766 // We have a connection without any macaroon. A call should fail.
724767 _ , err = makeRequest (ctxt , rawConn )
725768 if disabled {
@@ -772,7 +815,7 @@ func runGRPCAuthTest(t *testing.T, hostPort, tlsCertPath, macPath string,
772815
773816// runUIPasswordCheck tests UI password authentication.
774817func runUIPasswordCheck (t * testing.T , hostPort , tlsCertPath , uiPassword string ,
775- makeRequest requestFn , shouldFailWithoutMacaroon bool ,
818+ makeRequest requestFn , noAuth , shouldFailWithoutMacaroon bool ,
776819 successContent string , disabled bool , disabledErr string ) {
777820
778821 ctxb := context .Background ()
@@ -783,11 +826,21 @@ func runUIPasswordCheck(t *testing.T, hostPort, tlsCertPath, uiPassword string,
783826 require .NoError (t , err )
784827 defer rawConn .Close ()
785828
786- // Make sure that a call without any metadata results in an error.
787- _ , err = makeRequest (ctxt , rawConn )
788- if disabled {
829+ // Make sure that a call without any metadata results in an error unless
830+ // this is a call that is allowed to be un-authenticated in which case
831+ // we expect it to succeed.
832+ resp , err := makeRequest (ctxt , rawConn )
833+ switch {
834+ case disabled :
789835 require .ErrorContains (t , err , disabledErr )
790- } else {
836+ case noAuth :
837+ require .NoError (t , err )
838+ json , err := marshalOptions .Marshal (resp )
839+ require .NoError (t , err )
840+ require .Contains (t , string (json ), successContent )
841+
842+ return
843+ default :
791844 require .ErrorContains (t , err , "expected 1 macaroon, got 0" )
792845 }
793846
@@ -826,7 +879,7 @@ func runUIPasswordCheck(t *testing.T, hostPort, tlsCertPath, uiPassword string,
826879 // Using the correct UI password should work for all requests unless the
827880 // request is for a disabled sub-server.
828881 ctxm = uiPasswordContext (ctxt , uiPassword , false )
829- resp , err : = makeRequest (ctxm , rawConn )
882+ resp , err = makeRequest (ctxm , rawConn )
830883
831884 // On lnd's gRPC interface we don't support using the UI password.
832885 if shouldFailWithoutMacaroon {
@@ -898,7 +951,8 @@ func runIndexPageCheck(t *testing.T, hostPort string, uiDisabled bool) {
898951
899952// runGRPCWebAuthTest tests authentication of the given gRPC interface.
900953func runGRPCWebAuthTest (t * testing.T , hostPort , uiPassword , grpcWebURI string ,
901- shouldFailWithUIPassword , disabled bool , disableErr string ) {
954+ shouldFailWithUIPassword , disabled bool , disableErr string ,
955+ noAuth bool ) {
902956
903957 basicAuth := base64 .StdEncoding .EncodeToString (
904958 []byte (fmt .Sprintf ("%s:%s" , uiPassword , uiPassword )),
@@ -911,15 +965,26 @@ func runGRPCWebAuthTest(t *testing.T, hostPort, uiPassword, grpcWebURI string,
911965
912966 url := fmt .Sprintf ("https://%s%s" , hostPort , grpcWebURI )
913967
914- // First test a grpc-web call without authorization, which should fail.
915- _ , responseHeader , err := postURL (url , emptyGrpcWebRequest , header )
968+ // First test a grpc-web call without authorization, which should fail
969+ // unless this call does not require authentication.
970+ body , responseHeader , err := postURL (url , emptyGrpcWebRequest , header )
916971 require .NoError (t , err )
917972
918- if disabled {
973+ switch {
974+ case disabled :
919975 require .Contains (
920976 t , responseHeader .Get ("grpc-message" ), disableErr ,
921977 )
922- } else {
978+
979+ case noAuth :
980+ require .Empty (t , responseHeader .Get ("grpc-message" ))
981+ require .Empty (t , responseHeader .Get ("grpc-status" ))
982+
983+ // We get the status encoded as trailer in the response.
984+ require .Contains (t , body , "grpc-status: 0" )
985+
986+ return
987+ default :
923988 require .Equal (
924989 t , "expected 1 macaroon, got 0" ,
925990 responseHeader .Get ("grpc-message" ),
@@ -933,7 +998,7 @@ func runGRPCWebAuthTest(t *testing.T, hostPort, uiPassword, grpcWebURI string,
933998
934999 // Now add the basic auth and try again.
9351000 header ["authorization" ] = []string {fmt .Sprintf ("Basic %s" , basicAuth )}
936- body , responseHeader , err : = postURL (url , emptyGrpcWebRequest , header )
1001+ body , responseHeader , err = postURL (url , emptyGrpcWebRequest , header )
9371002 require .NoError (t , err )
9381003
9391004 if shouldFailWithUIPassword {
@@ -968,7 +1033,7 @@ func runGRPCWebAuthTest(t *testing.T, hostPort, uiPassword, grpcWebURI string,
9681033// runRESTAuthTest tests authentication of the given REST interface.
9691034func runRESTAuthTest (t * testing.T , hostPort , uiPassword , macaroonPath , restURI ,
9701035 successPattern string , usePOST , shouldFailWithUIPassword ,
971- disabled bool ) {
1036+ disabled , noMac bool ) {
9721037
9731038 basicAuth := base64 .StdEncoding .EncodeToString (
9741039 []byte (fmt .Sprintf ("%s:%s" , uiPassword , uiPassword )),
@@ -983,7 +1048,9 @@ func runRESTAuthTest(t *testing.T, hostPort, uiPassword, macaroonPath, restURI,
9831048 method = "POST"
9841049 }
9851050
986- // First test a REST call without authorization, which should fail.
1051+ // First test a REST call without authorization, which should fail
1052+ // unless this is a call for an endpoint that does not require
1053+ // authorization.
9871054 body , responseHeader , err := callURL (url , method , nil , nil , false )
9881055 require .NoError (t , err )
9891056
@@ -992,6 +1059,11 @@ func runRESTAuthTest(t *testing.T, hostPort, uiPassword, macaroonPath, restURI,
9921059 responseHeader .Get ("content-type" ),
9931060 )
9941061
1062+ if noMac {
1063+ require .Contains (t , body , successPattern )
1064+ return
1065+ }
1066+
9951067 if disabled {
9961068 require .Empty (
9971069 t , responseHeader .Get ("grpc-metadata-content-type" ),
@@ -1021,7 +1093,6 @@ func runRESTAuthTest(t *testing.T, hostPort, uiPassword, macaroonPath, restURI,
10211093
10221094 default :
10231095 require .Contains (t , body , successPattern )
1024-
10251096 }
10261097
10271098 // And finally, try with the given macaroon.
@@ -1049,7 +1120,7 @@ func runRESTAuthTest(t *testing.T, hostPort, uiPassword, macaroonPath, restURI,
10491120// through Lightning Node Connect.
10501121func runLNCAuthTest (t * testing.T , rawLNCConn grpc.ClientConnInterface ,
10511122 makeRequest requestFn , successContent string , callAllowed bool ,
1052- expectErrContains string , disabled bool ) {
1123+ expectErrContains string , disabled , noMac bool ) {
10531124
10541125 ctxt , cancel := context .WithTimeout (
10551126 context .Background (), defaultTimeout ,
@@ -1062,6 +1133,21 @@ func runLNCAuthTest(t *testing.T, rawLNCConn grpc.ClientConnInterface,
10621133 // macaroon permissions properly set up).
10631134 resp , err := makeRequest (ctxt , rawLNCConn )
10641135
1136+ if noMac {
1137+ if disabled {
1138+ require .ErrorContains (t , err , "unknown gRPC web " +
1139+ "request" )
1140+ return
1141+ }
1142+ require .NoError (t , err )
1143+
1144+ json , err := marshalOptions .Marshal (resp )
1145+ require .NoError (t , err )
1146+ require .Contains (t , string (json ), successContent )
1147+
1148+ return
1149+ }
1150+
10651151 // Is this a disallowed call?
10661152 if ! callAllowed {
10671153 if disabled {
0 commit comments