@@ -138,6 +138,7 @@ var (
138138 supportsUIPasswordOnLndPort bool
139139 supportsUIPasswordOnLitPort bool
140140 grpcWebURI string
141+ restWebURI string
141142 }{{
142143 name : "lnrpc" ,
143144 macaroonFn : lndMacaroonFn ,
@@ -148,6 +149,7 @@ var (
148149 supportsUIPasswordOnLndPort : false ,
149150 supportsUIPasswordOnLitPort : true ,
150151 grpcWebURI : "/lnrpc.Lightning/GetInfo" ,
152+ restWebURI : "/v1/getinfo" ,
151153 }, {
152154 name : "frdrpc" ,
153155 macaroonFn : faradayMacaroonFn ,
@@ -158,6 +160,7 @@ var (
158160 supportsUIPasswordOnLndPort : false ,
159161 supportsUIPasswordOnLitPort : true ,
160162 grpcWebURI : "/frdrpc.FaradayServer/RevenueReport" ,
163+ restWebURI : "/v1/faraday/revenue" ,
161164 }, {
162165 name : "looprpc" ,
163166 macaroonFn : loopMacaroonFn ,
@@ -168,6 +171,7 @@ var (
168171 supportsUIPasswordOnLndPort : false ,
169172 supportsUIPasswordOnLitPort : true ,
170173 grpcWebURI : "/looprpc.SwapClient/ListSwaps" ,
174+ restWebURI : "/v1/loop/swaps" ,
171175 }, {
172176 name : "poolrpc" ,
173177 macaroonFn : poolMacaroonFn ,
@@ -178,6 +182,7 @@ var (
178182 supportsUIPasswordOnLndPort : false ,
179183 supportsUIPasswordOnLitPort : true ,
180184 grpcWebURI : "/poolrpc.Trader/GetInfo" ,
185+ restWebURI : "/v1/pool/info" ,
181186 }, {
182187 name : "litrpc" ,
183188 macaroonFn : nil ,
@@ -326,6 +331,27 @@ func testModeIntegrated(net *NetworkHarness, t *harnessTest) {
326331 })
327332 }
328333 })
334+
335+ t .t .Run ("REST auth" , func (tt * testing.T ) {
336+ cfg := net .Alice .Cfg
337+
338+ for _ , endpoint := range endpoints {
339+ endpoint := endpoint
340+
341+ if endpoint .restWebURI == "" {
342+ continue
343+ }
344+
345+ tt .Run (endpoint .name + " lit port" , func (ttt * testing.T ) {
346+ runRESTAuthTest (
347+ ttt , cfg .LitAddr (), cfg .UIPassword ,
348+ endpoint .macaroonFn (cfg ),
349+ endpoint .restWebURI ,
350+ endpoint .successPattern ,
351+ )
352+ })
353+ }
354+ })
329355}
330356
331357// runCertificateCheck checks that the TLS certificates presented to clients are
@@ -513,6 +539,58 @@ func runGRPCWebAuthTest(t *testing.T, hostPort, uiPassword, grpcWebURI string) {
513539 require .Contains (t , body , "grpc-status: 0" )
514540}
515541
542+ // runRESTAuthTest tests authentication of the given REST interface.
543+ func runRESTAuthTest (t * testing.T , hostPort , uiPassword , macaroonPath , restURI ,
544+ successPattern string ) {
545+
546+ basicAuth := base64 .StdEncoding .EncodeToString (
547+ []byte (fmt .Sprintf ("%s:%s" , uiPassword , uiPassword )),
548+ )
549+ basicAuthHeader := http.Header {
550+ "authorization" : []string {fmt .Sprintf ("Basic %s" , basicAuth )},
551+ }
552+ url := fmt .Sprintf ("https://%s%s" , hostPort , restURI )
553+
554+ // First test a REST call without authorization, which should fail.
555+ body , responseHeader , err := callURL (url , "GET" , nil , nil , false )
556+ require .NoError (t , err )
557+
558+ require .Equal (
559+ t , "application/grpc" ,
560+ responseHeader .Get ("grpc-metadata-content-type" ),
561+ )
562+ require .Equal (
563+ t , "application/json" ,
564+ responseHeader .Get ("content-type" ),
565+ )
566+ require .Contains (
567+ t , body ,
568+ "expected 1 macaroon, got 0" ,
569+ )
570+
571+ // Now add the UI password which should make the request succeed.
572+ body , responseHeader , err = callURL (
573+ url , "GET" , nil , basicAuthHeader , false ,
574+ )
575+ require .NoError (t , err )
576+ require .Contains (t , body , successPattern )
577+
578+ // And finally, try with the given macaroon.
579+ macBytes , err := ioutil .ReadFile (macaroonPath )
580+ require .NoError (t , err )
581+
582+ macaroonHeader := http.Header {
583+ "grpc-metadata-macaroon" : []string {
584+ hex .EncodeToString (macBytes ),
585+ },
586+ }
587+ body , responseHeader , err = callURL (
588+ url , "GET" , nil , macaroonHeader , false ,
589+ )
590+ require .NoError (t , err )
591+ require .Contains (t , body , successPattern )
592+ }
593+
516594// getURL retrieves the body of a given URL, ignoring any TLS certificate the
517595// server might present.
518596func getURL (url string ) (string , error ) {
@@ -538,7 +616,15 @@ func getURL(url string) (string, error) {
538616func postURL (url string , postBody []byte , header http.Header ) (string ,
539617 http.Header , error ) {
540618
541- req , err := http .NewRequest ("POST" , url , bytes .NewReader (postBody ))
619+ return callURL (url , "POST" , postBody , header , true )
620+ }
621+
622+ // callURL does a HTTP call to the given URL, ignoring any TLS certificate the
623+ // server might present.
624+ func callURL (url , method string , postBody []byte , header http.Header ,
625+ expectOk bool ) (string , http.Header , error ) {
626+
627+ req , err := http .NewRequest (method , url , bytes .NewReader (postBody ))
542628 if err != nil {
543629 return "" , nil , err
544630 }
@@ -552,7 +638,7 @@ func postURL(url string, postBody []byte, header http.Header) (string,
552638 return "" , nil , err
553639 }
554640
555- if resp .StatusCode != 200 {
641+ if expectOk && resp .StatusCode != 200 {
556642 return "" , nil , fmt .Errorf ("request failed, got status code " +
557643 "%d (%s)" , resp .StatusCode , resp .Status )
558644 }
0 commit comments