• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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