|
|
|
|
@@ -48,21 +48,45 @@ type Server struct {
|
|
|
|
|
listener net.Listener
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Options configures optional behavior for the gRPC server.
|
|
|
|
|
type Options struct {
|
|
|
|
|
// PreInterceptors run before the logging and auth interceptors.
|
|
|
|
|
// Use for lifecycle gates like seal checks that should reject
|
|
|
|
|
// requests before any auth validation occurs.
|
|
|
|
|
PreInterceptors []grpc.UnaryServerInterceptor
|
|
|
|
|
|
|
|
|
|
// PostInterceptors run after auth but before the handler.
|
|
|
|
|
// Use for audit logging, rate limiting, or other cross-cutting
|
|
|
|
|
// concerns that need access to the authenticated identity.
|
|
|
|
|
PostInterceptors []grpc.UnaryServerInterceptor
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// New creates a gRPC server with TLS (if certFile and keyFile are
|
|
|
|
|
// non-empty) and an interceptor chain: logging → auth → handler.
|
|
|
|
|
// non-empty) and an interceptor chain:
|
|
|
|
|
//
|
|
|
|
|
// [pre-interceptors] → logging → auth → [post-interceptors] → handler
|
|
|
|
|
//
|
|
|
|
|
// The auth interceptor uses methods to determine the access level for
|
|
|
|
|
// each RPC. Methods not in any map are denied by default.
|
|
|
|
|
//
|
|
|
|
|
// If certFile and keyFile are empty, TLS is skipped (for testing).
|
|
|
|
|
func New(certFile, keyFile string, authenticator *auth.Authenticator, methods MethodMap, logger *slog.Logger) (*Server, error) {
|
|
|
|
|
chain := grpc.ChainUnaryInterceptor(
|
|
|
|
|
// opts is optional; pass nil for the default chain (logging + auth only).
|
|
|
|
|
func New(certFile, keyFile string, authenticator *auth.Authenticator, methods MethodMap, logger *slog.Logger, opts *Options) (*Server, error) {
|
|
|
|
|
var interceptors []grpc.UnaryServerInterceptor
|
|
|
|
|
if opts != nil {
|
|
|
|
|
interceptors = append(interceptors, opts.PreInterceptors...)
|
|
|
|
|
}
|
|
|
|
|
interceptors = append(interceptors,
|
|
|
|
|
loggingInterceptor(logger),
|
|
|
|
|
authInterceptor(authenticator, methods),
|
|
|
|
|
)
|
|
|
|
|
if opts != nil {
|
|
|
|
|
interceptors = append(interceptors, opts.PostInterceptors...)
|
|
|
|
|
}
|
|
|
|
|
chain := grpc.ChainUnaryInterceptor(interceptors...)
|
|
|
|
|
|
|
|
|
|
var opts []grpc.ServerOption
|
|
|
|
|
opts = append(opts, chain)
|
|
|
|
|
var serverOpts []grpc.ServerOption
|
|
|
|
|
serverOpts = append(serverOpts, chain)
|
|
|
|
|
|
|
|
|
|
if certFile != "" && keyFile != "" {
|
|
|
|
|
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
|
|
|
|
@@ -73,11 +97,11 @@ func New(certFile, keyFile string, authenticator *auth.Authenticator, methods Me
|
|
|
|
|
Certificates: []tls.Certificate{cert},
|
|
|
|
|
MinVersion: tls.VersionTLS13,
|
|
|
|
|
}
|
|
|
|
|
opts = append(opts, grpc.Creds(credentials.NewTLS(tlsCfg)))
|
|
|
|
|
serverOpts = append(serverOpts, grpc.Creds(credentials.NewTLS(tlsCfg)))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &Server{
|
|
|
|
|
GRPCServer: grpc.NewServer(opts...),
|
|
|
|
|
GRPCServer: grpc.NewServer(serverOpts...),
|
|
|
|
|
Logger: logger,
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|