• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 /**
20  * class CallCredentials
21  * @see https://github.com/grpc/grpc/tree/master/src/php/ext/grpc/call_credentials.c
22  */
23 
24 #include "call_credentials.h"
25 
26 #include <ext/spl/spl_exceptions.h>
27 #include <zend_exceptions.h>
28 
29 #include <grpc/support/log.h>
30 #include <grpc/support/string_util.h>
31 
32 #include "call.h"
33 
34 zend_class_entry *grpc_ce_call_credentials;
35 PHP_GRPC_DECLARE_OBJECT_HANDLER(call_credentials_ce_handlers)
36 
37 /* Frees and destroys an instance of wrapped_grpc_call_credentials */
38 PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_call_credentials)
39   if (p->wrapped != NULL) {
40     grpc_call_credentials_release(p->wrapped);
41   }
PHP_GRPC_FREE_WRAPPED_FUNC_END()42 PHP_GRPC_FREE_WRAPPED_FUNC_END()
43 
44 /* Initializes an instance of wrapped_grpc_call_credentials to be
45  * associated with an object of a class specified by class_type */
46 php_grpc_zend_object create_wrapped_grpc_call_credentials(
47     zend_class_entry *class_type TSRMLS_DC) {
48   PHP_GRPC_ALLOC_CLASS_OBJECT(wrapped_grpc_call_credentials);
49   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
50   object_properties_init(&intern->std, class_type);
51   PHP_GRPC_FREE_CLASS_OBJECT(wrapped_grpc_call_credentials,
52                              call_credentials_ce_handlers);
53 }
54 
grpc_php_wrap_call_credentials(grpc_call_credentials * wrapped TSRMLS_DC)55 zval *grpc_php_wrap_call_credentials(grpc_call_credentials
56                                      *wrapped TSRMLS_DC) {
57   zval *credentials_object;
58   PHP_GRPC_MAKE_STD_ZVAL(credentials_object);
59   object_init_ex(credentials_object, grpc_ce_call_credentials);
60   wrapped_grpc_call_credentials *credentials =
61     PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_call_credentials,
62                                 credentials_object);
63   credentials->wrapped = wrapped;
64   return credentials_object;
65 }
66 
67 /**
68  * Create composite credentials from two existing credentials.
69  * @param CallCredentials $cred1_obj The first credential
70  * @param CallCredentials $cred2_obj The second credential
71  * @return CallCredentials The new composite credentials object
72  */
PHP_METHOD(CallCredentials,createComposite)73 PHP_METHOD(CallCredentials, createComposite) {
74   zval *cred1_obj;
75   zval *cred2_obj;
76 
77   /* "OO" == 2 Objects */
78   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OO", &cred1_obj,
79                             grpc_ce_call_credentials, &cred2_obj,
80                             grpc_ce_call_credentials) == FAILURE) {
81     zend_throw_exception(spl_ce_InvalidArgumentException,
82                          "createComposite expects 2 CallCredentials",
83                          1 TSRMLS_CC);
84     return;
85   }
86   wrapped_grpc_call_credentials *cred1 =
87     PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_call_credentials, cred1_obj);
88   wrapped_grpc_call_credentials *cred2 =
89     PHP_GRPC_GET_WRAPPED_OBJECT(wrapped_grpc_call_credentials, cred2_obj);
90   grpc_call_credentials *creds =
91     grpc_composite_call_credentials_create(cred1->wrapped, cred2->wrapped,
92                                            NULL);
93   zval *creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
94   RETURN_DESTROY_ZVAL(creds_object);
95 }
96 
97 /**
98  * Create a call credentials object from the plugin API
99  * @param function $fci The callback function
100  * @return CallCredentials The new call credentials object
101  */
PHP_METHOD(CallCredentials,createFromPlugin)102 PHP_METHOD(CallCredentials, createFromPlugin) {
103   zend_fcall_info *fci;
104   zend_fcall_info_cache *fci_cache;
105 
106   fci = (zend_fcall_info *)malloc(sizeof(zend_fcall_info));
107   fci_cache = (zend_fcall_info_cache *)malloc(sizeof(zend_fcall_info_cache));
108   memset(fci, 0, sizeof(zend_fcall_info));
109   memset(fci_cache, 0, sizeof(zend_fcall_info_cache));
110 
111   /* "f" == 1 function */
112   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "f*", fci, fci_cache,
113                             fci->params, fci->param_count) == FAILURE) {
114     zend_throw_exception(spl_ce_InvalidArgumentException,
115                          "createFromPlugin expects 1 callback", 1 TSRMLS_CC);
116     free(fci);
117     free(fci_cache);
118     return;
119   }
120 
121   plugin_state *state;
122   state = (plugin_state *)malloc(sizeof(plugin_state));
123   memset(state, 0, sizeof(plugin_state));
124 
125   /* save the user provided PHP callback function */
126   state->fci = fci;
127   state->fci_cache = fci_cache;
128 
129   grpc_metadata_credentials_plugin plugin;
130   plugin.get_metadata = plugin_get_metadata;
131   plugin.destroy = plugin_destroy_state;
132   plugin.state = (void *)state;
133   plugin.type = "";
134   // TODO(yihuazhang): Expose min_security_level via the PHP API so that
135   // applications can decide what minimum security level their plugins require.
136   grpc_call_credentials *creds =
137     grpc_metadata_credentials_create_from_plugin(plugin, GRPC_PRIVACY_AND_INTEGRITY, NULL);
138   zval *creds_object = grpc_php_wrap_call_credentials(creds TSRMLS_CC);
139   RETURN_DESTROY_ZVAL(creds_object);
140 }
141 
142 /* Callback function for plugin creds API */
plugin_get_metadata(void * ptr,grpc_auth_metadata_context context,grpc_credentials_plugin_metadata_cb cb,void * user_data,grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],size_t * num_creds_md,grpc_status_code * status,const char ** error_details)143 int plugin_get_metadata(
144     void *ptr, grpc_auth_metadata_context context,
145     grpc_credentials_plugin_metadata_cb cb, void *user_data,
146     grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX],
147     size_t *num_creds_md, grpc_status_code *status,
148     const char **error_details) {
149   TSRMLS_FETCH();
150 
151   plugin_state *state = (plugin_state *)ptr;
152 
153   /* prepare to call the user callback function with info from the
154    * grpc_auth_metadata_context */
155   zval *arg;
156   PHP_GRPC_MAKE_STD_ZVAL(arg);
157   object_init(arg);
158   php_grpc_add_property_string(arg, "service_url", context.service_url, true);
159   php_grpc_add_property_string(arg, "method_name", context.method_name, true);
160   zval *retval = NULL;
161 #if PHP_MAJOR_VERSION < 7
162   zval **params[1];
163   params[0] = &arg;
164   state->fci->params = params;
165   state->fci->retval_ptr_ptr = &retval;
166 #else
167   PHP_GRPC_MAKE_STD_ZVAL(retval);
168   state->fci->params = arg;
169   state->fci->retval = retval;
170 #endif
171   state->fci->param_count = 1;
172 
173   PHP_GRPC_DELREF(arg);
174 
175   gpr_log(GPR_INFO, "GRPC_PHP: call credentials plugin function - begin");
176   /* call the user callback function */
177   zend_call_function(state->fci, state->fci_cache TSRMLS_CC);
178   gpr_log(GPR_INFO, "GRPC_PHP: call credentials plugin function - end");
179 
180   *num_creds_md = 0;
181   *status = GRPC_STATUS_OK;
182   *error_details = NULL;
183 
184   bool should_return = false;
185   grpc_metadata_array metadata;
186 
187   if (retval == NULL || Z_TYPE_P(retval) != IS_ARRAY) {
188     *status = GRPC_STATUS_INVALID_ARGUMENT;
189     should_return = true;  // Synchronous return.
190   }
191   if (!create_metadata_array(retval, &metadata)) {
192     *status = GRPC_STATUS_INVALID_ARGUMENT;
193     should_return = true;  // Synchronous return.
194     grpc_php_metadata_array_destroy_including_entries(&metadata);
195   }
196 
197   if (retval != NULL) {
198 #if PHP_MAJOR_VERSION < 7
199     zval_ptr_dtor(&retval);
200 #else
201     zval_ptr_dtor(arg);
202     zval_ptr_dtor(retval);
203     PHP_GRPC_FREE_STD_ZVAL(arg);
204     PHP_GRPC_FREE_STD_ZVAL(retval);
205 #endif
206   }
207   if (should_return) {
208     return true;
209   }
210 
211   if (metadata.count > GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX) {
212     *status = GRPC_STATUS_INTERNAL;
213     *error_details = gpr_strdup(
214         "PHP plugin credentials returned too many metadata entries");
215     for (size_t i = 0; i < metadata.count; i++) {
216       // TODO(stanleycheung): Why don't we need to unref the key here?
217       grpc_slice_unref(metadata.metadata[i].value);
218     }
219   } else {
220     // Return data to core.
221     *num_creds_md = metadata.count;
222     for (size_t i = 0; i < metadata.count; ++i) {
223       creds_md[i] = metadata.metadata[i];
224     }
225   }
226 
227   grpc_metadata_array_destroy(&metadata);
228   return true;  // Synchronous return.
229 }
230 
231 /* Cleanup function for plugin creds API */
plugin_destroy_state(void * ptr)232 void plugin_destroy_state(void *ptr) {
233   plugin_state *state = (plugin_state *)ptr;
234   free(state->fci);
235   free(state->fci_cache);
236 #if PHP_MAJOR_VERSION < 7
237   PHP_GRPC_FREE_STD_ZVAL(state->fci->params);
238   PHP_GRPC_FREE_STD_ZVAL(state->fci->retval);
239 #endif
240   free(state);
241 }
242 
243 ZEND_BEGIN_ARG_INFO_EX(arginfo_createComposite, 0, 0, 2)
244   ZEND_ARG_INFO(0, creds1)
245   ZEND_ARG_INFO(0, creds2)
246 ZEND_END_ARG_INFO()
247 
248 ZEND_BEGIN_ARG_INFO_EX(arginfo_createFromPlugin, 0, 0, 1)
249   ZEND_ARG_INFO(0, callback)
250 ZEND_END_ARG_INFO()
251 
252 static zend_function_entry call_credentials_methods[] = {
253   PHP_ME(CallCredentials, createComposite, arginfo_createComposite,
254          ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
255   PHP_ME(CallCredentials, createFromPlugin, arginfo_createFromPlugin,
256          ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
257   PHP_FE_END
258 };
259 
grpc_init_call_credentials(TSRMLS_D)260 void grpc_init_call_credentials(TSRMLS_D) {
261   zend_class_entry ce;
262   INIT_CLASS_ENTRY(ce, "Grpc\\CallCredentials", call_credentials_methods);
263   ce.create_object = create_wrapped_grpc_call_credentials;
264   grpc_ce_call_credentials = zend_register_internal_class(&ce TSRMLS_CC);
265   PHP_GRPC_INIT_HANDLER(wrapped_grpc_call_credentials,
266                         call_credentials_ce_handlers);
267 }
268