• 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
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