1 # Copyright 2015 gRPC authors.
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
16 def _spawn_callback_in_thread(cb_func, args):
17 t = ForkManagedThread(target=cb_func, args=args)
21 async_callback_func = _spawn_callback_in_thread
23 def set_async_callback_func(callback_func):
24 global async_callback_func
25 async_callback_func = callback_func
27 def _spawn_callback_async(callback, args):
28 async_callback_func(callback, args)
31 cdef class CallCredentials:
33 cdef grpc_call_credentials *c(self) except *:
34 raise NotImplementedError()
37 cdef int _get_metadata(void *state,
38 grpc_auth_metadata_context context,
39 grpc_credentials_plugin_metadata_cb cb,
41 grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
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)
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
59 cdef void _destroy(void *state) except * with gil:
60 cpython.Py_DECREF(<object>state)
64 cdef class MetadataPluginCallCredentials(CallCredentials):
66 def __cinit__(self, metadata_plugin, name):
67 self._metadata_plugin = metadata_plugin
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)
83 cdef 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
100 cdef class CompositeCallCredentials(CallCredentials):
102 def __cinit__(self, call_credentialses):
103 self._call_credentialses = call_credentialses
105 cdef grpc_call_credentials *c(self) except *:
106 return _composition(self._call_credentialses)
109 cdef class ChannelCredentials:
111 cdef grpc_channel_credentials *c(self) except *:
112 raise NotImplementedError()
115 cdef class SSLSessionCacheLRU:
117 def __cinit__(self, capacity):
118 fork_handlers_and_grpc_init()
119 self._cache = grpc_ssl_session_cache_create_lru(capacity)
122 return <uintptr_t>self._cache
124 def __dealloc__(self):
125 if self._cache != NULL:
126 grpc_ssl_session_cache_destroy(self._cache)
130 cdef class SSLChannelCredentials(ChannelCredentials):
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
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
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)
150 if self._private_key:
151 c_pem_key_certificate_pair.private_key = self._private_key
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
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)
162 cdef class CompositeChannelCredentials(ChannelCredentials):
164 def __cinit__(self, call_credentialses, channel_credentials):
165 self._call_credentialses = call_credentialses
166 self._channel_credentials = channel_credentials
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)
181 cdef class XDSChannelCredentials(ChannelCredentials):
183 def __cinit__(self, fallback_credentials):
184 self._fallback_credentials = fallback_credentials
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)
193 cdef class ServerCertificateConfig:
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
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)
208 cdef class ServerCredentials:
211 fork_handlers_and_grpc_init()
212 self.c_credentials = NULL
214 self.initial_cert_config = None
215 self.cert_config_fetcher = None
216 self.initial_cert_config_fetched = False
218 def __dealloc__(self):
219 if self.c_credentials != NULL:
220 grpc_server_credentials_release(self.c_credentials)
223 cdef const char* _get_c_pem_root_certs(pem_root_certs):
224 if pem_root_certs is None:
227 return pem_root_certs
229 cdef 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 "
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
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
246 def 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,
267 # C-core assumes ownership of c_options
268 credentials.c_credentials = grpc_ssl_server_credentials_create_with_options(c_options)
271 def 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)
285 def server_credentials_ssl_dynamic_cert_config(initial_cert_config,
287 bint force_client_auth):
288 if not isinstance(initial_cert_config, grpc.ServerCertificateConfiguration):
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,
303 # C-core assumes ownership of c_options
304 credentials.c_credentials = grpc_ssl_server_credentials_create_with_options(c_options)
307 cdef 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
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
319 user_cb = credentials.cert_config_fetcher
321 cert_config_wrapper = user_cb()
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
328 cert_config_wrapper, grpc.ServerCertificateConfiguration):
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
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
345 class LocalConnectionType:
347 local_tcp = LOCAL_TCP
349 cdef class LocalChannelCredentials(ChannelCredentials):
351 def __cinit__(self, grpc_local_connect_type local_connect_type):
352 self._local_connect_type = local_connect_type
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)
359 def channel_credentials_local(grpc_local_connect_type local_connect_type):
360 return LocalChannelCredentials(local_connect_type)
362 cdef class InsecureChannelCredentials(ChannelCredentials):
364 cdef grpc_channel_credentials *c(self) except *:
365 return grpc_insecure_credentials_create()
367 def channel_credentials_insecure():
368 return InsecureChannelCredentials()
370 def 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)
375 def 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.
383 def insecure_server_credentials():
384 cdef ServerCredentials credentials = ServerCredentials()
385 credentials.c_credentials = grpc_insecure_server_credentials_create()
388 cdef class ALTSChannelCredentials(ChannelCredentials):
390 def __cinit__(self, list service_accounts):
391 self.c_options = grpc_alts_credentials_client_options_create()
393 for account in service_accounts:
394 grpc_alts_credentials_client_options_add_target_service_account(self.c_options, account)
396 def __dealloc__(self):
397 if self.c_options != NULL:
398 grpc_alts_credentials_options_destroy(self.c_options)
400 cdef grpc_channel_credentials *c(self) except *:
401 return grpc_alts_credentials_create(self.c_options)
404 def channel_credentials_alts(list service_accounts):
405 return ALTSChannelCredentials(service_accounts)
408 def 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)
417 cdef class ComputeEngineChannelCredentials(ChannelCredentials):
418 cdef grpc_channel_credentials* _c_creds
419 cdef grpc_call_credentials* _call_creds
421 def __cinit__(self, CallCredentials call_creds):
423 self._call_creds = call_creds.c()
424 if self._call_creds == NULL:
425 raise ValueError("Call credentials may not be NULL.")
427 cdef grpc_channel_credentials *c(self) except *:
428 self._c_creds = grpc_google_default_credentials_create(self._call_creds)
432 def channel_credentials_compute_engine(call_creds):
433 return ComputeEngineChannelCredentials(call_creds)