mirror of
https://github.com/lightninglabs/aperture.git
synced 2025-12-18 17:44:20 +01:00
auth: add server interceptor
This commit is contained in:
32
auth/context.go
Normal file
32
auth/context.go
Normal file
@@ -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)
|
||||
}
|
||||
58
auth/server_interceptor.go
Normal file
58
auth/server_interceptor.go
Normal file
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user