diff --git a/lntest/itest/lnd_macaroons_test.go b/lntest/itest/lnd_macaroons_test.go index 8a28329eb..3d87a0743 100644 --- a/lntest/itest/lnd_macaroons_test.go +++ b/lntest/itest/lnd_macaroons_test.go @@ -197,6 +197,84 @@ func testMacaroonAuthentication(net *lntest.NetworkHarness, ht *harnessTest) { require.Error(t, err) require.Contains(t, err.Error(), "permission denied") }, + }, { + // Eighth test: check that with the CheckMacaroonPermissions + // RPC, we can check that a macaroon follows (or doesn't) + // permissions and constraints. + name: "unknown permissions", + run: func(ctxt context.Context, t *testing.T) { + // A test macaroon created with permissions from pool, + // to make sure CheckMacaroonPermissions RPC accepts + // them. + rootKeyID := uint64(4200) + req := &lnrpc.BakeMacaroonRequest{ + RootKeyId: rootKeyID, + Permissions: []*lnrpc.MacaroonPermission{{ + Entity: "account", + Action: "read", + }, { + Entity: "recommendation", + Action: "read", + }}, + AllowExternalPermissions: true, + } + bakeResp, err := testNode.BakeMacaroon(ctxt, req) + require.NoError(t, err) + + macBytes, err := hex.DecodeString(bakeResp.Macaroon) + require.NoError(t, err) + + checkReq := &lnrpc.CheckMacPermRequest{ + Macaroon: macBytes, + Permissions: req.Permissions, + } + + // Test that CheckMacaroonPermissions accurately + // characterizes macaroon as valid, even if the + // permissions are not native to LND. + checkResp, err := testNode.CheckMacaroonPermissions( + ctxt, checkReq, + ) + require.NoError(t, err) + require.Equal(t, checkResp.Valid, true) + + mac, err := readMacaroonFromHex(bakeResp.Macaroon) + require.NoError(t, err) + + // Test that CheckMacaroonPermissions responds that the + // macaroon is invalid if timed out. + timeoutMac, err := macaroons.AddConstraints( + mac, macaroons.TimeoutConstraint(-30), + ) + require.NoError(t, err) + + timeoutMacBytes, err := timeoutMac.MarshalBinary() + require.NoError(t, err) + + checkReq.Macaroon = timeoutMacBytes + + _, err = testNode.CheckMacaroonPermissions( + ctxt, checkReq, + ) + require.Error(t, err) + require.Contains(t, err.Error(), "macaroon has expired") + + // Test that CheckMacaroonPermissions labels macaroon + // input with wrong permissions as invalid. + wrongPermissions := []*lnrpc.MacaroonPermission{{ + Entity: "invoice", + Action: "read", + }} + + checkReq.Permissions = wrongPermissions + checkReq.Macaroon = macBytes + + _, err = testNode.CheckMacaroonPermissions( + ctxt, checkReq, + ) + require.Error(t, err) + require.Contains(t, err.Error(), "permission denied") + }, }} for _, tc := range testCases {