# Copyright 2015, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. cimport cpython cdef class ChannelCredentials: def __cinit__(self): self.c_credentials = NULL self.c_ssl_pem_key_cert_pair.private_key = NULL self.c_ssl_pem_key_cert_pair.certificate_chain = NULL self.references = [] # The object *can* be invalid in Python if we fail to make the credentials # (and the core thus returns NULL credentials). Used primarily for debugging. @property def is_valid(self): return self.c_credentials != NULL def __dealloc__(self): if self.c_credentials != NULL: with nogil: grpc_channel_credentials_release(self.c_credentials) cdef class CallCredentials: def __cinit__(self): self.c_credentials = NULL self.references = [] # The object *can* be invalid in Python if we fail to make the credentials # (and the core thus returns NULL credentials). Used primarily for debugging. @property def is_valid(self): return self.c_credentials != NULL def __dealloc__(self): if self.c_credentials != NULL: with nogil: grpc_call_credentials_release(self.c_credentials) cdef class ServerCredentials: def __cinit__(self): self.c_credentials = NULL self.references = [] def __dealloc__(self): if self.c_credentials != NULL: with nogil: grpc_server_credentials_release(self.c_credentials) cdef class CredentialsMetadataPlugin: def __cinit__(self, object plugin_callback, str name): """ Args: plugin_callback (callable): Callback accepting a service URL (str/bytes) and callback object (accepting a Metadata, grpc_status_code, and a str/bytes error message). This argument when called should be non-blocking and eventually call the callback object with the appropriate status code/details and metadata (if successful). name (str): Plugin name. """ if not callable(plugin_callback): raise ValueError('expected callable plugin_callback') self.plugin_callback = plugin_callback self.plugin_name = name @staticmethod cdef grpc_metadata_credentials_plugin make_c_plugin(self): cdef grpc_metadata_credentials_plugin result result.get_metadata = plugin_get_metadata result.destroy = plugin_destroy_c_plugin_state result.state = self result.type = self.plugin_name cpython.Py_INCREF(self) return result cdef class AuthMetadataContext: def __cinit__(self): self.context.service_url = NULL self.context.method_name = NULL @property def service_url(self): return self.context.service_url @property def method_name(self): return self.context.method_name cdef void plugin_get_metadata( void *state, grpc_auth_metadata_context context, grpc_credentials_plugin_metadata_cb cb, void *user_data) with gil: def python_callback( Metadata metadata, grpc_status_code status, const char *error_details): cb(user_data, metadata.c_metadata_array.metadata, metadata.c_metadata_array.count, status, error_details) cdef CredentialsMetadataPlugin self = state cdef AuthMetadataContext cy_context = AuthMetadataContext() cy_context.context = context self.plugin_callback(cy_context, python_callback) cdef void plugin_destroy_c_plugin_state(void *state): cpython.Py_DECREF(state) def channel_credentials_google_default(): cdef ChannelCredentials credentials = ChannelCredentials(); with nogil: credentials.c_credentials = grpc_google_default_credentials_create() return credentials def channel_credentials_ssl(pem_root_certificates, SslPemKeyCertPair ssl_pem_key_cert_pair): if pem_root_certificates is None: pass elif isinstance(pem_root_certificates, bytes): pass elif isinstance(pem_root_certificates, basestring): pem_root_certificates = pem_root_certificates.encode() else: raise TypeError("expected str or bytes for pem_root_certificates") cdef ChannelCredentials credentials = ChannelCredentials() cdef const char *c_pem_root_certificates = NULL if pem_root_certificates is not None: c_pem_root_certificates = pem_root_certificates credentials.references.append(pem_root_certificates) if ssl_pem_key_cert_pair is not None: with nogil: credentials.c_credentials = grpc_ssl_credentials_create( c_pem_root_certificates, &ssl_pem_key_cert_pair.c_pair, NULL) credentials.references.append(ssl_pem_key_cert_pair) else: with nogil: credentials.c_credentials = grpc_ssl_credentials_create( c_pem_root_certificates, NULL, NULL) return credentials def channel_credentials_composite( ChannelCredentials credentials_1 not None, CallCredentials credentials_2 not None): if not credentials_1.is_valid or not credentials_2.is_valid: raise ValueError("passed credentials must both be valid") cdef ChannelCredentials credentials = ChannelCredentials() with nogil: credentials.c_credentials = grpc_composite_channel_credentials_create( credentials_1.c_credentials, credentials_2.c_credentials, NULL) credentials.references.append(credentials_1) credentials.references.append(credentials_2) return credentials def call_credentials_composite( CallCredentials credentials_1 not None, CallCredentials credentials_2 not None): if not credentials_1.is_valid or not credentials_2.is_valid: raise ValueError("passed credentials must both be valid") cdef CallCredentials credentials = CallCredentials() with nogil: credentials.c_credentials = grpc_composite_call_credentials_create( credentials_1.c_credentials, credentials_2.c_credentials, NULL) credentials.references.append(credentials_1) credentials.references.append(credentials_2) return credentials def call_credentials_google_compute_engine(): cdef CallCredentials credentials = CallCredentials() with nogil: credentials.c_credentials = ( grpc_google_compute_engine_credentials_create(NULL)) return credentials def call_credentials_service_account_jwt_access( json_key, Timespec token_lifetime not None): if isinstance(json_key, bytes): pass elif isinstance(json_key, basestring): json_key = json_key.encode() else: raise TypeError("expected json_key to be str or bytes") cdef CallCredentials credentials = CallCredentials() cdef char *json_key_c_string = json_key with nogil: credentials.c_credentials = ( grpc_service_account_jwt_access_credentials_create( json_key_c_string, token_lifetime.c_time, NULL)) credentials.references.append(json_key) return credentials def call_credentials_google_refresh_token(json_refresh_token): if isinstance(json_refresh_token, bytes): pass elif isinstance(json_refresh_token, basestring): json_refresh_token = json_refresh_token.encode() else: raise TypeError("expected json_refresh_token to be str or bytes") cdef CallCredentials credentials = CallCredentials() cdef char *json_refresh_token_c_string = json_refresh_token with nogil: credentials.c_credentials = grpc_google_refresh_token_credentials_create( json_refresh_token_c_string, NULL) credentials.references.append(json_refresh_token) return credentials def call_credentials_google_iam(authorization_token, authority_selector): if isinstance(authorization_token, bytes): pass elif isinstance(authorization_token, basestring): authorization_token = authorization_token.encode() else: raise TypeError("expected authorization_token to be str or bytes") if isinstance(authority_selector, bytes): pass elif isinstance(authority_selector, basestring): authority_selector = authority_selector.encode() else: raise TypeError("expected authority_selector to be str or bytes") cdef CallCredentials credentials = CallCredentials() cdef char *authorization_token_c_string = authorization_token cdef char *authority_selector_c_string = authority_selector with nogil: credentials.c_credentials = grpc_google_iam_credentials_create( authorization_token_c_string, authority_selector_c_string, NULL) credentials.references.append(authorization_token) credentials.references.append(authority_selector) return credentials def call_credentials_metadata_plugin(CredentialsMetadataPlugin plugin): cdef CallCredentials credentials = CallCredentials() cdef grpc_metadata_credentials_plugin c_plugin = plugin.make_c_plugin() with nogil: credentials.c_credentials = ( grpc_metadata_credentials_create_from_plugin(c_plugin, NULL)) # TODO(atash): the following held reference is *probably* never necessary credentials.references.append(plugin) return credentials def server_credentials_ssl(pem_root_certs, pem_key_cert_pairs, bint force_client_auth): cdef char *c_pem_root_certs = NULL if pem_root_certs is None: pass elif isinstance(pem_root_certs, bytes): c_pem_root_certs = pem_root_certs elif isinstance(pem_root_certs, basestring): pem_root_certs = pem_root_certs.encode() c_pem_root_certs = pem_root_certs else: raise TypeError("expected pem_root_certs to be str or bytes") pem_key_cert_pairs = list(pem_key_cert_pairs) for pair in pem_key_cert_pairs: if not isinstance(pair, SslPemKeyCertPair): raise TypeError("expected pem_key_cert_pairs to be sequence of " "SslPemKeyCertPair") cdef ServerCredentials credentials = ServerCredentials() credentials.references.append(pem_key_cert_pairs) credentials.references.append(pem_root_certs) credentials.c_ssl_pem_key_cert_pairs_count = len(pem_key_cert_pairs) with nogil: credentials.c_ssl_pem_key_cert_pairs = ( gpr_malloc( sizeof(grpc_ssl_pem_key_cert_pair) * credentials.c_ssl_pem_key_cert_pairs_count )) for i in range(credentials.c_ssl_pem_key_cert_pairs_count): credentials.c_ssl_pem_key_cert_pairs[i] = ( (pem_key_cert_pairs[i]).c_pair) credentials.c_credentials = grpc_ssl_server_credentials_create( c_pem_root_certs, credentials.c_ssl_pem_key_cert_pairs, credentials.c_ssl_pem_key_cert_pairs_count, force_client_auth, NULL) return credentials