diff --git a/auth/context.go b/auth/context.go new file mode 100644 index 0000000..3321e6d --- /dev/null +++ b/auth/context.go @@ -0,0 +1,32 @@ +package auth + +import ( + "context" +) + +// ContextKey is the type that we use to identify LSAT specific values in the +// request context. We wrap the string inside a struct because of this comment +// in the context API: "The provided key must be comparable and should not be of +// type string or any other built-in type to avoid collisions between packages +// using context." +type ContextKey struct { + Name string +} + +var ( + // KeyTokenID is the key under which we store the client's token ID in + // the request context. + KeyTokenID = ContextKey{"tokenid"} +) + +// FromContext tries to extract a value from the given context. +func FromContext(ctx context.Context, key ContextKey) interface{} { + return ctx.Value(key) +} + +// AddToContext adds the given value to the context for easy retrieval later on. +func AddToContext(ctx context.Context, key ContextKey, + value interface{}) context.Context { + + return context.WithValue(ctx, key, value) +} diff --git a/auth/log.go b/auth/log.go index d1fe86c..457a691 100644 --- a/auth/log.go +++ b/auth/log.go @@ -5,6 +5,8 @@ import ( "github.com/lightningnetwork/lnd/build" ) +const Subsystem = "AUTH" + // log is a logger that is initialized with no output filters. This // means the package will not perform any logging by default until the caller // requests it. @@ -12,7 +14,7 @@ var log btclog.Logger // The default amount of logging is none. func init() { - UseLogger(build.NewSubLogger("AUTH", nil)) + UseLogger(build.NewSubLogger(Subsystem, nil)) } // DisableLog disables all library log output. Logging output is disabled diff --git a/auth/server_interceptor.go b/auth/server_interceptor.go new file mode 100644 index 0000000..e06745c --- /dev/null +++ b/auth/server_interceptor.go @@ -0,0 +1,58 @@ +package auth + +import ( + "bytes" + "context" + "net/http" + + "github.com/lightninglabs/loop/lsat" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" +) + +// ServerInterceptor is a gRPC server interceptor that extracts the token ID +// from the request context if an LSAT is present. +type ServerInterceptor struct{} + +// UnaryInterceptor is an unary gRPC server interceptor that inspects incoming +// calls for authentication tokens. If an LSAT authentication token is found in +// the request, its token ID is extracted and treated as client ID. The +// extracted ID is then attached to the request context in a format that is easy +// to extract by request handlers. +func (i *ServerInterceptor) UnaryInterceptor(ctx context.Context, + req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) ( + resp interface{}, err error) { + + // Try getting the authentication header embedded in the context meta + // data and parse it. We ignore all errors that happen and just forward + // the request to the handler if anything fails. Incoming calls with + // invalid metadata will therefore just be treated as non-identified or + // non-authenticated. + md, ok := metadata.FromIncomingContext(ctx) + if !ok { + return handler(ctx, req) + } + header := &http.Header{ + HeaderAuthorization: md.Get(HeaderAuthorization), + } + log.Debugf("Auth header present in request: %s", + md.Get(HeaderAuthorization)) + macaroon, _, err := FromHeader(header) + if err != nil { + return handler(ctx, req) + } + + // If there is an LSAT, decode and add it to the context. + identifier, err := lsat.DecodeIdentifier(bytes.NewBuffer(macaroon.Id())) + if err != nil { + return handler(ctx, req) + } + var clientID lsat.TokenID + copy(clientID[:], identifier.TokenID[:]) + idCtx := AddToContext(ctx, KeyTokenID, clientID) + log.Debugf("Decoded client/token ID %s from auth header", + clientID.String()) + + // Continue the call chain by invoking the handler. + return handler(idCtx, req) +} diff --git a/go.mod b/go.mod index 5a8b387..d11743a 100644 --- a/go.mod +++ b/go.mod @@ -17,8 +17,8 @@ require ( github.com/gorilla/websocket v1.4.1 // indirect github.com/jonboulle/clockwork v0.1.0 // indirect github.com/json-iterator/go v1.1.8 // indirect - github.com/lightninglabs/loop v0.3.0-alpha.0.20191126005026-8b8b87844035 - github.com/lightningnetwork/lnd v0.8.0-beta-rc3.0.20191115230031-4d7a151b4763 + github.com/lightninglabs/loop v0.3.0-alpha.0.20200103135410-5e00ce62677a + github.com/lightningnetwork/lnd v0.8.0-beta-rc3.0.20200103000305-22e1f006b194 github.com/lightningnetwork/lnd/cert v1.0.0 github.com/modern-go/reflect2 v1.0.1 // indirect github.com/soheilhy/cmux v0.1.4 // indirect diff --git a/go.sum b/go.sum index 56185ee..82f99e0 100644 --- a/go.sum +++ b/go.sum @@ -79,6 +79,7 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/frankban/quicktest v1.0.0/go.mod h1:R98jIehRai+d1/3Hv2//jOVCTJhW1VBavT6B6CuGq2k= github.com/frankban/quicktest v1.2.2 h1:xfmOhhoH5fGPgbEAlhLpJH9p0z/0Qizio9osmvn9IUY= @@ -167,18 +168,21 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf h1:HZKvJUHlcXI/f/O0Avg7t8sqkPo78HFzjmeYFl6DPnc= github.com/lightninglabs/gozmq v0.0.0-20191113021534-d20a764486bf/go.mod h1:vxmQPeIQxPf6Jf9rM8R+B4rKBqLA2AjttNxkFBL2Plk= -github.com/lightninglabs/loop v0.3.0-alpha.0.20191126005026-8b8b87844035 h1:Sw8Ibk3xIZgneHvmAcob1uVz55DYn8mvvjbcpH9CH0w= -github.com/lightninglabs/loop v0.3.0-alpha.0.20191126005026-8b8b87844035/go.mod h1:9tvOOyUhd3AcfrxLz/dJSTHJ0ouqA+u6utJ+fBYrk9M= +github.com/lightninglabs/loop v0.3.0-alpha.0.20200103135410-5e00ce62677a h1:EiZsid2PZaanlYn5x41hKttdoxnd3rJ34SotnO4bu4Y= +github.com/lightninglabs/loop v0.3.0-alpha.0.20200103135410-5e00ce62677a/go.mod h1:VEp7TFUL7Ehq9mjQVUuNVTjpMIeTx8kOHvQ7PdJpLuA= github.com/lightninglabs/neutrino v0.11.0 h1:lPpYFCtsfJX2W5zI4pWycPmbbBdr7zU+BafYdLoD6k0= github.com/lightninglabs/neutrino v0.11.0/go.mod h1:CuhF0iuzg9Sp2HO6ZgXgayviFTn1QHdSTJlMncK80wg= -github.com/lightningnetwork/lightning-onion v0.0.0-20190909101754-850081b08b6a h1:GoWPN4i4jTKRxhVNh9a2vvBBO1Y2seiJB+SopUYoKyo= -github.com/lightningnetwork/lightning-onion v0.0.0-20190909101754-850081b08b6a/go.mod h1:rigfi6Af/KqsF7Za0hOgcyq2PNH4AN70AaMRxcJkff4= -github.com/lightningnetwork/lnd v0.8.0-beta-rc3.0.20191115230031-4d7a151b4763 h1:Eit9hH737th2WwnnVhkuxyMqgXce6keztGTtbDMLJ80= -github.com/lightningnetwork/lnd v0.8.0-beta-rc3.0.20191115230031-4d7a151b4763/go.mod h1:Z7DDVIgvMgyb/4+btLeiU++xt49T35PNunXGCvAaxiE= +github.com/lightninglabs/protobuf-hex-display v1.3.3-0.20191212020323-b444784ce75d/go.mod h1:KDb67YMzoh4eudnzClmvs2FbiLG9vxISmLApUkCa4uI= +github.com/lightningnetwork/lightning-onion v0.0.0-20191214001659-f34e9dc1651d h1:U50MHOOeL6gR3Ee/l0eMvZMpmRo+ydzmlQuIruCyCsA= +github.com/lightningnetwork/lightning-onion v0.0.0-20191214001659-f34e9dc1651d/go.mod h1:rigfi6Af/KqsF7Za0hOgcyq2PNH4AN70AaMRxcJkff4= +github.com/lightningnetwork/lnd v0.8.0-beta-rc3.0.20200103000305-22e1f006b194 h1:PCzjJcVWcMbkiQvzFNc3ta0JmiMprFDqzMZsSpd/km8= +github.com/lightningnetwork/lnd v0.8.0-beta-rc3.0.20200103000305-22e1f006b194/go.mod h1:WHK90FD3m2n6OyWzondS7ho0Uhtgfp30Nxvj24lQYX4= github.com/lightningnetwork/lnd/cert v1.0.0 h1:J0gtf2UNQX2U+/j5cXnX2wIMSTuJuwrXv7m9qJr2wtw= github.com/lightningnetwork/lnd/cert v1.0.0/go.mod h1:fmtemlSMf5t4hsQmcprSoOykypAPp+9c+0d0iqTScMo= github.com/lightningnetwork/lnd/queue v1.0.1 h1:jzJKcTy3Nj5lQrooJ3aaw9Lau3I0IwvQR5sqtjdv2R0= github.com/lightningnetwork/lnd/queue v1.0.1/go.mod h1:vaQwexir73flPW43Mrm7JOgJHmcEFBWWSl9HlyASoms= +github.com/lightningnetwork/lnd/queue v1.0.2 h1:Hx43fmTz2pDH4fIYDr57P/M5cB+GEMLzN+eif8576Xo= +github.com/lightningnetwork/lnd/queue v1.0.2/go.mod h1:YTkTVZCxz8tAYreH27EO3s8572ODumWrNdYW2E/YKxg= github.com/lightningnetwork/lnd/ticker v1.0.0 h1:S1b60TEGoTtCe2A0yeB+ecoj/kkS4qpwh6l+AkQEZwU= github.com/lightningnetwork/lnd/ticker v1.0.0/go.mod h1:iaLXJiVgI1sPANIF2qYYUJXjoksPNvGNYowB8aRbpX0= github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 h1:sjOGyegMIhvgfq5oaue6Td+hxZuf3tDC8lAPrFldqFw= diff --git a/log.go b/log.go index cf1cca8..647e890 100644 --- a/log.go +++ b/log.go @@ -15,7 +15,7 @@ var ( func init() { setSubLogger("MAIN", log, nil) - addSubLogger("AUTH", auth.UseLogger) + addSubLogger(auth.Subsystem, auth.UseLogger) addSubLogger("PRXY", proxy.UseLogger) }