Imported Upstream version 1.36.0
[platform/upstream/grpc.git] / src / python / grpcio / grpc / _cython / _cygrpc / credentials.pyx.pxi
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
16 def _spawn_callback_in_thread(cb_func, args):
17   t = ForkManagedThread(target=cb_func, args=args)
18   t.setDaemon(True)
19   t.start()
20
21 async_callback_func = _spawn_callback_in_thread
22
23 def set_async_callback_func(callback_func):
24   global async_callback_func
25   async_callback_func = callback_func
26
27 def _spawn_callback_async(callback, args):
28   async_callback_func(callback, args)
29
30
31 cdef class CallCredentials:
32
33   cdef grpc_call_credentials *c(self) except *:
34     raise NotImplementedError()
35
36
37 cdef 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
59 cdef void _destroy(void *state) except * with gil:
60   cpython.Py_DECREF(<object>state)
61   grpc_shutdown()
62
63
64 cdef 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
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
97   return c_composition
98
99
100 cdef 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
109 cdef class ChannelCredentials:
110
111   cdef grpc_channel_credentials *c(self) except *:
112     raise NotImplementedError()
113
114
115 cdef 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
130 cdef 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
162 cdef 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
181 cdef 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
193 cdef 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
208 cdef 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
223 cdef 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
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 "
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
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,
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
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)
283   return cert_config
284
285 def 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
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
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
345 class LocalConnectionType:
346   uds = UDS
347   local_tcp = LOCAL_TCP
348
349 cdef 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
359 def channel_credentials_local(grpc_local_connect_type local_connect_type):
360   return LocalChannelCredentials(local_connect_type)
361
362 cdef class InsecureChannelCredentials(ChannelCredentials):
363
364   cdef grpc_channel_credentials *c(self) except *:
365     return grpc_insecure_credentials_create()
366
367 def channel_credentials_insecure():
368   return InsecureChannelCredentials()
369
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)
373   return credentials
374
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.
381   return credentials
382
383 def insecure_server_credentials():
384   cdef ServerCredentials credentials = ServerCredentials()
385   credentials.c_credentials = grpc_insecure_server_credentials_create()
386   return credentials
387
388 cdef 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
404 def channel_credentials_alts(list service_accounts):
405   return ALTSChannelCredentials(service_accounts)
406
407
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)
414   return credentials
415
416
417 cdef 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
432 def channel_credentials_compute_engine(call_creds):
433   return ComputeEngineChannelCredentials(call_creds)