Skip to content

Commit 17b0a7a

Browse files
committed
itest: add UI password auth test
1 parent 2ada1f1 commit 17b0a7a

File tree

1 file changed

+180
-20
lines changed

1 file changed

+180
-20
lines changed

itest/litd_mode_integrated_test.go

Lines changed: 180 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@ import (
44
"context"
55
"crypto/tls"
66
"crypto/x509"
7+
"encoding/base64"
78
"encoding/hex"
89
"fmt"
910
"io/ioutil"
11+
"strings"
1012
"testing"
1113

1214
"github.com/btcsuite/btcutil"
1315
"github.com/lightninglabs/faraday/frdrpc"
16+
"github.com/lightninglabs/lightning-terminal/litrpc"
1417
"github.com/lightninglabs/loop/looprpc"
1518
"github.com/lightninglabs/pool/poolrpc"
1619
"github.com/lightningnetwork/lnd/lnrpc"
@@ -94,32 +97,69 @@ var (
9497
poolMacaroonFn = func(cfg *LitNodeConfig) string {
9598
return cfg.PoolMacPath
9699
}
100+
litRequestFn = func(ctx context.Context,
101+
c grpc.ClientConnInterface) (proto.Message, error) {
102+
103+
litConn := litrpc.NewSessionsClient(c)
104+
return litConn.ListSessions(
105+
ctx, &litrpc.ListSessionsRequest{},
106+
)
107+
}
97108

98109
endpoints = []struct {
99-
name string
100-
macaroonFn macaroonFn
101-
requestFn requestFn
102-
successPattern string
110+
name string
111+
macaroonFn macaroonFn
112+
requestFn requestFn
113+
successPattern string
114+
supportsMacAuthOnLndPort bool
115+
supportsMacAuthOnLitPort bool
116+
supportsUIPasswordOnLndPort bool
117+
supportsUIPasswordOnLitPort bool
103118
}{{
104-
name: "lnrpc",
105-
macaroonFn: lndMacaroonFn,
106-
requestFn: lndRequestFn,
107-
successPattern: "\"identity_pubkey\":\"0",
119+
name: "lnrpc",
120+
macaroonFn: lndMacaroonFn,
121+
requestFn: lndRequestFn,
122+
successPattern: "\"identity_pubkey\":\"0",
123+
supportsMacAuthOnLndPort: true,
124+
supportsMacAuthOnLitPort: true,
125+
supportsUIPasswordOnLndPort: false,
126+
supportsUIPasswordOnLitPort: true,
127+
}, {
128+
name: "frdrpc",
129+
macaroonFn: faradayMacaroonFn,
130+
requestFn: faradayRequestFn,
131+
successPattern: "\"reports\":[]",
132+
supportsMacAuthOnLndPort: true,
133+
supportsMacAuthOnLitPort: true,
134+
supportsUIPasswordOnLndPort: false,
135+
supportsUIPasswordOnLitPort: true,
108136
}, {
109-
name: "frdrpc",
110-
macaroonFn: faradayMacaroonFn,
111-
requestFn: faradayRequestFn,
112-
successPattern: "\"reports\":[]",
137+
name: "looprpc",
138+
macaroonFn: loopMacaroonFn,
139+
requestFn: loopRequestFn,
140+
successPattern: "\"swaps\":[]",
141+
supportsMacAuthOnLndPort: true,
142+
supportsMacAuthOnLitPort: true,
143+
supportsUIPasswordOnLndPort: false,
144+
supportsUIPasswordOnLitPort: true,
113145
}, {
114-
name: "looprpc",
115-
macaroonFn: loopMacaroonFn,
116-
requestFn: loopRequestFn,
117-
successPattern: "\"swaps\":[]",
146+
name: "poolrpc",
147+
macaroonFn: poolMacaroonFn,
148+
requestFn: poolRequestFn,
149+
successPattern: "\"accounts_active\":0",
150+
supportsMacAuthOnLndPort: true,
151+
supportsMacAuthOnLitPort: true,
152+
supportsUIPasswordOnLndPort: false,
153+
supportsUIPasswordOnLitPort: true,
118154
}, {
119-
name: "poolrpc",
120-
macaroonFn: poolMacaroonFn,
121-
requestFn: poolRequestFn,
122-
successPattern: "\"accounts_active\":0",
155+
name: "litrpc",
156+
macaroonFn: nil,
157+
requestFn: litRequestFn,
158+
successPattern: "\"sessions\":[]",
159+
supportsMacAuthOnLndPort: false,
160+
supportsMacAuthOnLitPort: false,
161+
supportsUIPasswordOnLndPort: true,
162+
supportsUIPasswordOnLitPort: true,
123163
}}
124164
)
125165

@@ -147,6 +187,10 @@ func testModeIntegrated(net *NetworkHarness, t *harnessTest) {
147187
for _, endpoint := range endpoints {
148188
endpoint := endpoint
149189
tt.Run(endpoint.name+" lnd port", func(ttt *testing.T) {
190+
if !endpoint.supportsMacAuthOnLndPort {
191+
return
192+
}
193+
150194
runGRPCAuthTest(
151195
ttt, cfg.RPCAddr(), cfg.TLSCertPath,
152196
endpoint.macaroonFn(cfg),
@@ -156,6 +200,10 @@ func testModeIntegrated(net *NetworkHarness, t *harnessTest) {
156200
})
157201

158202
tt.Run(endpoint.name+" lit port", func(ttt *testing.T) {
203+
if !endpoint.supportsMacAuthOnLitPort {
204+
return
205+
}
206+
159207
runGRPCAuthTest(
160208
ttt, cfg.LitAddr(), cfg.TLSCertPath,
161209
endpoint.macaroonFn(cfg),
@@ -165,6 +213,33 @@ func testModeIntegrated(net *NetworkHarness, t *harnessTest) {
165213
})
166214
}
167215
})
216+
217+
t.t.Run("UI password auth check", func(tt *testing.T) {
218+
cfg := net.Alice.Cfg
219+
220+
for _, endpoint := range endpoints {
221+
endpoint := endpoint
222+
tt.Run(endpoint.name+" lnd port", func(ttt *testing.T) {
223+
runUIPasswordCheck(
224+
ttt, cfg.RPCAddr(), cfg.TLSCertPath,
225+
cfg.UIPassword,
226+
endpoint.requestFn, true,
227+
!endpoint.supportsUIPasswordOnLndPort,
228+
endpoint.successPattern,
229+
)
230+
})
231+
232+
tt.Run(endpoint.name+" lit port", func(ttt *testing.T) {
233+
runUIPasswordCheck(
234+
ttt, cfg.LitAddr(), cfg.TLSCertPath,
235+
cfg.UIPassword,
236+
endpoint.requestFn, false,
237+
!endpoint.supportsUIPasswordOnLitPort,
238+
endpoint.successPattern,
239+
)
240+
})
241+
}
242+
})
168243
}
169244

170245
// runCertificateCheck checks that the TLS certificates presented to clients are
@@ -232,6 +307,74 @@ func runGRPCAuthTest(t *testing.T, hostPort, tlsCertPath, macPath string,
232307
require.Contains(t, string(json), successContent)
233308
}
234309

310+
// runUIPasswordCheck tests UI password authentication.
311+
func runUIPasswordCheck(t *testing.T, hostPort, tlsCertPath, uiPassword string,
312+
makeRequest requestFn, shouldFailWithoutMacaroon,
313+
shouldFailWithDummyMacaroon bool, successContent string) {
314+
315+
ctxb := context.Background()
316+
ctxt, cancel := context.WithTimeout(ctxb, defaultTimeout)
317+
defer cancel()
318+
319+
rawConn, err := connectRPC(ctxt, hostPort, tlsCertPath)
320+
require.NoError(t, err)
321+
322+
// Make sure that a call without any metadata results in an error.
323+
_, err = makeRequest(ctxt, rawConn)
324+
require.Error(t, err)
325+
require.Contains(t, err.Error(), "expected 1 macaroon, got 0")
326+
327+
// We can do the same calls by providing a UI password. Make sure that
328+
// sending an incorrect one is ignored.
329+
ctxm := uiPasswordContext(ctxt, "foobar", false)
330+
_, err = makeRequest(ctxm, rawConn)
331+
require.Error(t, err)
332+
require.Contains(t, err.Error(), "expected 1 macaroon, got 0")
333+
334+
// Sending a dummy macaroon along with the incorrect UI password also
335+
// shouldn't be allowed and result in an error.
336+
ctxm = uiPasswordContext(ctxt, "foobar", true)
337+
_, err = makeRequest(ctxm, rawConn)
338+
require.Error(t, err)
339+
errStr := err.Error()
340+
err1 := strings.Contains(errStr, "invalid auth: invalid basic auth")
341+
err2 := strings.Contains(errStr, "cannot get macaroon: root key with")
342+
require.True(t, err1 || err2, "wrong UI password and dummy mac")
343+
344+
// Using the correct UI password should work for all requests.
345+
ctxm = uiPasswordContext(ctxt, uiPassword, false)
346+
resp, err := makeRequest(ctxm, rawConn)
347+
348+
// On lnd's gRPC interface we don't support using the UI password.
349+
if shouldFailWithoutMacaroon {
350+
require.Error(t, err)
351+
require.Contains(t, err.Error(), "expected 1 macaroon, got 0")
352+
353+
// Sending a dummy macaroon will allow us to not get an error in
354+
// case of the litrpc calls, where we don't support macaroons
355+
// but have the extraction call in the validator anyway. So we
356+
// provide a dummy macaroon but still the UI password must be
357+
// correct to pass.
358+
ctxm = uiPasswordContext(ctxt, uiPassword, true)
359+
resp, err = makeRequest(ctxm, rawConn)
360+
361+
if shouldFailWithDummyMacaroon {
362+
require.Error(t, err)
363+
require.Contains(
364+
t, err.Error(), "cannot get macaroon: root",
365+
)
366+
return
367+
}
368+
}
369+
370+
// We expect the call to succeed.
371+
require.NoError(t, err)
372+
373+
json, err := marshalOptions.Marshal(resp)
374+
require.NoError(t, err)
375+
require.Contains(t, string(json), successContent)
376+
}
377+
235378
// getServerCertificates returns the TLS certificates that a server presents to
236379
// clients.
237380
func getServerCertificates(hostPort string) ([]*x509.Certificate, error) {
@@ -256,6 +399,23 @@ func macaroonContext(ctx context.Context, macBytes []byte) context.Context {
256399
return metadata.NewOutgoingContext(ctx, md)
257400
}
258401

402+
func uiPasswordContext(ctx context.Context, password string,
403+
withDummyMac bool) context.Context {
404+
405+
basicAuth := base64.StdEncoding.EncodeToString(
406+
[]byte(fmt.Sprintf("%s:%s", password, password)),
407+
)
408+
409+
md := metadata.MD{}
410+
md["authorization"] = []string{fmt.Sprintf("Basic %s", basicAuth)}
411+
412+
if withDummyMac {
413+
md["macaroon"] = []string{hex.EncodeToString(dummyMacBytes)}
414+
}
415+
416+
return metadata.NewOutgoingContext(ctx, md)
417+
}
418+
259419
func makeMac() *macaroon.Macaroon {
260420
dummyMac, err := macaroon.New(
261421
[]byte("aabbccddeeff00112233445566778899"), []byte("AA=="),

0 commit comments

Comments
 (0)