1# Copyright 2015 gRPC authors. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15cimport cpython 16 17import grpc 18import threading 19 20from libc.stdint cimport uintptr_t 21 22 23def _spawn_callback_in_thread(cb_func, args): 24 ForkManagedThread(target=cb_func, args=args).start() 25 26async_callback_func = _spawn_callback_in_thread 27 28def set_async_callback_func(callback_func): 29 global async_callback_func 30 async_callback_func = callback_func 31 32def _spawn_callback_async(callback, args): 33 async_callback_func(callback, args) 34 35 36cdef class CallCredentials: 37 38 cdef grpc_call_credentials *c(self): 39 raise NotImplementedError() 40 41 42cdef int _get_metadata( 43 void *state, grpc_auth_metadata_context context, 44 grpc_credentials_plugin_metadata_cb cb, void *user_data, 45 grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX], 46 size_t *num_creds_md, grpc_status_code *status, 47 const char **error_details) with gil: 48 cdef size_t metadata_count 49 cdef grpc_metadata *c_metadata 50 def callback(metadata, grpc_status_code status, bytes error_details): 51 if status == StatusCode.ok: 52 _store_c_metadata(metadata, &c_metadata, &metadata_count) 53 cb(user_data, c_metadata, metadata_count, status, NULL) 54 _release_c_metadata(c_metadata, metadata_count) 55 else: 56 cb(user_data, NULL, 0, status, error_details) 57 args = context.service_url, context.method_name, callback, 58 _spawn_callback_async(<object>state, args) 59 return 0 # Asynchronous return 60 61 62cdef void _destroy(void *state) with gil: 63 cpython.Py_DECREF(<object>state) 64 65 66cdef class MetadataPluginCallCredentials(CallCredentials): 67 68 def __cinit__(self, metadata_plugin, name): 69 self._metadata_plugin = metadata_plugin 70 self._name = name 71 72 cdef grpc_call_credentials *c(self): 73 cdef grpc_metadata_credentials_plugin c_metadata_plugin 74 c_metadata_plugin.get_metadata = _get_metadata 75 c_metadata_plugin.destroy = _destroy 76 c_metadata_plugin.state = <void *>self._metadata_plugin 77 c_metadata_plugin.type = self._name 78 cpython.Py_INCREF(self._metadata_plugin) 79 return grpc_metadata_credentials_create_from_plugin(c_metadata_plugin, NULL) 80 81 82cdef grpc_call_credentials *_composition(call_credentialses): 83 call_credentials_iterator = iter(call_credentialses) 84 cdef CallCredentials composition = next(call_credentials_iterator) 85 cdef grpc_call_credentials *c_composition = composition.c() 86 cdef CallCredentials additional_call_credentials 87 cdef grpc_call_credentials *c_additional_call_credentials 88 cdef grpc_call_credentials *c_next_composition 89 for additional_call_credentials in call_credentials_iterator: 90 c_additional_call_credentials = additional_call_credentials.c() 91 c_next_composition = grpc_composite_call_credentials_create( 92 c_composition, c_additional_call_credentials, NULL) 93 grpc_call_credentials_release(c_composition) 94 grpc_call_credentials_release(c_additional_call_credentials) 95 c_composition = c_next_composition 96 return c_composition 97 98 99cdef class CompositeCallCredentials(CallCredentials): 100 101 def __cinit__(self, call_credentialses): 102 self._call_credentialses = call_credentialses 103 104 cdef grpc_call_credentials *c(self): 105 return _composition(self._call_credentialses) 106 107 108cdef class ChannelCredentials: 109 110 cdef grpc_channel_credentials *c(self): 111 raise NotImplementedError() 112 113 114cdef class SSLSessionCacheLRU: 115 116 def __cinit__(self, capacity): 117 fork_handlers_and_grpc_init() 118 self._cache = grpc_ssl_session_cache_create_lru(capacity) 119 120 def __int__(self): 121 return <uintptr_t>self._cache 122 123 def __dealloc__(self): 124 if self._cache != NULL: 125 grpc_ssl_session_cache_destroy(self._cache) 126 grpc_shutdown() 127 128 129cdef class SSLChannelCredentials(ChannelCredentials): 130 131 def __cinit__(self, pem_root_certificates, private_key, certificate_chain): 132 self._pem_root_certificates = pem_root_certificates 133 self._private_key = private_key 134 self._certificate_chain = certificate_chain 135 136 cdef grpc_channel_credentials *c(self): 137 cdef const char *c_pem_root_certificates 138 cdef grpc_ssl_pem_key_cert_pair c_pem_key_certificate_pair 139 if self._pem_root_certificates is None: 140 c_pem_root_certificates = NULL 141 else: 142 c_pem_root_certificates = self._pem_root_certificates 143 if self._private_key is None and self._certificate_chain is None: 144 return grpc_ssl_credentials_create( 145 c_pem_root_certificates, NULL, NULL, NULL) 146 else: 147 if self._private_key: 148 c_pem_key_certificate_pair.private_key = self._private_key 149 else: 150 c_pem_key_certificate_pair.private_key = NULL 151 if self._certificate_chain: 152 c_pem_key_certificate_pair.certificate_chain = self._certificate_chain 153 else: 154 c_pem_key_certificate_pair.certificate_chain = NULL 155 return grpc_ssl_credentials_create( 156 c_pem_root_certificates, &c_pem_key_certificate_pair, NULL, NULL) 157 158 159cdef class CompositeChannelCredentials(ChannelCredentials): 160 161 def __cinit__(self, call_credentialses, channel_credentials): 162 self._call_credentialses = call_credentialses 163 self._channel_credentials = channel_credentials 164 165 cdef grpc_channel_credentials *c(self): 166 cdef grpc_channel_credentials *c_channel_credentials 167 c_channel_credentials = self._channel_credentials.c() 168 cdef grpc_call_credentials *c_call_credentials_composition = _composition( 169 self._call_credentialses) 170 cdef grpc_channel_credentials *composition 171 c_composition = grpc_composite_channel_credentials_create( 172 c_channel_credentials, c_call_credentials_composition, NULL) 173 grpc_channel_credentials_release(c_channel_credentials) 174 grpc_call_credentials_release(c_call_credentials_composition) 175 return c_composition 176 177 178cdef class ServerCertificateConfig: 179 180 def __cinit__(self): 181 fork_handlers_and_grpc_init() 182 self.c_cert_config = NULL 183 self.c_pem_root_certs = NULL 184 self.c_ssl_pem_key_cert_pairs = NULL 185 self.references = [] 186 187 def __dealloc__(self): 188 grpc_ssl_server_certificate_config_destroy(self.c_cert_config) 189 gpr_free(self.c_ssl_pem_key_cert_pairs) 190 grpc_shutdown() 191 192 193cdef class ServerCredentials: 194 195 def __cinit__(self): 196 fork_handlers_and_grpc_init() 197 self.c_credentials = NULL 198 self.references = [] 199 self.initial_cert_config = None 200 self.cert_config_fetcher = None 201 self.initial_cert_config_fetched = False 202 203 def __dealloc__(self): 204 if self.c_credentials != NULL: 205 grpc_server_credentials_release(self.c_credentials) 206 grpc_shutdown() 207 208cdef const char* _get_c_pem_root_certs(pem_root_certs): 209 if pem_root_certs is None: 210 return NULL 211 else: 212 return pem_root_certs 213 214cdef grpc_ssl_pem_key_cert_pair* _create_c_ssl_pem_key_cert_pairs(pem_key_cert_pairs): 215 # return a malloc'ed grpc_ssl_pem_key_cert_pair from a _list_ of SslPemKeyCertPair 216 for pair in pem_key_cert_pairs: 217 if not isinstance(pair, SslPemKeyCertPair): 218 raise TypeError("expected pem_key_cert_pairs to be sequence of " 219 "SslPemKeyCertPair") 220 cdef size_t c_ssl_pem_key_cert_pairs_count = len(pem_key_cert_pairs) 221 cdef grpc_ssl_pem_key_cert_pair* c_ssl_pem_key_cert_pairs = NULL 222 with nogil: 223 c_ssl_pem_key_cert_pairs = ( 224 <grpc_ssl_pem_key_cert_pair *>gpr_malloc( 225 sizeof(grpc_ssl_pem_key_cert_pair) * c_ssl_pem_key_cert_pairs_count)) 226 for i in range(c_ssl_pem_key_cert_pairs_count): 227 c_ssl_pem_key_cert_pairs[i] = ( 228 (<SslPemKeyCertPair>pem_key_cert_pairs[i]).c_pair) 229 return c_ssl_pem_key_cert_pairs 230 231def server_credentials_ssl(pem_root_certs, pem_key_cert_pairs, 232 bint force_client_auth): 233 pem_root_certs = str_to_bytes(pem_root_certs) 234 pem_key_cert_pairs = list(pem_key_cert_pairs) 235 cdef ServerCredentials credentials = ServerCredentials() 236 credentials.references.append(pem_root_certs) 237 credentials.references.append(pem_key_cert_pairs) 238 cdef const char * c_pem_root_certs = _get_c_pem_root_certs(pem_root_certs) 239 credentials.c_ssl_pem_key_cert_pairs_count = len(pem_key_cert_pairs) 240 credentials.c_ssl_pem_key_cert_pairs = _create_c_ssl_pem_key_cert_pairs(pem_key_cert_pairs) 241 cdef grpc_ssl_server_certificate_config *c_cert_config = NULL 242 c_cert_config = grpc_ssl_server_certificate_config_create( 243 c_pem_root_certs, credentials.c_ssl_pem_key_cert_pairs, 244 credentials.c_ssl_pem_key_cert_pairs_count) 245 cdef grpc_ssl_server_credentials_options* c_options = NULL 246 # C-core assumes ownership of c_cert_config 247 c_options = grpc_ssl_server_credentials_create_options_using_config( 248 GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY 249 if force_client_auth else 250 GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE, 251 c_cert_config) 252 # C-core assumes ownership of c_options 253 credentials.c_credentials = grpc_ssl_server_credentials_create_with_options(c_options) 254 return credentials 255 256def server_certificate_config_ssl(pem_root_certs, pem_key_cert_pairs): 257 pem_root_certs = str_to_bytes(pem_root_certs) 258 pem_key_cert_pairs = list(pem_key_cert_pairs) 259 cdef ServerCertificateConfig cert_config = ServerCertificateConfig() 260 cert_config.references.append(pem_root_certs) 261 cert_config.references.append(pem_key_cert_pairs) 262 cert_config.c_pem_root_certs = _get_c_pem_root_certs(pem_root_certs) 263 cert_config.c_ssl_pem_key_cert_pairs_count = len(pem_key_cert_pairs) 264 cert_config.c_ssl_pem_key_cert_pairs = _create_c_ssl_pem_key_cert_pairs(pem_key_cert_pairs) 265 cert_config.c_cert_config = grpc_ssl_server_certificate_config_create( 266 cert_config.c_pem_root_certs, cert_config.c_ssl_pem_key_cert_pairs, 267 cert_config.c_ssl_pem_key_cert_pairs_count) 268 return cert_config 269 270def server_credentials_ssl_dynamic_cert_config(initial_cert_config, 271 cert_config_fetcher, 272 bint force_client_auth): 273 if not isinstance(initial_cert_config, grpc.ServerCertificateConfiguration): 274 raise TypeError( 275 'initial_cert_config must be a grpc.ServerCertificateConfiguration') 276 if not callable(cert_config_fetcher): 277 raise TypeError('cert_config_fetcher must be callable') 278 cdef ServerCredentials credentials = ServerCredentials() 279 credentials.initial_cert_config = initial_cert_config 280 credentials.cert_config_fetcher = cert_config_fetcher 281 cdef grpc_ssl_server_credentials_options* c_options = NULL 282 c_options = grpc_ssl_server_credentials_create_options_using_config_fetcher( 283 GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY 284 if force_client_auth else 285 GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE, 286 _server_cert_config_fetcher_wrapper, 287 <void*>credentials) 288 # C-core assumes ownership of c_options 289 credentials.c_credentials = grpc_ssl_server_credentials_create_with_options(c_options) 290 return credentials 291 292cdef grpc_ssl_certificate_config_reload_status _server_cert_config_fetcher_wrapper( 293 void* user_data, grpc_ssl_server_certificate_config **config) with gil: 294 # This is a credentials.ServerCertificateConfig 295 cdef ServerCertificateConfig cert_config = None 296 if not user_data: 297 raise ValueError('internal error: user_data must be specified') 298 credentials = <ServerCredentials>user_data 299 if not credentials.initial_cert_config_fetched: 300 # C-core is asking for the initial cert config 301 credentials.initial_cert_config_fetched = True 302 cert_config = credentials.initial_cert_config._certificate_configuration 303 else: 304 user_cb = credentials.cert_config_fetcher 305 try: 306 cert_config_wrapper = user_cb() 307 except Exception: 308 _LOGGER.exception('Error fetching certificate config') 309 return GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL 310 if cert_config_wrapper is None: 311 return GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED 312 elif not isinstance( 313 cert_config_wrapper, grpc.ServerCertificateConfiguration): 314 _LOGGER.error( 315 'Error fetching certificate configuration: certificate ' 316 'configuration must be of type grpc.ServerCertificateConfiguration, ' 317 'not %s' % type(cert_config_wrapper).__name__) 318 return GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL 319 else: 320 cert_config = cert_config_wrapper._certificate_configuration 321 config[0] = <grpc_ssl_server_certificate_config*>cert_config.c_cert_config 322 # our caller will assume ownership of memory, so we have to recreate 323 # a copy of c_cert_config here 324 cert_config.c_cert_config = grpc_ssl_server_certificate_config_create( 325 cert_config.c_pem_root_certs, cert_config.c_ssl_pem_key_cert_pairs, 326 cert_config.c_ssl_pem_key_cert_pairs_count) 327 return GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW 328 329