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 15 16def _spawn_callback_in_thread(cb_func, args): 17 t = ForkManagedThread(target=cb_func, args=args) 18 t.setDaemon(True) 19 t.start() 20 21async_callback_func = _spawn_callback_in_thread 22 23def set_async_callback_func(callback_func): 24 global async_callback_func 25 async_callback_func = callback_func 26 27def _spawn_callback_async(callback, args): 28 async_callback_func(callback, args) 29 30 31cdef class CallCredentials: 32 33 cdef grpc_call_credentials *c(self) except *: 34 raise NotImplementedError() 35 36 37cdef int _get_metadata(void *state, 38 grpc_auth_metadata_context context, 39 grpc_credentials_plugin_metadata_cb cb, 40 void *user_data, 41 grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX], 42 size_t *num_creds_md, 43 grpc_status_code *status, 44 const char **error_details) except * with gil: 45 cdef size_t metadata_count 46 cdef grpc_metadata *c_metadata 47 def callback(metadata, grpc_status_code status, bytes error_details): 48 cdef char* c_error_details = NULL 49 if error_details is not None: 50 c_error_details = <char*> error_details 51 if status == StatusCode.ok: 52 _store_c_metadata(metadata, &c_metadata, &metadata_count) 53 with nogil: 54 cb(user_data, c_metadata, metadata_count, status, NULL) 55 _release_c_metadata(c_metadata, metadata_count) 56 else: 57 with nogil: 58 cb(user_data, NULL, 0, status, c_error_details) 59 args = context.service_url, context.method_name, callback, 60 plugin = <object>state 61 if plugin._stored_ctx is not None: 62 plugin._stored_ctx.copy().run(_spawn_callback_async, plugin, args) 63 else: 64 _spawn_callback_async(<object>state, args) 65 return 0 # Asynchronous return 66 67 68cdef void _destroy(void *state) except * with gil: 69 cpython.Py_DECREF(<object>state) 70 grpc_shutdown() 71 72 73cdef class MetadataPluginCallCredentials(CallCredentials): 74 75 def __cinit__(self, metadata_plugin, name): 76 self._metadata_plugin = metadata_plugin 77 self._name = name 78 79 cdef grpc_call_credentials *c(self) except *: 80 cdef grpc_metadata_credentials_plugin c_metadata_plugin 81 c_metadata_plugin.get_metadata = _get_metadata 82 c_metadata_plugin.destroy = _destroy 83 c_metadata_plugin.state = <void *>self._metadata_plugin 84 c_metadata_plugin.type = self._name 85 cpython.Py_INCREF(self._metadata_plugin) 86 fork_handlers_and_grpc_init() 87 # TODO(yihuazhang): Expose min_security_level via the Python API so that 88 # applications can decide what minimum security level their plugins require. 89 return grpc_metadata_credentials_create_from_plugin(c_metadata_plugin, GRPC_PRIVACY_AND_INTEGRITY, NULL) 90 91 92cdef grpc_call_credentials *_composition(call_credentialses): 93 call_credentials_iterator = iter(call_credentialses) 94 cdef CallCredentials composition = next(call_credentials_iterator) 95 cdef grpc_call_credentials *c_composition = composition.c() 96 cdef CallCredentials additional_call_credentials 97 cdef grpc_call_credentials *c_additional_call_credentials 98 cdef grpc_call_credentials *c_next_composition 99 for additional_call_credentials in call_credentials_iterator: 100 c_additional_call_credentials = additional_call_credentials.c() 101 c_next_composition = grpc_composite_call_credentials_create( 102 c_composition, c_additional_call_credentials, NULL) 103 grpc_call_credentials_release(c_composition) 104 grpc_call_credentials_release(c_additional_call_credentials) 105 c_composition = c_next_composition 106 return c_composition 107 108 109cdef class CompositeCallCredentials(CallCredentials): 110 111 def __cinit__(self, call_credentialses): 112 self._call_credentialses = call_credentialses 113 114 cdef grpc_call_credentials *c(self) except *: 115 return _composition(self._call_credentialses) 116 117 118cdef class ChannelCredentials: 119 120 cdef grpc_channel_credentials *c(self) except *: 121 raise NotImplementedError() 122 123 124cdef class SSLSessionCacheLRU: 125 126 def __cinit__(self, capacity): 127 fork_handlers_and_grpc_init() 128 self._cache = grpc_ssl_session_cache_create_lru(capacity) 129 130 def __int__(self): 131 return <uintptr_t>self._cache 132 133 def __dealloc__(self): 134 if self._cache != NULL: 135 grpc_ssl_session_cache_destroy(self._cache) 136 grpc_shutdown() 137 138 139cdef class SSLChannelCredentials(ChannelCredentials): 140 141 def __cinit__(self, pem_root_certificates, private_key, certificate_chain): 142 if pem_root_certificates is not None and not isinstance(pem_root_certificates, bytes): 143 raise TypeError('expected certificate to be bytes, got %s' % (type(pem_root_certificates))) 144 self._pem_root_certificates = pem_root_certificates 145 self._private_key = private_key 146 self._certificate_chain = certificate_chain 147 148 cdef grpc_channel_credentials *c(self) except *: 149 cdef const char *c_pem_root_certificates 150 cdef grpc_ssl_pem_key_cert_pair c_pem_key_certificate_pair 151 if self._pem_root_certificates is None: 152 c_pem_root_certificates = NULL 153 else: 154 c_pem_root_certificates = self._pem_root_certificates 155 if self._private_key is None and self._certificate_chain is None: 156 with nogil: 157 return grpc_ssl_credentials_create( 158 c_pem_root_certificates, NULL, NULL, NULL) 159 else: 160 if self._private_key: 161 c_pem_key_certificate_pair.private_key = self._private_key 162 else: 163 c_pem_key_certificate_pair.private_key = NULL 164 if self._certificate_chain: 165 c_pem_key_certificate_pair.certificate_chain = self._certificate_chain 166 else: 167 c_pem_key_certificate_pair.certificate_chain = NULL 168 with nogil: 169 return grpc_ssl_credentials_create( 170 c_pem_root_certificates, &c_pem_key_certificate_pair, NULL, NULL) 171 172 173cdef class CompositeChannelCredentials(ChannelCredentials): 174 175 def __cinit__(self, call_credentialses, channel_credentials): 176 self._call_credentialses = call_credentialses 177 self._channel_credentials = channel_credentials 178 179 cdef grpc_channel_credentials *c(self) except *: 180 cdef grpc_channel_credentials *c_channel_credentials 181 c_channel_credentials = self._channel_credentials.c() 182 cdef grpc_call_credentials *c_call_credentials_composition = _composition( 183 self._call_credentialses) 184 cdef grpc_channel_credentials *composition 185 c_composition = grpc_composite_channel_credentials_create( 186 c_channel_credentials, c_call_credentials_composition, NULL) 187 grpc_channel_credentials_release(c_channel_credentials) 188 grpc_call_credentials_release(c_call_credentials_composition) 189 return c_composition 190 191 192cdef class XDSChannelCredentials(ChannelCredentials): 193 194 def __cinit__(self, fallback_credentials): 195 self._fallback_credentials = fallback_credentials 196 197 cdef grpc_channel_credentials *c(self) except *: 198 cdef grpc_channel_credentials *c_fallback_creds = self._fallback_credentials.c() 199 cdef grpc_channel_credentials *xds_creds = grpc_xds_credentials_create(c_fallback_creds) 200 grpc_channel_credentials_release(c_fallback_creds) 201 return xds_creds 202 203 204cdef class ServerCertificateConfig: 205 206 def __cinit__(self): 207 fork_handlers_and_grpc_init() 208 self.c_cert_config = NULL 209 self.c_pem_root_certs = NULL 210 self.c_ssl_pem_key_cert_pairs = NULL 211 self.references = [] 212 213 def __dealloc__(self): 214 grpc_ssl_server_certificate_config_destroy(self.c_cert_config) 215 gpr_free(self.c_ssl_pem_key_cert_pairs) 216 grpc_shutdown() 217 218 219cdef class ServerCredentials: 220 221 def __cinit__(self): 222 fork_handlers_and_grpc_init() 223 self.c_credentials = NULL 224 self.references = [] 225 self.initial_cert_config = None 226 self.cert_config_fetcher = None 227 self.initial_cert_config_fetched = False 228 229 def __dealloc__(self): 230 if self.c_credentials != NULL: 231 grpc_server_credentials_release(self.c_credentials) 232 grpc_shutdown() 233 234cdef const char* _get_c_pem_root_certs(pem_root_certs): 235 if pem_root_certs is None: 236 return NULL 237 else: 238 return pem_root_certs 239 240cdef grpc_ssl_pem_key_cert_pair* _create_c_ssl_pem_key_cert_pairs(pem_key_cert_pairs): 241 # return a malloc'ed grpc_ssl_pem_key_cert_pair from a _list_ of SslPemKeyCertPair 242 for pair in pem_key_cert_pairs: 243 if not isinstance(pair, SslPemKeyCertPair): 244 raise TypeError("expected pem_key_cert_pairs to be sequence of " 245 "SslPemKeyCertPair") 246 cdef size_t c_ssl_pem_key_cert_pairs_count = len(pem_key_cert_pairs) 247 cdef grpc_ssl_pem_key_cert_pair* c_ssl_pem_key_cert_pairs = NULL 248 with nogil: 249 c_ssl_pem_key_cert_pairs = ( 250 <grpc_ssl_pem_key_cert_pair *>gpr_malloc( 251 sizeof(grpc_ssl_pem_key_cert_pair) * c_ssl_pem_key_cert_pairs_count)) 252 for i in range(c_ssl_pem_key_cert_pairs_count): 253 c_ssl_pem_key_cert_pairs[i] = ( 254 (<SslPemKeyCertPair>pem_key_cert_pairs[i]).c_pair) 255 return c_ssl_pem_key_cert_pairs 256 257def server_credentials_ssl(pem_root_certs, pem_key_cert_pairs, 258 bint force_client_auth): 259 pem_root_certs = str_to_bytes(pem_root_certs) 260 pem_key_cert_pairs = list(pem_key_cert_pairs) 261 cdef ServerCredentials credentials = ServerCredentials() 262 credentials.references.append(pem_root_certs) 263 credentials.references.append(pem_key_cert_pairs) 264 cdef const char * c_pem_root_certs = _get_c_pem_root_certs(pem_root_certs) 265 credentials.c_ssl_pem_key_cert_pairs_count = len(pem_key_cert_pairs) 266 credentials.c_ssl_pem_key_cert_pairs = _create_c_ssl_pem_key_cert_pairs(pem_key_cert_pairs) 267 cdef grpc_ssl_server_certificate_config *c_cert_config = NULL 268 c_cert_config = grpc_ssl_server_certificate_config_create( 269 c_pem_root_certs, credentials.c_ssl_pem_key_cert_pairs, 270 credentials.c_ssl_pem_key_cert_pairs_count) 271 cdef grpc_ssl_server_credentials_options* c_options = NULL 272 # C-core assumes ownership of c_cert_config 273 c_options = grpc_ssl_server_credentials_create_options_using_config( 274 GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY 275 if force_client_auth else 276 GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE, 277 c_cert_config) 278 # C-core assumes ownership of c_options 279 credentials.c_credentials = grpc_ssl_server_credentials_create_with_options(c_options) 280 return credentials 281 282def server_certificate_config_ssl(pem_root_certs, pem_key_cert_pairs): 283 pem_root_certs = str_to_bytes(pem_root_certs) 284 pem_key_cert_pairs = list(pem_key_cert_pairs) 285 cdef ServerCertificateConfig cert_config = ServerCertificateConfig() 286 cert_config.references.append(pem_root_certs) 287 cert_config.references.append(pem_key_cert_pairs) 288 cert_config.c_pem_root_certs = _get_c_pem_root_certs(pem_root_certs) 289 cert_config.c_ssl_pem_key_cert_pairs_count = len(pem_key_cert_pairs) 290 cert_config.c_ssl_pem_key_cert_pairs = _create_c_ssl_pem_key_cert_pairs(pem_key_cert_pairs) 291 cert_config.c_cert_config = grpc_ssl_server_certificate_config_create( 292 cert_config.c_pem_root_certs, cert_config.c_ssl_pem_key_cert_pairs, 293 cert_config.c_ssl_pem_key_cert_pairs_count) 294 return cert_config 295 296def server_credentials_ssl_dynamic_cert_config(initial_cert_config, 297 cert_config_fetcher, 298 bint force_client_auth): 299 if not isinstance(initial_cert_config, grpc.ServerCertificateConfiguration): 300 raise TypeError( 301 'initial_cert_config must be a grpc.ServerCertificateConfiguration') 302 if not callable(cert_config_fetcher): 303 raise TypeError('cert_config_fetcher must be callable') 304 cdef ServerCredentials credentials = ServerCredentials() 305 credentials.initial_cert_config = initial_cert_config 306 credentials.cert_config_fetcher = cert_config_fetcher 307 cdef grpc_ssl_server_credentials_options* c_options = NULL 308 c_options = grpc_ssl_server_credentials_create_options_using_config_fetcher( 309 GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY 310 if force_client_auth else 311 GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE, 312 _server_cert_config_fetcher_wrapper, 313 <void*>credentials) 314 # C-core assumes ownership of c_options 315 credentials.c_credentials = grpc_ssl_server_credentials_create_with_options(c_options) 316 return credentials 317 318cdef grpc_ssl_certificate_config_reload_status _server_cert_config_fetcher_wrapper( 319 void* user_data, grpc_ssl_server_certificate_config **config) noexcept with gil: 320 # This is a credentials.ServerCertificateConfig 321 cdef ServerCertificateConfig cert_config = None 322 if not user_data: 323 raise ValueError('internal error: user_data must be specified') 324 credentials = <ServerCredentials>user_data 325 if not credentials.initial_cert_config_fetched: 326 # C-core is asking for the initial cert config 327 credentials.initial_cert_config_fetched = True 328 cert_config = credentials.initial_cert_config._certificate_configuration 329 else: 330 user_cb = credentials.cert_config_fetcher 331 try: 332 cert_config_wrapper = user_cb() 333 except Exception: 334 _LOGGER.exception('Error fetching certificate config') 335 return GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL 336 if cert_config_wrapper is None: 337 return GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED 338 elif not isinstance( 339 cert_config_wrapper, grpc.ServerCertificateConfiguration): 340 _LOGGER.error( 341 'Error fetching certificate configuration: certificate ' 342 'configuration must be of type grpc.ServerCertificateConfiguration, ' 343 'not %s' % type(cert_config_wrapper).__name__) 344 return GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL 345 else: 346 cert_config = cert_config_wrapper._certificate_configuration 347 config[0] = <grpc_ssl_server_certificate_config*>cert_config.c_cert_config 348 # our caller will assume ownership of memory, so we have to recreate 349 # a copy of c_cert_config here 350 cert_config.c_cert_config = grpc_ssl_server_certificate_config_create( 351 cert_config.c_pem_root_certs, cert_config.c_ssl_pem_key_cert_pairs, 352 cert_config.c_ssl_pem_key_cert_pairs_count) 353 return GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW 354 355 356class LocalConnectionType: 357 uds = UDS 358 local_tcp = LOCAL_TCP 359 360cdef class LocalChannelCredentials(ChannelCredentials): 361 362 def __cinit__(self, grpc_local_connect_type local_connect_type): 363 self._local_connect_type = local_connect_type 364 365 cdef grpc_channel_credentials *c(self) except *: 366 cdef grpc_local_connect_type local_connect_type 367 local_connect_type = self._local_connect_type 368 return grpc_local_credentials_create(local_connect_type) 369 370def channel_credentials_local(grpc_local_connect_type local_connect_type): 371 return LocalChannelCredentials(local_connect_type) 372 373cdef class InsecureChannelCredentials(ChannelCredentials): 374 375 cdef grpc_channel_credentials *c(self) except *: 376 return grpc_insecure_credentials_create() 377 378def channel_credentials_insecure(): 379 return InsecureChannelCredentials() 380 381def server_credentials_local(grpc_local_connect_type local_connect_type): 382 cdef ServerCredentials credentials = ServerCredentials() 383 credentials.c_credentials = grpc_local_server_credentials_create(local_connect_type) 384 return credentials 385 386def xds_server_credentials(ServerCredentials fallback_credentials): 387 cdef ServerCredentials credentials = ServerCredentials() 388 credentials.c_credentials = grpc_xds_server_credentials_create(fallback_credentials.c_credentials) 389 # NOTE: We do not need to call grpc_server_credentials_release on the 390 # fallback credentials here because this will be done by the __dealloc__ 391 # method of its Cython wrapper. 392 return credentials 393 394def insecure_server_credentials(): 395 cdef ServerCredentials credentials = ServerCredentials() 396 credentials.c_credentials = grpc_insecure_server_credentials_create() 397 return credentials 398 399cdef class ALTSChannelCredentials(ChannelCredentials): 400 401 def __cinit__(self, list service_accounts): 402 self.c_options = grpc_alts_credentials_client_options_create() 403 cdef str account 404 for account in service_accounts: 405 grpc_alts_credentials_client_options_add_target_service_account( 406 self.c_options, str_to_bytes(account)) 407 408 def __dealloc__(self): 409 if self.c_options != NULL: 410 grpc_alts_credentials_options_destroy(self.c_options) 411 412 cdef grpc_channel_credentials *c(self) except *: 413 return grpc_alts_credentials_create(self.c_options) 414 415 416def channel_credentials_alts(list service_accounts): 417 return ALTSChannelCredentials(service_accounts) 418 419 420def server_credentials_alts(): 421 cdef ServerCredentials credentials = ServerCredentials() 422 cdef grpc_alts_credentials_options* c_options = grpc_alts_credentials_server_options_create() 423 credentials.c_credentials = grpc_alts_server_credentials_create(c_options) 424 # Options can be destroyed as deep copy was performed. 425 grpc_alts_credentials_options_destroy(c_options) 426 return credentials 427 428 429cdef class ComputeEngineChannelCredentials(ChannelCredentials): 430 cdef grpc_channel_credentials* _c_creds 431 cdef grpc_call_credentials* _call_creds 432 433 def __cinit__(self, CallCredentials call_creds): 434 self._c_creds = NULL 435 self._call_creds = call_creds.c() 436 if self._call_creds == NULL: 437 raise ValueError("Call credentials may not be NULL.") 438 439 cdef grpc_channel_credentials *c(self) except *: 440 with nogil: 441 self._c_creds = grpc_google_default_credentials_create(self._call_creds) 442 return self._c_creds 443 444 445def channel_credentials_compute_engine(call_creds): 446 return ComputeEngineChannelCredentials(call_creds) 447