mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-13 11:09:23 +01:00
macaroons+rpcserver: Add new RPC call for checking macaroon permissions
This commit is contained in:
parent
1ea6db1f26
commit
d10a682fa9
9 changed files with 1000 additions and 571 deletions
File diff suppressed because it is too large
Load diff
|
@ -2217,6 +2217,40 @@ func local_request_Lightning_ListPermissions_0(ctx context.Context, marshaler ru
|
|||
|
||||
}
|
||||
|
||||
func request_Lightning_CheckMacaroonPermissions_0(ctx context.Context, marshaler runtime.Marshaler, client LightningClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq CheckMacPermRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||
if berr != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||
}
|
||||
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.CheckMacaroonPermissions(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Lightning_CheckMacaroonPermissions_0(ctx context.Context, marshaler runtime.Marshaler, server LightningServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq CheckMacPermRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||
if berr != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||
}
|
||||
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.CheckMacaroonPermissions(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
// RegisterLightningHandlerServer registers the http handlers for service Lightning to "mux".
|
||||
// UnaryRPC :call LightningServer directly.
|
||||
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
|
||||
|
@ -3443,6 +3477,29 @@ func RegisterLightningHandlerServer(ctx context.Context, mux *runtime.ServeMux,
|
|||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Lightning_CheckMacaroonPermissions_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/lnrpc.Lightning/CheckMacaroonPermissions", runtime.WithHTTPPathPattern("/v1/macaroon/checkpermissions"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Lightning_CheckMacaroonPermissions_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Lightning_CheckMacaroonPermissions_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -4684,6 +4741,26 @@ func RegisterLightningHandlerClient(ctx context.Context, mux *runtime.ServeMux,
|
|||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Lightning_CheckMacaroonPermissions_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req, "/lnrpc.Lightning/CheckMacaroonPermissions", runtime.WithHTTPPathPattern("/v1/macaroon/checkpermissions"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Lightning_CheckMacaroonPermissions_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Lightning_CheckMacaroonPermissions_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -4807,6 +4884,8 @@ var (
|
|||
pattern_Lightning_DeleteMacaroonID_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "macaroon", "root_key_id"}, ""))
|
||||
|
||||
pattern_Lightning_ListPermissions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "macaroon", "permissions"}, ""))
|
||||
|
||||
pattern_Lightning_CheckMacaroonPermissions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "macaroon", "checkpermissions"}, ""))
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -4929,4 +5008,6 @@ var (
|
|||
forward_Lightning_DeleteMacaroonID_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Lightning_ListPermissions_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Lightning_CheckMacaroonPermissions_0 = runtime.ForwardResponseMessage
|
||||
)
|
||||
|
|
|
@ -1608,4 +1608,29 @@ func RegisterLightningJSONCallbacks(registry map[string]func(ctx context.Context
|
|||
}
|
||||
callback(string(respBytes), nil)
|
||||
}
|
||||
|
||||
registry["lnrpc.Lightning.CheckMacaroonPermissions"] = func(ctx context.Context,
|
||||
conn *grpc.ClientConn, reqJSON string, callback func(string, error)) {
|
||||
|
||||
req := &CheckMacPermRequest{}
|
||||
err := marshaler.Unmarshal([]byte(reqJSON), req)
|
||||
if err != nil {
|
||||
callback("", err)
|
||||
return
|
||||
}
|
||||
|
||||
client := NewLightningClient(conn)
|
||||
resp, err := client.CheckMacaroonPermissions(ctx, req)
|
||||
if err != nil {
|
||||
callback("", err)
|
||||
return
|
||||
}
|
||||
|
||||
respBytes, err := marshaler.Marshal(resp)
|
||||
if err != nil {
|
||||
callback("", err)
|
||||
return
|
||||
}
|
||||
callback(string(respBytes), nil)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -532,6 +532,14 @@ service Lightning {
|
|||
*/
|
||||
rpc ListPermissions (ListPermissionsRequest)
|
||||
returns (ListPermissionsResponse);
|
||||
|
||||
/*
|
||||
CheckMacaroonPermissions checks whether a request follows the constraints
|
||||
imposed on the macaroon and that the macaroon is authorized to follow the
|
||||
provided permissions.
|
||||
*/
|
||||
rpc CheckMacaroonPermissions (CheckMacPermRequest)
|
||||
returns (CheckMacPermResponse);
|
||||
}
|
||||
|
||||
message Utxo {
|
||||
|
@ -4006,3 +4014,13 @@ message Op {
|
|||
string entity = 1;
|
||||
repeated string actions = 2;
|
||||
}
|
||||
|
||||
message CheckMacPermRequest {
|
||||
bytes macaroon = 1;
|
||||
repeated MacaroonPermission permissions = 2;
|
||||
string fullMethod = 3;
|
||||
}
|
||||
|
||||
message CheckMacPermResponse {
|
||||
bool valid = 1;
|
||||
}
|
||||
|
|
|
@ -1563,6 +1563,39 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"/v1/macaroon/checkpermissions": {
|
||||
"post": {
|
||||
"summary": "CheckMacaroonPermissions checks whether a request follows the constraints\nimposed on the macaroon and that the macaroon is authorized to follow the\nprovided permissions.",
|
||||
"operationId": "Lightning_CheckMacaroonPermissions",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/lnrpcCheckMacPermResponse"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/rpcStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/lnrpcCheckMacPermRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"Lightning"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v1/macaroon/ids": {
|
||||
"get": {
|
||||
"summary": "lncli: `listmacaroonids`\nListMacaroonIDs returns all root key IDs that are in use.",
|
||||
|
@ -3622,6 +3655,32 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"lnrpcCheckMacPermRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"macaroon": {
|
||||
"type": "string",
|
||||
"format": "byte"
|
||||
},
|
||||
"permissions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/lnrpcMacaroonPermission"
|
||||
}
|
||||
},
|
||||
"fullMethod": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lnrpcCheckMacPermResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"valid": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lnrpcCloseStatusUpdate": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
@ -150,3 +150,7 @@ http:
|
|||
delete: "/v1/macaroon/{root_key_id}"
|
||||
- selector: lnrpc.Lightning.ListPermissions
|
||||
get: "/v1/macaroon/permissions"
|
||||
- selector: lnrpc.Lightning.CheckMacaroonPermissions
|
||||
post: "/v1/macaroon/checkpermissions"
|
||||
body: "*"
|
||||
|
||||
|
|
|
@ -384,6 +384,11 @@ type LightningClient interface {
|
|||
//ListPermissions lists all RPC method URIs and their required macaroon
|
||||
//permissions to access them.
|
||||
ListPermissions(ctx context.Context, in *ListPermissionsRequest, opts ...grpc.CallOption) (*ListPermissionsResponse, error)
|
||||
//
|
||||
//CheckMacaroonPermissions checks whether a request follows the constraints
|
||||
//imposed on the macaroon and that the macaroon is authorized to follow the
|
||||
//provided permissions.
|
||||
CheckMacaroonPermissions(ctx context.Context, in *CheckMacPermRequest, opts ...grpc.CallOption) (*CheckMacPermResponse, error)
|
||||
}
|
||||
|
||||
type lightningClient struct {
|
||||
|
@ -1195,6 +1200,15 @@ func (c *lightningClient) ListPermissions(ctx context.Context, in *ListPermissio
|
|||
return out, nil
|
||||
}
|
||||
|
||||
func (c *lightningClient) CheckMacaroonPermissions(ctx context.Context, in *CheckMacPermRequest, opts ...grpc.CallOption) (*CheckMacPermResponse, error) {
|
||||
out := new(CheckMacPermResponse)
|
||||
err := c.cc.Invoke(ctx, "/lnrpc.Lightning/CheckMacaroonPermissions", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// LightningServer is the server API for Lightning service.
|
||||
// All implementations must embed UnimplementedLightningServer
|
||||
// for forward compatibility
|
||||
|
@ -1565,6 +1579,11 @@ type LightningServer interface {
|
|||
//ListPermissions lists all RPC method URIs and their required macaroon
|
||||
//permissions to access them.
|
||||
ListPermissions(context.Context, *ListPermissionsRequest) (*ListPermissionsResponse, error)
|
||||
//
|
||||
//CheckMacaroonPermissions checks whether a request follows the constraints
|
||||
//imposed on the macaroon and that the macaroon is authorized to follow the
|
||||
//provided permissions.
|
||||
CheckMacaroonPermissions(context.Context, *CheckMacPermRequest) (*CheckMacPermResponse, error)
|
||||
mustEmbedUnimplementedLightningServer()
|
||||
}
|
||||
|
||||
|
@ -1755,6 +1774,9 @@ func (UnimplementedLightningServer) DeleteMacaroonID(context.Context, *DeleteMac
|
|||
func (UnimplementedLightningServer) ListPermissions(context.Context, *ListPermissionsRequest) (*ListPermissionsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListPermissions not implemented")
|
||||
}
|
||||
func (UnimplementedLightningServer) CheckMacaroonPermissions(context.Context, *CheckMacPermRequest) (*CheckMacPermResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CheckMacaroonPermissions not implemented")
|
||||
}
|
||||
func (UnimplementedLightningServer) mustEmbedUnimplementedLightningServer() {}
|
||||
|
||||
// UnsafeLightningServer may be embedded to opt out of forward compatibility for this service.
|
||||
|
@ -2914,6 +2936,24 @@ func _Lightning_ListPermissions_Handler(srv interface{}, ctx context.Context, de
|
|||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Lightning_CheckMacaroonPermissions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CheckMacPermRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(LightningServer).CheckMacaroonPermissions(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/lnrpc.Lightning/CheckMacaroonPermissions",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(LightningServer).CheckMacaroonPermissions(ctx, req.(*CheckMacPermRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// Lightning_ServiceDesc is the grpc.ServiceDesc for Lightning service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
|
@ -3121,6 +3161,10 @@ var Lightning_ServiceDesc = grpc.ServiceDesc{
|
|||
MethodName: "ListPermissions",
|
||||
Handler: _Lightning_ListPermissions_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CheckMacaroonPermissions",
|
||||
Handler: _Lightning_CheckMacaroonPermissions_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
|
|
|
@ -161,10 +161,20 @@ func (svc *Service) ValidateMacaroon(ctx context.Context,
|
|||
len(md["macaroon"]))
|
||||
}
|
||||
|
||||
return svc.CheckMacAuth(
|
||||
ctx, md["macaroon"][0], requiredPermissions, fullMethod,
|
||||
)
|
||||
}
|
||||
|
||||
// CheckMacAuth checks that the macaroon is not disobeying any caveats and is
|
||||
// authorized to perform the operation the user wants to perform.
|
||||
func (svc *Service) CheckMacAuth(ctx context.Context, macStr string,
|
||||
requiredPermissions []bakery.Op, fullMethod string) error {
|
||||
|
||||
// With the macaroon obtained, we'll now decode the hex-string
|
||||
// encoding, then unmarshal it from binary into its concrete struct
|
||||
// representation.
|
||||
macBytes, err := hex.DecodeString(md["macaroon"][0])
|
||||
macBytes, err := hex.DecodeString(macStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
31
rpcserver.go
31
rpcserver.go
|
@ -513,6 +513,10 @@ func MainRPCServerPermissions() map[string][]bakery.Op {
|
|||
Entity: "info",
|
||||
Action: "read",
|
||||
}},
|
||||
"/lnrpc.Lightning/CheckMacaroonPermissions": {{
|
||||
Entity: "macaroon",
|
||||
Action: "read",
|
||||
}},
|
||||
"/lnrpc.Lightning/SubscribePeerEvents": {{
|
||||
Entity: "peers",
|
||||
Action: "read",
|
||||
|
@ -6962,6 +6966,33 @@ func (r *rpcServer) ListPermissions(_ context.Context,
|
|||
}, nil
|
||||
}
|
||||
|
||||
// CheckMacaroonPermissions checks the caveats and permissions of a macaroon.
|
||||
func (r *rpcServer) CheckMacaroonPermissions(ctx context.Context,
|
||||
req *lnrpc.CheckMacPermRequest) (*lnrpc.CheckMacPermResponse, error) {
|
||||
|
||||
// Turn grpc macaroon permission into bakery.Op for the server to
|
||||
// process.
|
||||
permissions := make([]bakery.Op, len(req.Permissions))
|
||||
for idx, perm := range req.Permissions {
|
||||
permissions[idx] = bakery.Op{
|
||||
Entity: perm.Entity,
|
||||
Action: perm.Action,
|
||||
}
|
||||
}
|
||||
|
||||
err := r.macService.CheckMacAuth(
|
||||
ctx, hex.EncodeToString(req.Macaroon), permissions,
|
||||
req.FullMethod,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||
}
|
||||
|
||||
return &lnrpc.CheckMacPermResponse{
|
||||
Valid: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// FundingStateStep is an advanced funding related call that allows the caller
|
||||
// to either execute some preparatory steps for a funding workflow, or manually
|
||||
// progress a funding workflow. The primary way a funding flow is identified is
|
||||
|
|
Loading…
Add table
Reference in a new issue