@@ -28,6 +28,7 @@ import (
2828 "github.com/lightningnetwork/lnd/lnrpc"
2929 "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
3030 "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
31+ "github.com/lightningnetwork/lnd/macaroons"
3132 "github.com/stretchr/testify/require"
3233 "golang.org/x/net/http2"
3334 "google.golang.org/grpc"
@@ -224,6 +225,13 @@ var (
224225 allowedThroughLNC : false ,
225226 grpcWebURI : "/litrpc.Sessions/ListSessions" ,
226227 }}
228+
229+ // customURIs is a map of endpoint URIs that we want to allow via a
230+ // custom-macaroon session type.
231+ customURIs = map [string ]bool {
232+ "/lnrpc.Lightning/GetInfo" : true ,
233+ "/frdrpc.FaradayServer/RevenueReport" : true ,
234+ }
227235)
228236
229237// testModeIntegrated makes sure that in integrated mode all daemons work
@@ -367,20 +375,109 @@ func testModeIntegrated(net *NetworkHarness, t *harnessTest) {
367375 t .t .Run ("lnc auth" , func (tt * testing.T ) {
368376 cfg := net .Alice .Cfg
369377
378+ ctx := context .Background ()
379+ ctxt , cancel := context .WithTimeout (ctx , defaultTimeout )
380+ defer cancel ()
381+
382+ rawLNCConn := setUpLNCConn (
383+ ctxt , t .t , cfg .LitAddr (), cfg .TLSCertPath ,
384+ cfg .LitMacPath ,
385+ litrpc .SessionType_TYPE_MACAROON_READONLY , nil ,
386+ )
387+ defer rawLNCConn .Close ()
388+
370389 for _ , endpoint := range endpoints {
371390 endpoint := endpoint
372391 tt .Run (endpoint .name + " lit port" , func (ttt * testing.T ) {
373392 runLNCAuthTest (
374- ttt , cfg .LitAddr (), cfg .TLSCertPath ,
375- cfg .LitMacPath , endpoint .requestFn ,
393+ ttt , rawLNCConn , endpoint .requestFn ,
376394 endpoint .successPattern ,
377395 endpoint .allowedThroughLNC ,
396+ "unknown service" ,
397+ )
398+ })
399+ }
400+ })
401+
402+ t .t .Run ("lnc auth custom mac perms" , func (tt * testing.T ) {
403+ cfg := net .Alice .Cfg
404+
405+ ctx := context .Background ()
406+ ctxt , cancel := context .WithTimeout (ctx , defaultTimeout )
407+ defer cancel ()
408+
409+ customPerms := make (
410+ []* litrpc.MacaroonPermission , 0 , len (customURIs ),
411+ )
412+
413+ customURIKeyword := macaroons .PermissionEntityCustomURI
414+ for uri := range customURIs {
415+ customPerms = append (
416+ customPerms , & litrpc.MacaroonPermission {
417+ Entity : customURIKeyword ,
418+ Action : uri ,
419+ },
420+ )
421+ }
422+
423+ rawLNCConn := setUpLNCConn (
424+ ctxt , t .t , cfg .LitAddr (), cfg .TLSCertPath ,
425+ cfg .LitMacPath ,
426+ litrpc .SessionType_TYPE_MACAROON_CUSTOM , customPerms ,
427+ )
428+ defer rawLNCConn .Close ()
429+
430+ for _ , endpoint := range endpoints {
431+ endpoint := endpoint
432+ tt .Run (endpoint .name + " lit port" , func (ttt * testing.T ) {
433+ allowed := customURIs [endpoint .grpcWebURI ]
434+ runLNCAuthTest (
435+ ttt , rawLNCConn , endpoint .requestFn ,
436+ endpoint .successPattern ,
437+ allowed , "permission denied" ,
378438 )
379439 })
380440 }
381441 })
382442}
383443
444+ // setUpLNCConn creates a new LNC session and then creates a connection to that
445+ // session via the mailbox that the session was created with.
446+ func setUpLNCConn (ctx context.Context , t * testing.T , hostPort , tlsCertPath ,
447+ macPath string , sessType litrpc.SessionType ,
448+ customMacPerms []* litrpc.MacaroonPermission ) * grpc.ClientConn {
449+
450+ rawConn , err := connectRPC (ctx , hostPort , tlsCertPath )
451+ require .NoError (t , err )
452+
453+ macBytes , err := ioutil .ReadFile (macPath )
454+ require .NoError (t , err )
455+ ctxm := macaroonContext (ctx , macBytes )
456+
457+ // We first need to create an LNC session that we can use to connect.
458+ litClient := litrpc .NewSessionsClient (rawConn )
459+ sessResp , err := litClient .AddSession (ctxm , & litrpc.AddSessionRequest {
460+ Label : "integration-test" ,
461+ SessionType : sessType ,
462+ ExpiryTimestampSeconds : uint64 (
463+ time .Now ().Add (5 * time .Minute ).Unix (),
464+ ),
465+ MailboxServerAddr : mailboxServerAddr ,
466+ MacaroonCustomPermissions : customMacPerms ,
467+ })
468+ require .NoError (t , err )
469+
470+ // Try the LNC connection now.
471+ connectPhrase := strings .Split (
472+ sessResp .Session .PairingSecretMnemonic , " " ,
473+ )
474+
475+ rawLNCConn , err := connectMailbox (ctx , connectPhrase )
476+ require .NoError (t , err )
477+
478+ return rawLNCConn
479+ }
480+
384481// runCertificateCheck checks that the TLS certificates presented to clients are
385482// what we expect them to be.
386483func runCertificateCheck (t * testing.T , node * HarnessNode ) {
@@ -624,44 +721,15 @@ func runRESTAuthTest(t *testing.T, hostPort, uiPassword, macaroonPath, restURI,
624721
625722// runLNCAuthTest tests authentication of the given interface when connecting
626723// through Lightning Node Connect.
627- func runLNCAuthTest (t * testing.T , hostPort , tlsCertPath , macPath string ,
628- makeRequest requestFn , successContent string , callAllowed bool ) {
629-
630- ctxb := context .Background ()
631- ctxt , cancel := context .WithTimeout (ctxb , defaultTimeout )
632- defer cancel ()
633-
634- rawConn , err := connectRPC (ctxt , hostPort , tlsCertPath )
635- require .NoError (t , err )
724+ func runLNCAuthTest (t * testing.T , rawLNCConn grpc.ClientConnInterface ,
725+ makeRequest requestFn , successContent string , callAllowed bool ,
726+ expectErrContains string ) {
636727
637- macBytes , err := ioutil .ReadFile (macPath )
638- require .NoError (t , err )
639- ctxm := macaroonContext (ctxt , macBytes )
640-
641- // We first need to create an LNC session that we can use to connect.
642- // We use the UI password to create the session.
643- litClient := litrpc .NewSessionsClient (rawConn )
644- sessResp , err := litClient .AddSession (ctxm , & litrpc.AddSessionRequest {
645- Label : "integration-test" ,
646- SessionType : litrpc .SessionType_TYPE_MACAROON_READONLY ,
647- ExpiryTimestampSeconds : uint64 (
648- time .Now ().Add (5 * time .Minute ).Unix (),
649- ),
650- MailboxServerAddr : mailboxServerAddr ,
651- })
652- require .NoError (t , err )
653-
654- // Try the LNC connection now.
655- connectPhrase := strings .Split (
656- sessResp .Session .PairingSecretMnemonic , " " ,
728+ ctxt , cancel := context .WithTimeout (
729+ context .Background (), defaultTimeout ,
657730 )
658-
659- ctxt , cancel = context .WithTimeout (ctxb , defaultTimeout )
660731 defer cancel ()
661732
662- rawLNCConn , err := connectMailbox (ctxt , connectPhrase )
663- require .NoError (t , err )
664-
665733 // We should be able to make a request via LNC to the given RPC
666734 // endpoint, unless it is explicitly disallowed (we currently don't want
667735 // to support creating more sessions through LNC until we have all
@@ -671,7 +739,7 @@ func runLNCAuthTest(t *testing.T, hostPort, tlsCertPath, macPath string,
671739 // Is this a disallowed call?
672740 if ! callAllowed {
673741 require .Error (t , err )
674- require .Contains (t , err .Error (), "unknown service" )
742+ require .Contains (t , err .Error (), expectErrContains )
675743
676744 return
677745 }
@@ -767,7 +835,7 @@ func getServerCertificates(hostPort string) ([]*x509.Certificate, error) {
767835// connectMailbox tries to establish a connection through LNC using the given
768836// connect phrase and the test mailbox server.
769837func connectMailbox (ctx context.Context ,
770- connectPhrase []string ) (grpc.ClientConnInterface , error ) {
838+ connectPhrase []string ) (* grpc.ClientConn , error ) {
771839
772840 var mnemonicWords [mailbox .NumPassphraseWords ]string
773841 copy (mnemonicWords [:], connectPhrase )
0 commit comments