@@ -138,6 +138,9 @@ var (
138138 loopMacaroonFn = func (cfg * LitNodeConfig ) string {
139139 return cfg .LoopMacPath
140140 }
141+ emptyMacaroonFn = func (_ * LitNodeConfig ) string {
142+ return ""
143+ }
141144 poolRequestFn = func (ctx context.Context ,
142145 c grpc.ClientConnInterface ) (proto.Message , error ) {
143146
@@ -182,6 +185,14 @@ var (
182185 litConn := litrpc .NewProxyClient (c )
183186 return litConn .GetInfo (ctx , & litrpc.GetInfoRequest {})
184187 }
188+ statusRequestFn = func (ctx context.Context ,
189+ c grpc.ClientConnInterface ) (proto.Message , error ) {
190+
191+ litConn := litrpc .NewStatusClient (c )
192+ return litConn .SubServerStatus (
193+ ctx , & litrpc.SubServerStatusReq {},
194+ )
195+ }
185196 litMacaroonFn = func (cfg * LitNodeConfig ) string {
186197 return cfg .LitMacPath
187198 }
@@ -201,6 +212,9 @@ var (
201212 // Lit's grpc server and so will never be accessible via the
202213 // LND port.
203214 litOnly bool
215+
216+ // noAuth is true if the call does not require a macaroon.
217+ noAuth bool
204218 }{{
205219 name : "lnrpc" ,
206220 macaroonFn : lndMacaroonFn ,
@@ -298,6 +312,16 @@ var (
298312 grpcWebURI : "/litrpc.Proxy/GetInfo" ,
299313 restWebURI : "/v1/proxy/info" ,
300314 litOnly : true ,
315+ }, {
316+ name : "litrpc-status" ,
317+ macaroonFn : emptyMacaroonFn ,
318+ requestFn : statusRequestFn ,
319+ successPattern : "\" sub_servers\" :" ,
320+ allowedThroughLNC : true ,
321+ grpcWebURI : "/litrpc.Status/SubServerStatus" ,
322+ restWebURI : "/v1/status" ,
323+ noAuth : true ,
324+ litOnly : true ,
301325 }}
302326
303327 // customURIs is a map of endpoint URIs that we want to allow via a
@@ -420,6 +444,7 @@ func integratedTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
420444 runGRPCAuthTest (
421445 ttt , cfg .RPCAddr (), cfg .TLSCertPath ,
422446 endpoint .macaroonFn (cfg ),
447+ endpoint .noAuth ,
423448 endpoint .requestFn ,
424449 endpoint .successPattern ,
425450 endpointDisabled || endpoint .litOnly ,
@@ -431,6 +456,7 @@ func integratedTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
431456 runGRPCAuthTest (
432457 ttt , cfg .LitAddr (), cfg .LitTLSCertPath ,
433458 endpoint .macaroonFn (cfg ),
459+ endpoint .noAuth ,
434460 endpoint .requestFn ,
435461 endpoint .successPattern ,
436462 endpointDisabled ,
@@ -452,7 +478,8 @@ func integratedTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
452478 runUIPasswordCheck (
453479 ttt , cfg .RPCAddr (), cfg .TLSCertPath ,
454480 cfg .UIPassword , endpoint .requestFn ,
455- true , endpoint .successPattern ,
481+ endpoint .noAuth , true ,
482+ endpoint .successPattern ,
456483 endpointDisabled || endpoint .litOnly ,
457484 "Unimplemented desc = unknown service" ,
458485 )
@@ -467,6 +494,7 @@ func integratedTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
467494 runUIPasswordCheck (
468495 ttt , cfg .LitAddr (), cfg .LitTLSCertPath ,
469496 cfg .UIPassword , endpoint .requestFn ,
497+ endpoint .noAuth ,
470498 shouldFailWithoutMacaroon ,
471499 endpoint .successPattern ,
472500 endpointDisabled ,
@@ -496,6 +524,7 @@ func integratedTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
496524 endpoint .grpcWebURI ,
497525 withoutUIPassword , endpointDisabled ,
498526 "unknown gRPC web request" ,
527+ endpoint .noAuth ,
499528 )
500529 })
501530 }
@@ -519,7 +548,7 @@ func integratedTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
519548 tt .Run (endpoint .name + " lnd port" , func (ttt * testing.T ) {
520549 runGRPCAuthTest (
521550 ttt , cfg .RPCAddr (), cfg .TLSCertPath ,
522- superMacFile ,
551+ superMacFile , endpoint . noAuth ,
523552 endpoint .requestFn ,
524553 endpoint .successPattern ,
525554 endpointDisabled || endpoint .litOnly ,
@@ -530,7 +559,7 @@ func integratedTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
530559 tt .Run (endpoint .name + " lit port" , func (ttt * testing.T ) {
531560 runGRPCAuthTest (
532561 ttt , cfg .LitAddr (), cfg .LitTLSCertPath ,
533- superMacFile ,
562+ superMacFile , endpoint . noAuth ,
534563 endpoint .requestFn ,
535564 endpoint .successPattern ,
536565 endpointDisabled ,
@@ -556,6 +585,7 @@ func integratedTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
556585 endpoint .successPattern ,
557586 endpoint .restPOST ,
558587 withoutUIPassword , endpointDisabled ,
588+ endpoint .noAuth ,
559589 )
560590 })
561591 }
@@ -587,6 +617,7 @@ func integratedTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
587617 endpoint .allowedThroughLNC ,
588618 "unknown service" ,
589619 endpointDisabled ,
620+ endpoint .noAuth ,
590621 )
591622 })
592623 }
@@ -646,13 +677,20 @@ func integratedTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
646677 endpointDisabled := subServersDisabled &&
647678 endpoint .canDisable
648679
680+ expectedErr := "permission denied"
681+ if endpoint .noAuth {
682+ expectedErr = "unknown service"
683+ }
684+
649685 tt .Run (endpoint .name + " lit port" , func (ttt * testing.T ) {
650686 allowed := customURIs [endpoint .grpcWebURI ]
687+
651688 runLNCAuthTest (
652689 ttt , rawLNCConn , endpoint .requestFn ,
653690 endpoint .successPattern ,
654- allowed , "permission denied" ,
691+ allowed , expectedErr ,
655692 endpointDisabled ,
693+ endpoint .noAuth ,
656694 )
657695 })
658696 }
@@ -717,7 +755,7 @@ func runCertificateCheck(t *testing.T, node *HarnessNode) {
717755
718756// runGRPCAuthTest tests authentication of the given gRPC interface.
719757func runGRPCAuthTest (t * testing.T , hostPort , tlsCertPath , macPath string ,
720- makeRequest requestFn , successContent string , disabled bool ,
758+ noMac bool , makeRequest requestFn , successContent string , disabled bool ,
721759 disabledErr string ) {
722760
723761 ctxb := context .Background ()
@@ -728,6 +766,21 @@ func runGRPCAuthTest(t *testing.T, hostPort, tlsCertPath, macPath string,
728766 require .NoError (t , err )
729767 defer rawConn .Close ()
730768
769+ if noMac {
770+ resp , err := makeRequest (ctxt , rawConn )
771+ if disabled {
772+ require .ErrorContains (t , err , disabledErr )
773+ return
774+ }
775+ require .NoError (t , err )
776+
777+ json , err := marshalOptions .Marshal (resp )
778+ require .NoError (t , err )
779+ require .Contains (t , string (json ), successContent )
780+
781+ return
782+ }
783+
731784 // We have a connection without any macaroon. A call should fail.
732785 _ , err = makeRequest (ctxt , rawConn )
733786 if disabled {
@@ -769,9 +822,9 @@ func runGRPCAuthTest(t *testing.T, hostPort, tlsCertPath, macPath string,
769822 resp , err := makeRequest (ctxm , rawConn )
770823 if disabled {
771824 require .ErrorContains (t , err , disabledErr )
772- } else {
773- require .NoError (t , err )
825+ return
774826 }
827+ require .NoError (t , err )
775828
776829 json , err := marshalOptions .Marshal (resp )
777830 require .NoError (t , err )
@@ -780,7 +833,7 @@ func runGRPCAuthTest(t *testing.T, hostPort, tlsCertPath, macPath string,
780833
781834// runUIPasswordCheck tests UI password authentication.
782835func runUIPasswordCheck (t * testing.T , hostPort , tlsCertPath , uiPassword string ,
783- makeRequest requestFn , shouldFailWithoutMacaroon bool ,
836+ makeRequest requestFn , noAuth , shouldFailWithoutMacaroon bool ,
784837 successContent string , disabled bool , disabledErr string ) {
785838
786839 ctxb := context .Background ()
@@ -791,11 +844,23 @@ func runUIPasswordCheck(t *testing.T, hostPort, tlsCertPath, uiPassword string,
791844 require .NoError (t , err )
792845 defer rawConn .Close ()
793846
794- // Make sure that a call without any metadata results in an error.
795- _ , err = makeRequest (ctxt , rawConn )
796- if disabled {
847+ // Make sure that a call without any metadata results in an error unless
848+ // this is a call that is allowed to be un-authenticated in which case
849+ // we expect it to succeed.
850+ resp , err := makeRequest (ctxt , rawConn )
851+ switch {
852+ case disabled :
797853 require .ErrorContains (t , err , disabledErr )
798- } else {
854+ case noAuth :
855+ require .NoError (t , err )
856+
857+ json , err := marshalOptions .Marshal (resp )
858+ require .NoError (t , err )
859+ require .Contains (t , string (json ), successContent )
860+
861+ return
862+
863+ default :
799864 require .ErrorContains (t , err , "expected 1 macaroon, got 0" )
800865 }
801866
@@ -834,7 +899,7 @@ func runUIPasswordCheck(t *testing.T, hostPort, tlsCertPath, uiPassword string,
834899 // Using the correct UI password should work for all requests unless the
835900 // request is for a disabled sub-server.
836901 ctxm = uiPasswordContext (ctxt , uiPassword , false )
837- resp , err : = makeRequest (ctxm , rawConn )
902+ resp , err = makeRequest (ctxm , rawConn )
838903
839904 // On lnd's gRPC interface we don't support using the UI password.
840905 if shouldFailWithoutMacaroon {
@@ -906,7 +971,8 @@ func runIndexPageCheck(t *testing.T, hostPort string, uiDisabled bool) {
906971
907972// runGRPCWebAuthTest tests authentication of the given gRPC interface.
908973func runGRPCWebAuthTest (t * testing.T , hostPort , uiPassword , grpcWebURI string ,
909- shouldFailWithUIPassword , disabled bool , disableErr string ) {
974+ shouldFailWithUIPassword , disabled bool , disableErr string ,
975+ noAuth bool ) {
910976
911977 basicAuth := base64 .StdEncoding .EncodeToString (
912978 []byte (fmt .Sprintf ("%s:%s" , uiPassword , uiPassword )),
@@ -919,15 +985,27 @@ func runGRPCWebAuthTest(t *testing.T, hostPort, uiPassword, grpcWebURI string,
919985
920986 url := fmt .Sprintf ("https://%s%s" , hostPort , grpcWebURI )
921987
922- // First test a grpc-web call without authorization, which should fail.
923- _ , responseHeader , err := postURL (url , emptyGrpcWebRequest , header )
988+ // First test a grpc-web call without authorization, which should fail
989+ // unless this call does not require authentication.
990+ body , responseHeader , err := postURL (url , emptyGrpcWebRequest , header )
924991 require .NoError (t , err )
925992
926- if disabled {
993+ switch {
994+ case disabled :
927995 require .Contains (
928996 t , responseHeader .Get ("grpc-message" ), disableErr ,
929997 )
930- } else {
998+
999+ case noAuth :
1000+ require .Empty (t , responseHeader .Get ("grpc-message" ))
1001+ require .Empty (t , responseHeader .Get ("grpc-status" ))
1002+
1003+ // We get the status encoded as trailer in the response.
1004+ require .Contains (t , body , "grpc-status: 0" )
1005+
1006+ return
1007+
1008+ default :
9311009 require .Equal (
9321010 t , "expected 1 macaroon, got 0" ,
9331011 responseHeader .Get ("grpc-message" ),
@@ -941,7 +1019,7 @@ func runGRPCWebAuthTest(t *testing.T, hostPort, uiPassword, grpcWebURI string,
9411019
9421020 // Now add the basic auth and try again.
9431021 header ["authorization" ] = []string {fmt .Sprintf ("Basic %s" , basicAuth )}
944- body , responseHeader , err : = postURL (url , emptyGrpcWebRequest , header )
1022+ body , responseHeader , err = postURL (url , emptyGrpcWebRequest , header )
9451023 require .NoError (t , err )
9461024
9471025 if shouldFailWithUIPassword {
@@ -976,7 +1054,7 @@ func runGRPCWebAuthTest(t *testing.T, hostPort, uiPassword, grpcWebURI string,
9761054// runRESTAuthTest tests authentication of the given REST interface.
9771055func runRESTAuthTest (t * testing.T , hostPort , uiPassword , macaroonPath , restURI ,
9781056 successPattern string , usePOST , shouldFailWithUIPassword ,
979- disabled bool ) {
1057+ disabled , noMac bool ) {
9801058
9811059 basicAuth := base64 .StdEncoding .EncodeToString (
9821060 []byte (fmt .Sprintf ("%s:%s" , uiPassword , uiPassword )),
@@ -991,7 +1069,9 @@ func runRESTAuthTest(t *testing.T, hostPort, uiPassword, macaroonPath, restURI,
9911069 method = "POST"
9921070 }
9931071
994- // First test a REST call without authorization, which should fail.
1072+ // First test a REST call without authorization, which should fail
1073+ // unless this is a call for an endpoint that does not require
1074+ // authorization.
9951075 body , responseHeader , err := callURL (url , method , nil , nil , false )
9961076 require .NoError (t , err )
9971077
@@ -1000,6 +1080,11 @@ func runRESTAuthTest(t *testing.T, hostPort, uiPassword, macaroonPath, restURI,
10001080 responseHeader .Get ("content-type" ),
10011081 )
10021082
1083+ if noMac {
1084+ require .Contains (t , body , successPattern )
1085+ return
1086+ }
1087+
10031088 if disabled {
10041089 require .Empty (
10051090 t , responseHeader .Get ("grpc-metadata-content-type" ),
@@ -1029,7 +1114,6 @@ func runRESTAuthTest(t *testing.T, hostPort, uiPassword, macaroonPath, restURI,
10291114
10301115 default :
10311116 require .Contains (t , body , successPattern )
1032-
10331117 }
10341118
10351119 // And finally, try with the given macaroon.
@@ -1057,7 +1141,7 @@ func runRESTAuthTest(t *testing.T, hostPort, uiPassword, macaroonPath, restURI,
10571141// through Lightning Node Connect.
10581142func runLNCAuthTest (t * testing.T , rawLNCConn grpc.ClientConnInterface ,
10591143 makeRequest requestFn , successContent string , callAllowed bool ,
1060- expectErrContains string , disabled bool ) {
1144+ expectErrContains string , disabled , noMac bool ) {
10611145
10621146 ctxt , cancel := context .WithTimeout (
10631147 context .Background (), defaultTimeout ,
@@ -1070,6 +1154,21 @@ func runLNCAuthTest(t *testing.T, rawLNCConn grpc.ClientConnInterface,
10701154 // macaroon permissions properly set up).
10711155 resp , err := makeRequest (ctxt , rawLNCConn )
10721156
1157+ if noMac {
1158+ if disabled {
1159+ require .ErrorContains (t , err , "unknown gRPC web " +
1160+ "request" )
1161+ return
1162+ }
1163+ require .NoError (t , err )
1164+
1165+ json , err := marshalOptions .Marshal (resp )
1166+ require .NoError (t , err )
1167+ require .Contains (t , string (json ), successContent )
1168+
1169+ return
1170+ }
1171+
10731172 // Is this a disallowed call?
10741173 if ! callAllowed {
10751174 if disabled {
0 commit comments