Skip to content

Commit 8e75a04

Browse files
committed
itest: add grpc-web auth test
1 parent 3fa0d5d commit 8e75a04

File tree

1 file changed

+100
-0
lines changed

1 file changed

+100
-0
lines changed

itest/litd_mode_integrated_test.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package itest
22

33
import (
4+
"bytes"
45
"context"
56
"crypto/tls"
67
"crypto/x509"
@@ -22,6 +23,7 @@ import (
2223
"github.com/stretchr/testify/require"
2324
"golang.org/x/net/http2"
2425
"google.golang.org/grpc"
26+
"google.golang.org/grpc/codes"
2527
"google.golang.org/grpc/credentials"
2628
"google.golang.org/grpc/metadata"
2729
"google.golang.org/protobuf/encoding/protojson"
@@ -66,6 +68,10 @@ var (
6668
Timeout: 1 * time.Second,
6769
}
6870

71+
// emptyGrpcWebRequest is the binary serialized POST content of an empty
72+
// gRPC request. One byte version and then 4 bytes content length.
73+
emptyGrpcWebRequest = []byte{0, 0, 0, 0, 0}
74+
6975
lndRequestFn = func(ctx context.Context,
7076
c grpc.ClientConnInterface) (proto.Message, error) {
7177

@@ -128,6 +134,7 @@ var (
128134
supportsMacAuthOnLitPort bool
129135
supportsUIPasswordOnLndPort bool
130136
supportsUIPasswordOnLitPort bool
137+
grpcWebURI string
131138
}{{
132139
name: "lnrpc",
133140
macaroonFn: lndMacaroonFn,
@@ -137,6 +144,7 @@ var (
137144
supportsMacAuthOnLitPort: true,
138145
supportsUIPasswordOnLndPort: false,
139146
supportsUIPasswordOnLitPort: true,
147+
grpcWebURI: "/lnrpc.Lightning/GetInfo",
140148
}, {
141149
name: "frdrpc",
142150
macaroonFn: faradayMacaroonFn,
@@ -146,6 +154,7 @@ var (
146154
supportsMacAuthOnLitPort: true,
147155
supportsUIPasswordOnLndPort: false,
148156
supportsUIPasswordOnLitPort: true,
157+
grpcWebURI: "/frdrpc.FaradayServer/RevenueReport",
149158
}, {
150159
name: "looprpc",
151160
macaroonFn: loopMacaroonFn,
@@ -155,6 +164,7 @@ var (
155164
supportsMacAuthOnLitPort: true,
156165
supportsUIPasswordOnLndPort: false,
157166
supportsUIPasswordOnLitPort: true,
167+
grpcWebURI: "/looprpc.SwapClient/ListSwaps",
158168
}, {
159169
name: "poolrpc",
160170
macaroonFn: poolMacaroonFn,
@@ -164,6 +174,7 @@ var (
164174
supportsMacAuthOnLitPort: true,
165175
supportsUIPasswordOnLndPort: false,
166176
supportsUIPasswordOnLitPort: true,
177+
grpcWebURI: "/poolrpc.Trader/GetInfo",
167178
}, {
168179
name: "litrpc",
169180
macaroonFn: nil,
@@ -173,6 +184,7 @@ var (
173184
supportsMacAuthOnLitPort: false,
174185
supportsUIPasswordOnLndPort: true,
175186
supportsUIPasswordOnLitPort: true,
187+
grpcWebURI: "/litrpc.Sessions/ListSessions",
176188
}}
177189
)
178190

@@ -257,6 +269,20 @@ func testModeIntegrated(net *NetworkHarness, t *harnessTest) {
257269
t.t.Run("UI index page fallback", func(tt *testing.T) {
258270
runIndexPageCheck(tt, net.Alice.Cfg.LitAddr())
259271
})
272+
273+
t.t.Run("grpc-web auth", func(tt *testing.T) {
274+
cfg := net.Alice.Cfg
275+
276+
for _, endpoint := range endpoints {
277+
endpoint := endpoint
278+
tt.Run(endpoint.name+" lit port", func(ttt *testing.T) {
279+
runGRPCWebAuthTest(
280+
ttt, cfg.LitAddr(), cfg.UIPassword,
281+
endpoint.grpcWebURI,
282+
)
283+
})
284+
}
285+
})
260286
}
261287

262288
// runCertificateCheck checks that the TLS certificates presented to clients are
@@ -406,6 +432,44 @@ func runIndexPageCheck(t *testing.T, hostPort string) {
406432
require.Contains(t, body, indexHtmlMarker)
407433
}
408434

435+
// runGRPCWebAuthTest tests authentication of the given gRPC interface.
436+
func runGRPCWebAuthTest(t *testing.T, hostPort, uiPassword, grpcWebURI string) {
437+
basicAuth := base64.StdEncoding.EncodeToString(
438+
[]byte(fmt.Sprintf("%s:%s", uiPassword, uiPassword)),
439+
)
440+
441+
header := http.Header{
442+
"content-type": []string{"application/grpc-web+proto"},
443+
"x-grpc-web": []string{"1"},
444+
}
445+
446+
url := fmt.Sprintf("https://%s%s", hostPort, grpcWebURI)
447+
448+
// First test a grpc-web call without authorization, which should fail.
449+
_, responseHeader, err := postURL(url, emptyGrpcWebRequest, header)
450+
require.NoError(t, err)
451+
452+
require.Equal(
453+
t, "expected 1 macaroon, got 0",
454+
responseHeader.Get("grpc-message"),
455+
)
456+
require.Equal(
457+
t, fmt.Sprintf("%d", codes.Unknown),
458+
responseHeader.Get("grpc-status"),
459+
)
460+
461+
// Now add the basic auth and try again.
462+
header["authorization"] = []string{fmt.Sprintf("Basic %s", basicAuth)}
463+
body, responseHeader, err := postURL(url, emptyGrpcWebRequest, header)
464+
require.NoError(t, err)
465+
466+
require.Empty(t, responseHeader.Get("grpc-message"))
467+
require.Empty(t, responseHeader.Get("grpc-status"))
468+
469+
// We get the status encoded as trailer in the response.
470+
require.Contains(t, body, "grpc-status: 0")
471+
}
472+
409473
// getURL retrieves the body of a given URL, ignoring any TLS certificate the
410474
// server might present.
411475
func getURL(url string) (string, error) {
@@ -426,6 +490,42 @@ func getURL(url string) (string, error) {
426490
return string(body), nil
427491
}
428492

493+
// postURL retrieves the body of a given URL, ignoring any TLS certificate the
494+
// server might present.
495+
func postURL(url string, postBody []byte, header http.Header) (string,
496+
http.Header, error) {
497+
498+
req, err := http.NewRequest("POST", url, bytes.NewReader(postBody))
499+
if err != nil {
500+
return "", nil, err
501+
}
502+
for key, values := range header {
503+
for _, value := range values {
504+
req.Header.Add(key, value)
505+
}
506+
}
507+
resp, err := client.Do(req)
508+
if err != nil {
509+
return "", nil, err
510+
}
511+
512+
if resp.StatusCode != 200 {
513+
return "", nil, fmt.Errorf("request failed, got status code "+
514+
"%d (%s)", resp.StatusCode, resp.Status)
515+
}
516+
517+
defer func() {
518+
_ = resp.Body.Close()
519+
}()
520+
521+
body, err := ioutil.ReadAll(resp.Body)
522+
if err != nil {
523+
return "", nil, err
524+
}
525+
526+
return string(body), resp.Header, nil
527+
}
528+
429529
// getServerCertificates returns the TLS certificates that a server presents to
430530
// clients.
431531
func getServerCertificates(hostPort string) ([]*x509.Certificate, error) {

0 commit comments

Comments
 (0)