• 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   PHP_GRPC_MAKE_STD_ZVAL(retval);
162   state->fci->params = arg;
163   state->fci->retval = retval;
164   state->fci->param_count = 1;
165 
166   PHP_GRPC_DELREF(arg);
167 
168   gpr_log(GPR_INFO, "GRPC_PHP: call credentials plugin function - begin");
169   /* call the user callback function */
170   zend_call_function(state->fci, state->fci_cache TSRMLS_CC);
171   gpr_log(GPR_INFO, "GRPC_PHP: call credentials plugin function - end");
172 
173   *num_creds_md = 0;
174   *status = GRPC_STATUS_OK;
175   *error_details = NULL;
176 
177   bool should_return = false;
178   grpc_metadata_array metadata;
179 
180   if (retval == NULL || Z_TYPE_P(retval) != IS_ARRAY) {
181     *status = GRPC_STATUS_INVALID_ARGUMENT;
182     should_return = true;  // Synchronous return.
183   }
184   if (!create_metadata_array(retval, &metadata)) {
185     *status = GRPC_STATUS_INVALID_ARGUMENT;
186     should_return = true;  // Synchronous return.
187     grpc_php_metadata_array_destroy_including_entries(&metadata);
188   }
189 
190   if (retval != NULL) {
191     zval_ptr_dtor(arg);
192     zval_ptr_dtor(retval);
193     PHP_GRPC_FREE_STD_ZVAL(arg);
194     PHP_GRPC_FREE_STD_ZVAL(retval);
195   }
196   if (should_return) {
197     return true;
198   }
199 
200   if (metadata.count > GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX) {
201     *status = GRPC_STATUS_INTERNAL;
202     *error_details = gpr_strdup(
203         "PHP plugin credentials returned too many metadata entries");
204     for (size_t i = 0; i < metadata.count; i++) {
205       // TODO(stanleycheung): Why don't we need to unref the key here?
206       grpc_slice_unref(metadata.metadata[i].value);
207     }
208   } else {
209     // Return data to core.
210     *num_creds_md = metadata.count;
211     for (size_t i = 0; i < metadata.count; ++i) {
212       creds_md[i] = metadata.metadata[i];
213     }
214   }
215 
216   grpc_metadata_array_destroy(&metadata);
217   return true;  // Synchronous return.
218 }
219 
220 /* Cleanup function for plugin creds API */
plugin_destroy_state(void * ptr)221 void plugin_destroy_state(void *ptr) {
222   plugin_state *state = (plugin_state *)ptr;
223   free(state->fci);
224   free(state->fci_cache);
225   free(state);
226 }
227 
228 ZEND_BEGIN_ARG_INFO_EX(arginfo_createComposite, 0, 0, 2)
229   ZEND_ARG_INFO(0, creds1)
230   ZEND_ARG_INFO(0, creds2)
231 ZEND_END_ARG_INFO()
232 
233 ZEND_BEGIN_ARG_INFO_EX(arginfo_createFromPlugin, 0, 0, 1)
234   ZEND_ARG_INFO(0, callback)
235 ZEND_END_ARG_INFO()
236 
237 static zend_function_entry call_credentials_methods[] = {
238   PHP_ME(CallCredentials, createComposite, arginfo_createComposite,
239          ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
240   PHP_ME(CallCredentials, createFromPlugin, arginfo_createFromPlugin,
241          ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
242   PHP_FE_END
243 };
244 
grpc_init_call_credentials(TSRMLS_D)245 void grpc_init_call_credentials(TSRMLS_D) {
246   zend_class_entry ce;
247   INIT_CLASS_ENTRY(ce, "Grpc\\CallCredentials", call_credentials_methods);
248   ce.create_object = create_wrapped_grpc_call_credentials;
249   grpc_ce_call_credentials = zend_register_internal_class(&ce TSRMLS_CC);
250   PHP_GRPC_INIT_HANDLER(wrapped_grpc_call_credentials,
251                         call_credentials_ce_handlers);
252 }
253