From a65791616818e437bb831f7f753242691757a0c9 Mon Sep 17 00:00:00 2001 From: Nic Hite Date: Tue, 29 Sep 2020 11:55:28 -0700 Subject: [PATCH] Add client validation to server credentials (#363) * Add ability to validate clients to server credentials. --- CHANGELOG.md | 5 ++++ lib/grpc.dart | 7 +++++- lib/service_api.dart | 2 +- lib/src/server/server.dart | 51 +++++++++++++++++++++++++++++--------- pubspec.yaml | 2 +- 5 files changed, 52 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3454733..846485d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.5.0 + +* Expose a `validateClient` method for server credentials so gRPC server + users may know when clients are loopback addresses. + ## 2.4.1 * Plumb stacktraces through request / response stream error handlers. diff --git a/lib/grpc.dart b/lib/grpc.dart index 9681cbb..ffe8e99 100644 --- a/lib/grpc.dart +++ b/lib/grpc.dart @@ -43,7 +43,12 @@ export 'src/client/transport/http2_credentials.dart' export 'src/server/call.dart' show ServiceCall; export 'src/server/interceptor.dart' show Interceptor; -export 'src/server/server.dart' show ServerTlsCredentials, Server; +export 'src/server/server.dart' + show + ServerCredentials, + ServerLocalCredentials, + ServerTlsCredentials, + Server; export 'src/server/service.dart' show ServiceMethod, Service; export 'src/shared/message.dart' diff --git a/lib/service_api.dart b/lib/service_api.dart index 7d7a593..5d8164b 100644 --- a/lib/service_api.dart +++ b/lib/service_api.dart @@ -18,7 +18,7 @@ /// Mainly intended to be imported by generated code. library service_api; -export 'src/client/call.dart' show CallOptions; +export 'src/client/call.dart' show CallOptions, MetadataProvider; export 'src/client/channel.dart' show ClientChannel; export 'src/client/client.dart' show Client; export 'src/client/common.dart' show ResponseFuture, ResponseStream; diff --git a/lib/src/server/server.dart b/lib/src/server/server.dart index 24a14c8..48f151e 100644 --- a/lib/src/server/server.dart +++ b/lib/src/server/server.dart @@ -25,7 +25,27 @@ import 'handler.dart'; import 'interceptor.dart'; import 'service.dart'; -class ServerTlsCredentials { +/// Wrapper around grpc_server_credentials, a way to authenticate a server. +abstract class ServerCredentials { + /// Validates incoming connection. Returns [true] if connection is + /// allowed to proceed. + bool validateClient(Socket socket) => true; + + /// Creates [SecurityContext] from these credentials if possible. + /// Otherwise returns [null]. + SecurityContext get securityContext; +} + +/// Set of credentials that only allows local TCP connections. +class ServerLocalCredentials extends ServerCredentials { + @override + bool validateClient(Socket socket) => socket.remoteAddress.isLoopback; + + @override + SecurityContext get securityContext => null; +} + +class ServerTlsCredentials extends ServerCredentials { final List certificate; final String certificatePassword; final List privateKey; @@ -52,6 +72,9 @@ class ServerTlsCredentials { } return context; } + + @override + bool validateClient(Socket socket) => true; } /// A gRPC server. @@ -87,21 +110,18 @@ class Server { Future serve( {dynamic address, int port, - ServerTlsCredentials security, + ServerCredentials security, ServerSettings http2ServerSettings, int backlog: 0, bool v6Only: false, bool shared: false}) async { // TODO(dart-lang/grpc-dart#9): Handle HTTP/1.1 upgrade to h2c, if allowed. Stream server; - if (security != null) { + final securityContext = security?.securityContext; + if (securityContext != null) { _secureServer = await SecureServerSocket.bind( - address ?? InternetAddress.anyIPv4, - port ?? 443, - security.securityContext, - backlog: backlog, - shared: shared, - v6Only: v6Only); + address ?? InternetAddress.anyIPv4, port ?? 443, securityContext, + backlog: backlog, shared: shared, v6Only: v6Only); server = _secureServer; } else { _insecureServer = await ServerSocket.bind( @@ -119,6 +139,11 @@ class Server { final connection = ServerTransportConnection.viaSocket(socket, settings: http2ServerSettings); _connections.add(connection); + if (security != null && !security.validateClient(socket)) { + _printSocketError( + 'cannot serve $address:$port - unable to validate client socket'); + return socket.close(); + } ServerHandler_ handler; // TODO(jakobr): Set active state handlers, close connection after idle // timeout. @@ -134,9 +159,11 @@ class Server { handler?.cancel(); _connections.remove(connection); }); - }, onError: (error) { - print('Socket error: $error'); - }); + }, onError: _printSocketError); + } + + void _printSocketError(Object error) { + print('Socket error: $error'); } @visibleForTesting diff --git a/pubspec.yaml b/pubspec.yaml index 15192be..9f01a00 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: grpc description: Dart implementation of gRPC, a high performance, open-source universal RPC framework. -version: 2.4.1 +version: 2.5.0 author: Dart Team homepage: https://github.com/dart-lang/grpc-dart