mirror of
https://github.com/lightninglabs/aperture.git
synced 2025-12-17 09:04:19 +01:00
auth: LsatAuthenticator -> L402Authenticator sed -i 's/LsatAuthenticator/L402Authenticator/g' aperture.go auth/authenticator.go auth/authenticator_test.go rename package lsat to l402 git mv lsat/ l402 sed 's@aperture/lsat@aperture/l402@g' -i `git grep -l aperture/lsat` sed -i 's@package lsat@package l402@' `git grep -l 'package lsat'` sed -i 's@lsat\.@l402.@g' -i `git grep -l 'lsat\.'` sed 's@l402.Id@lsat.Id@' -i mint/mint_test.go replace lsat with l402 in the code sed 's@lsat@l402@' -i mint/mint_test.go sed 's@Lsat@L402@' -i l402/client_interceptor.go sed 's@lsatstore@l402store@' -i l402/store_test.go replace LSAT to L402 in comments sed '/\/\//s@LSAT@L402@g' -i `git grep -l '//.*LSAT'` replace LSAT -> L402 in the code, skip when a string starts with it sed 's@\([^"/]\)LSAT@\1L402@g' -i `git grep -l LSAT`
111 lines
3.9 KiB
Go
111 lines
3.9 KiB
Go
package l402
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"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 L402 is present.
|
|
type ServerInterceptor struct{}
|
|
|
|
// UnaryInterceptor is an unary gRPC server interceptor that inspects incoming
|
|
// calls for authentication tokens. If an L402 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.
|
|
token, err := tokenFromContext(ctx)
|
|
if err != nil {
|
|
log.Debugf("No token extracted, error was: %v", err)
|
|
return handler(ctx, req)
|
|
}
|
|
|
|
// We got a token, create a new context that wraps its value and
|
|
// continue the call chain by invoking the handler.
|
|
idCtx := AddToContext(ctx, KeyTokenID, *token)
|
|
return handler(idCtx, req)
|
|
}
|
|
|
|
// wrappedStream is a thin wrapper around the grpc.ServerStream that allows us
|
|
// to overwrite the context of the stream.
|
|
type wrappedStream struct {
|
|
grpc.ServerStream
|
|
WrappedContext context.Context
|
|
}
|
|
|
|
// Context returns the context for this stream.
|
|
func (w *wrappedStream) Context() context.Context {
|
|
return w.WrappedContext
|
|
}
|
|
|
|
// StreamInterceptor is an stream gRPC server interceptor that inspects incoming
|
|
// streams for authentication tokens. If an L402 authentication token is found
|
|
// in the initial stream establishment 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) StreamInterceptor(srv interface{},
|
|
ss grpc.ServerStream, _ *grpc.StreamServerInfo,
|
|
handler grpc.StreamHandler) 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.
|
|
ctx := ss.Context()
|
|
token, err := tokenFromContext(ctx)
|
|
if err != nil {
|
|
log.Debugf("No token extracted, error was: %v", err)
|
|
return handler(srv, ss)
|
|
}
|
|
|
|
// We got a token, create a new context that wraps its value and
|
|
// continue the call chain by invoking the handler. We can't directly
|
|
// modify the server stream so we have to wrap it.
|
|
idCtx := AddToContext(ctx, KeyTokenID, *token)
|
|
wrappedStream := &wrappedStream{ss, idCtx}
|
|
return handler(srv, wrappedStream)
|
|
}
|
|
|
|
// tokenFromContext tries to extract the L402 from a context.
|
|
func tokenFromContext(ctx context.Context) (*TokenID, error) {
|
|
md, ok := metadata.FromIncomingContext(ctx)
|
|
if !ok {
|
|
return nil, fmt.Errorf("context contains no metadata")
|
|
}
|
|
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 nil, fmt.Errorf("auth header extraction failed: %v", err)
|
|
}
|
|
|
|
// If there is an L402, decode and add it to the context.
|
|
identifier, err := DecodeIdentifier(bytes.NewBuffer(macaroon.Id()))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("token ID decoding failed: %v", err)
|
|
}
|
|
var clientID TokenID
|
|
copy(clientID[:], identifier.TokenID[:])
|
|
log.Debugf("Decoded client/token ID %s from auth header",
|
|
clientID.String())
|
|
return &clientID, nil
|
|
}
|