Skip to content

Commit 8dab4e4

Browse files
committed
multi: allow LND whitelisted calls
This commit ensures that we dont check for a macaroon for an LND call that has been whitelisted.
1 parent 44b76a4 commit 8dab4e4

File tree

4 files changed

+130
-27
lines changed

4 files changed

+130
-27
lines changed

itest/litd_mode_integrated_test.go

Lines changed: 108 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
711739
func 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.
774817
func 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.
900953
func 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.
9691034
func 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.
10501121
func 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 {

itest/litd_mode_remote_test.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ func remoteTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
6363
runGRPCAuthTest(
6464
ttt, cfg.LitAddr(), cfg.LitTLSCertPath,
6565
endpoint.macaroonFn(cfg),
66+
endpoint.noAuth,
6667
endpoint.requestFn,
6768
endpoint.successPattern,
6869
endpointEnabled,
@@ -90,6 +91,7 @@ func remoteTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
9091
runUIPasswordCheck(
9192
ttt, cfg.LitAddr(), cfg.LitTLSCertPath,
9293
cfg.UIPassword, endpoint.requestFn,
94+
endpoint.noAuth,
9395
shouldFailWithoutMacaroon,
9496
endpoint.successPattern,
9597
endpointEnabled,
@@ -118,7 +120,7 @@ func remoteTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
118120
endpoint.grpcWebURI, withoutUIPassword,
119121
endpointEnabled,
120122
"unknown permissions required for "+
121-
"method",
123+
"method", endpoint.noAuth,
122124
)
123125
})
124126
}
@@ -142,7 +144,7 @@ func remoteTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
142144
tt.Run(endpoint.name+" lit port", func(ttt *testing.T) {
143145
runGRPCAuthTest(
144146
ttt, cfg.LitAddr(), cfg.LitTLSCertPath,
145-
superMacFile,
147+
superMacFile, endpoint.noAuth,
146148
endpoint.requestFn,
147149
endpoint.successPattern,
148150
endpointEnabled,
@@ -168,7 +170,7 @@ func remoteTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
168170
endpoint.restWebURI,
169171
endpoint.successPattern,
170172
endpoint.restPOST, withoutUIPassword,
171-
endpointDisabled,
173+
endpointDisabled, endpoint.noAuth,
172174
)
173175
})
174176
}
@@ -199,7 +201,7 @@ func remoteTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
199201
endpoint.successPattern,
200202
endpoint.allowedThroughLNC,
201203
"unknown service",
202-
endpointDisabled,
204+
endpointDisabled, endpoint.noAuth,
203205
)
204206
})
205207
}
@@ -244,7 +246,7 @@ func remoteTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
244246
ttt, rawLNCConn, endpoint.requestFn,
245247
endpoint.successPattern,
246248
allowed, "permission denied",
247-
endpointDisabled,
249+
endpointDisabled, endpoint.noAuth,
248250
)
249251
})
250252
}

0 commit comments

Comments
 (0)