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