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