From b4414b882c4f86058adbbf8784fd09cb6be14a33 Mon Sep 17 00:00:00 2001 From: Brian Hatfield Date: Mon, 30 Jul 2018 14:49:26 -0400 Subject: [PATCH] Expose google cgrpc credential mode --- Sources/CgRPC/shim/cgrpc.h | 4 +++ Sources/CgRPC/shim/channel.c | 16 ++++++++++++ Sources/SwiftGRPC/Core/Channel.swift | 26 +++++++++++++++---- Sources/SwiftGRPC/Runtime/ServiceClient.swift | 20 +++++++++++++- 4 files changed, 60 insertions(+), 6 deletions(-) diff --git a/Sources/CgRPC/shim/cgrpc.h b/Sources/CgRPC/shim/cgrpc.h index 31c1531c8..4e202232e 100644 --- a/Sources/CgRPC/shim/cgrpc.h +++ b/Sources/CgRPC/shim/cgrpc.h @@ -171,6 +171,10 @@ cgrpc_channel *cgrpc_channel_create_secure(const char *address, grpc_arg *args, int num_args); +cgrpc_channel *cgrpc_channel_create_google(const char *address, + grpc_arg *args, + int num_args); + void cgrpc_channel_destroy(cgrpc_channel *channel); cgrpc_call *cgrpc_channel_create_call(cgrpc_channel *channel, const char *method, diff --git a/Sources/CgRPC/shim/channel.c b/Sources/CgRPC/shim/channel.c index da90e76d9..68b95cb49 100644 --- a/Sources/CgRPC/shim/channel.c +++ b/Sources/CgRPC/shim/channel.c @@ -63,6 +63,22 @@ cgrpc_channel *cgrpc_channel_create_secure(const char *address, return c; } +cgrpc_channel *cgrpc_channel_create_google(const char *address, + grpc_arg *args, + int num_args) { + cgrpc_channel *c = (cgrpc_channel *) malloc(sizeof (cgrpc_channel)); + + grpc_channel_args channel_args; + channel_args.args = args; + channel_args.num_args = num_args; + + grpc_channel_credentials *google_creds = grpc_google_default_credentials_create(); + + c->channel = grpc_secure_channel_create(google_creds, address, &channel_args, NULL); + c->completion_queue = grpc_completion_queue_create_for_next(NULL); + return c; +} + void cgrpc_channel_destroy(cgrpc_channel *c) { grpc_channel_destroy(c->channel); diff --git a/Sources/SwiftGRPC/Core/Channel.swift b/Sources/SwiftGRPC/Core/Channel.swift index cafc8ab75..c50b1c589 100644 --- a/Sources/SwiftGRPC/Core/Channel.swift +++ b/Sources/SwiftGRPC/Core/Channel.swift @@ -56,6 +56,22 @@ public class Channel { completionQueue.run() // start a loop that watches the channel's completion queue } + /// Initializes a gRPC channel + /// + /// - Parameter address: the address of the server to be called + /// - Parameter arguments: list of channel configuration options + public init(googleAddress: String, arguments: [Argument] = []) { + gRPC.initialize() + host = googleAddress + let argumentWrappers = arguments.map { $0.toCArg() } + var argumentValues = argumentWrappers.map { $0.wrapped } + + underlyingChannel = cgrpc_channel_create_google(googleAddress, &argumentValues, Int32(arguments.count)) + + completionQueue = CompletionQueue(underlyingCompletionQueue: cgrpc_channel_completion_queue(underlyingChannel), name: "Client") + completionQueue.run() // start a loop that watches the channel's completion queue + } + /// Initializes a gRPC channel /// /// - Parameter address: the address of the server to be called @@ -116,7 +132,7 @@ private extension Channel { private let underlyingCompletionQueue: UnsafeMutableRawPointer private let callback: (ConnectivityState) -> Void private var lastState: ConnectivityState - + init(underlyingChannel: UnsafeMutableRawPointer, currentState: ConnectivityState, callback: @escaping (ConnectivityState) -> ()) { self.underlyingChannel = underlyingChannel self.underlyingCompletionQueue = cgrpc_completion_queue_create_for_next() @@ -136,7 +152,7 @@ private extension Channel { spinloopThreadQueue.async { while true { guard let underlyingState = self.lastState.underlyingState else { return } - + let deadline: TimeInterval = 0.2 cgrpc_channel_watch_connectivity_state(self.underlyingChannel, self.underlyingCompletionQueue, underlyingState, deadline, nil) let event = self.completionQueue.wait(timeout: deadline) @@ -144,11 +160,11 @@ private extension Channel { switch event.type { case .complete: let newState = ConnectivityState.connectivityState(cgrpc_channel_check_connectivity_state(self.underlyingChannel, 0)) - + if newState != self.lastState { self.callback(newState) } - + self.lastState = newState case .queueTimeout: continue @@ -160,7 +176,7 @@ private extension Channel { } } } - + func shutdown() { completionQueue.shutdown() } diff --git a/Sources/SwiftGRPC/Runtime/ServiceClient.swift b/Sources/SwiftGRPC/Runtime/ServiceClient.swift index 6ac8e28d4..41dfc4237 100644 --- a/Sources/SwiftGRPC/Runtime/ServiceClient.swift +++ b/Sources/SwiftGRPC/Runtime/ServiceClient.swift @@ -60,7 +60,25 @@ open class ServiceClientBase: ServiceClient { self.channel = channel metadata = Metadata() } - + + /// Create a client with Google credentials. + /// - Parameter googleApi: the name of the Google API service (e.g. "cloudkms" in "cloudkms.googleapis.com") + /// - Parameter arguments: list of channel configuration options + /// + /// Note: cgRPC's `grpc_google_default_credentials_create` doesn't accept a root pem argument. + /// To override: `export GRPC_DEFAULT_SSL_ROOTS_FILE_PATH=/path/to/your/root/cert.pem` + required public init(googleApi: String, arguments: [Channel.Argument] = []) { + gRPC.initialize() + + // Force the address of the Google API to account for the security concern mentioned in + // Sources/CgRPC/include/grpc/grpc_security.h: + // WARNING: Do NOT use this credentials to connect to a non-google service as + // this could result in an oauth2 token leak. + let address = googleApi + ".googleapis.com" + channel = Channel(googleAddress: address, arguments: arguments) + metadata = Metadata() + } + /// Create a client that makes secure connections with a custom certificate. required public init(address: String, certificates: String, clientCertificates: String? = nil, clientKey: String? = nil, arguments: [Channel.Argument] = []) { gRPC.initialize()