firewall: extract SessionID from gRPC metadata

In this commit, we update our various firewall interceptors so that they
rely on the session ID passed via gRPC metadata to extract a session ID.
For the PrivacyMapper and RuleEnforcer, these _MUST_ always contain a
session ID and so we error out if one was not found. For the request
logger, the session ID is optional and so we pass it to the new
SessionID field in the AddActionReq - our bbolt actions DB will not make
use of this field on persistence (but our incoming SQL version will).
This commit is contained in:
Elle Mouton 2025-05-13 08:53:03 +02:00
parent 87bef069e3
commit a89b3502e4
No known key found for this signature in database
GPG key ID: D7D916376026F177
5 changed files with 36 additions and 4 deletions

View file

@ -106,9 +106,11 @@ func (p *PrivacyMapper) Intercept(ctx context.Context,
"interception request: %v", err)
}
sessionID, err := session.IDFromMacaroon(ri.Macaroon)
sessionID, err := ri.SessionID.UnwrapOrErr(
fmt.Errorf("no session ID found in request info"),
)
if err != nil {
return nil, fmt.Errorf("could not extract ID from macaroon")
return nil, err
}
log.Tracef("PrivacyMapper: Intercepting %v", ri)

View file

@ -13,6 +13,7 @@ import (
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/rpcperms"
"github.com/stretchr/testify/require"
"google.golang.org/grpc/metadata"
"google.golang.org/protobuf/proto"
"gopkg.in/macaroon-bakery.v2/bakery"
"gopkg.in/macaroon.v2"
@ -907,6 +908,9 @@ func TestPrivacyMapper(t *testing.T) {
rawMsg, err := proto.Marshal(test.msg)
require.NoError(t, err)
md := make(metadata.MD)
session.AddToGRPCMetadata(md, sessionID)
interceptReq := &rpcperms.InterceptionRequest{
Type: test.msgType,
Macaroon: mac,
@ -916,6 +920,7 @@ func TestPrivacyMapper(t *testing.T) {
ProtoTypeName: string(
proto.MessageName(test.msg),
),
CtxMetadataPairs: md,
}
mwReq, err := interceptReq.ToRPC(1, 2)
@ -1006,6 +1011,9 @@ func TestPrivacyMapper(t *testing.T) {
amounts := make([]uint64, numSamples)
timestamps := make([]uint64, numSamples)
md := make(metadata.MD)
session.AddToGRPCMetadata(md, sessionID)
for i := 0; i < numSamples; i++ {
interceptReq := &rpcperms.InterceptionRequest{
Type: rpcperms.TypeResponse,
@ -1016,6 +1024,7 @@ func TestPrivacyMapper(t *testing.T) {
ProtoTypeName: string(
proto.MessageName(msg),
),
CtxMetadataPairs: md,
}
mwReq, err := interceptReq.ToRPC(1, 2)

View file

@ -4,7 +4,10 @@ import (
"fmt"
"strings"
"github.com/lightninglabs/lightning-terminal/session"
"github.com/lightningnetwork/lnd/fn"
"github.com/lightningnetwork/lnd/lnrpc"
"google.golang.org/grpc/metadata"
"gopkg.in/macaroon.v2"
)
@ -25,6 +28,7 @@ const (
// RequestInfo stores the parsed representation of an incoming RPC middleware
// request.
type RequestInfo struct {
SessionID fn.Option[session.ID]
MsgID uint64
RequestID uint64
MWRequestType string
@ -76,8 +80,22 @@ func NewInfoFromRequest(req *lnrpc.RPCMiddlewareRequest) (*RequestInfo, error) {
return nil, fmt.Errorf("invalid request type: %T", t)
}
md := make(metadata.MD)
for k, vs := range req.MetadataPairs {
for _, v := range vs.Values {
md.Append(k, v)
}
}
sessionID, err := session.FromGRPCMetadata(md)
if err != nil {
return nil, fmt.Errorf("error extracting session ID "+
"from request: %v", err)
}
ri.MsgID = req.MsgId
ri.RequestID = req.RequestId
ri.SessionID = sessionID
// If there is no macaroon in the request, then there is nothing left
// to parse.

View file

@ -194,6 +194,7 @@ func (r *RequestLogger) addNewAction(ctx context.Context, ri *RequestInfo,
}
actionReq := &firewalldb.AddActionReq{
SessionID: ri.SessionID,
MacaroonIdentifier: macaroonID,
RPCMethod: ri.URI,
}

View file

@ -237,9 +237,11 @@ func (r *RuleEnforcer) Intercept(ctx context.Context,
func (r *RuleEnforcer) handleRequest(ctx context.Context,
ri *RequestInfo) (proto.Message, error) {
sessionID, err := session.IDFromMacaroon(ri.Macaroon)
sessionID, err := ri.SessionID.UnwrapOrErr(
fmt.Errorf("no session ID found in request info"),
)
if err != nil {
return nil, fmt.Errorf("could not extract ID from macaroon")
return nil, err
}
rules, err := r.collectEnforcers(ctx, ri, sessionID)