/[drupal]/contributions/modules/netforum/xwebSecureOD.class.inc
ViewVC logotype

Contents of /contributions/modules/netforum/xwebSecureOD.class.inc

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1 - (show annotations) (download) (as text)
Sun Aug 31 23:43:54 2008 UTC (14 months, 3 weeks ago) by jamesmichaelhill
Branch: MAIN
CVS Tags: DRUPAL-5--0-8, DRUPAL-5--0-9, DRUPAL-5--1-1, DRUPAL-5--1-0, HEAD
Branch point for: DRUPAL-6--2
File MIME type: text/x-php
Added support for netforum OD
1 <?php
2 // $Id$
3
4 /*
5 Drupal release
6 James Michael-Hill
7 www.netforumondrupal.com
8
9 xWebSecureOD Class - an extension of the php SoapClient class to provide for
10 seamless sliding token based authentication with Avectra's netFORUM On Demand / Team.
11
12 Developed under php 5.1.6/apache 2. PHP 5 is REQUIRED.
13
14 Where possible functionality is parallel to the regular SoapClient with the exception of the
15 constructor and the __soapCall() method - which will not take any soap headers.
16
17 The constructor requires xwebUserName and xwebUserPass to be set.
18 These can be your regular user name and password, but that is NOT RECOMMENDED. See the
19 Avectra documentation for best practices, but in a nutshell there should be a dedicated user, and the
20 password is set in the usr_pwd field of the fw_user table. For more examples see the included
21 xwebExample.php file.
22
23 Drupal Version:
24 This release is intended for use solely with the drupal CMS system.
25 Changes have been made to the database caching routines to work with the drupal framework. If you're
26 interested in using this class for other purposes please contact me or look for the official
27 xWebSecureOD class.
28
29 */
30 class xwebSecureClient extends SoapClient {
31 private $userName;
32 private $userPass;
33 private $authToken;
34 private $xwebNamespace;
35 private $overloadedWsdlFunctions= Array();
36 private $wsdlNonOverloadFunctions = Array('Authenticate');
37
38 //new for response caching
39 private $cacheExpireTime = ""; //the default is 4 hours ago, and it is set in the constructor
40 private $cachedFunctions = Array('GetFacadeObject',
41 'GetQuery',
42 'GetCustomerBalance',
43 'GetCustomerMembership',
44 'GetCustomerByZip',
45 'GetCustomerByCityState',
46 'GetCustomerByRecordDate',
47 'GetCustomerByName',
48 'GetCustomerById',
49 'GetCustomerEvent',
50 'GetCustomerSession',
51 'GetEventListByName',
52 'GetEventByKey',
53 'GetSessionListByName',
54 'GetSessionByKey',
55 'GetSessionListByEvent',
56 'GetEventCustomerList',
57 'GetSessionCustomerList',
58 'GetProductBalances',
59 'GetCommitteeByKey',
60 'GetCommitteeByCode',
61 'GetCommitteeListByCode',
62 'GetCommitteeListByCstId');
63 private $cacheWsdlLoc = "";
64 private $cachingOn = false;
65 private $cachedResponse = false;
66 private $responseFromCache = false;
67 private $useSha1 = true; //Set this to false if the sha1() function doesn't work on your system
68
69 private $offlineMode = false;
70
71 //for debugging purposes. Not perfect, but if something is going awry it gives some insight
72 public $log;
73
74 function __construct($wsdl, $options = null) {
75 if (isset($options['xwebUserName'], $options['xwebUserPass'])){
76 $this->userName = $options['xwebUserName'];
77 $this->userPass = $options['xwebUserPass'];
78 parent::__construct($wsdl, $options);
79 $this->setOverloadedWsdlFunctions();
80 $this->cacheWsdlLoc = $wsdl;
81 //fetch the stored auth token from drupal
82 //$this->authToken = variable_get('netforum_auth_token','');
83 }
84 else{
85 //throw constructor error if we don't have the needed parameters
86 throw new Exception("Invalid parameters in xwebSecureClient constructor: xwebUserName and xwebUserPass are required");
87 }
88 $this->cacheExpireTime = strftime("%Y-%m-%d %H:%M",strtotime("-4 hours"));
89 $this->log .= "Finished constructor\n";
90 }
91
92 function __call($method, $arguments){
93 //the _call method is executed for every method call in this class. We're using it to wrap every wsdl function call in the xweb authentication scheme
94
95 //we're only overloading the functions that the wsdl defines here, so check to see if it is in our list
96 if (in_array($method,$this->overloadedWsdlFunctions) && ! in_array($method, $this->wsdlNonOverloadFunctions)){
97 $this->log .= "Overloading the call to $method method\n";
98 //note that this is the overloaded soap call method that adds the auth tokens
99 return $this->__soapCall($method, $arguments);
100 }
101 }
102
103 function __soapCall($fname, $arguments=Array()){
104 //overload the soap call function to only take a wsdl function name and an array of arguments, inject our auth token, and save the response auth token
105 $this->log .= "Beginning __SoapCall\n";
106 $responseHeaders = '';
107 $this->cachedResponse = false;
108
109 if ($this->cachingOn === true ){
110 $response = $this->cacheRetreive($fname,$arguments);
111 if ($response){
112 $this->log .= "Returning cached response to call\n";
113 $this->cachedResponse = true;
114 return $response ;
115 }
116 else if ($this->offlineMode === true){ // if we're in offline mode don't continue the request to the live server
117 return;
118 }
119 }
120 try{
121 $response = parent::__soapCall($fname, $arguments, null, $this->getAuthHeaders(), $responseHeaders);
122 $this->authToken = $responseHeaders['AuthorizationToken']->Token;
123 if ($this->cachingOn === true && in_array($fname,$this->cachedFunctions)){
124 $this->log .= "Caching response to soap call for future use\n";
125 $this->cacheStore($fname, $arguments, $response);
126 }
127 } catch(SoapFault $exception){
128 // if it is a bad token try re-authenticating - but only once
129 if (stristr($exception->faultstring, "Invalid Token Value")){
130 $this->log .= "Caught exception with invalid token value, re-authenticating and trying one more time\n";
131 $this->authToken = '';
132 try{
133 $response = parent::__soapCall($fname, $arguments, null, $this->getAuthHeaders(), $responseHeaders);
134 $this->authToken = $responseHeaders['AuthorizationToken']->Token;
135 //store the auth token with drupal for later use
136 //variable_set('netforum_auth_token',$this->authToken);
137 if ($this->cachingOn === true && in_array($fname,$this->cachedFunctions)){
138 $this->log .= "Caching response to soap call for future use\n";
139 $this->cacheStore($fname, $arguments, $response);
140 }
141 }
142 catch(SoapFault $exception){
143 $this->log .= "Caught exception in soap call to $fname again - bad authentication token\n";
144 throw $exception;
145 }
146 }
147 else{
148 $this->log .= "Caught exception in soap call to $fname \n";
149 //reset the auth token since a bad request invalidates any previous auth token. This will save us a step if we try again.
150 $this->authToken = '';
151 throw $exception;
152 }
153 }
154
155 return $response;
156 }
157
158 function __doRequest($request, $location, $action, $version) {
159 //really, this is only overloaded for debugging purposes - I want to be able to see what the final soap call is for each step,
160 //that way we can track the auth tokens. Feel free to remove this as needed
161 $this->log .= "Beginning __doRequest\n";
162 $this->log .= "Params for __doRequest: \nRequest: $request\nLocation: $location\nAction: $action\nVersion: $version\n\n";
163 return parent::__doRequest($request, $location, $action, $version);
164 }
165
166 public function clearLog(){
167 $this->log = '';
168 }
169
170 //Turn on caching for requests. It takes the db handle, the db type, and the expire time. By default this is four hours ago, but can be overridden.
171 //it should come as a regular unixtime seconds from 1970, since we'll later call stftime("format",$expire_time) on it.
172 public function setCaching($expire_time = ''){
173 if ($expire_time != ''){
174 if (is_string($expire_time)){
175 $expire_time = strtotime($expire_time);
176 }
177 if ($expire_time > time()){ //this is a boo boo, we want negatives here, so set it to the difference
178 $expire_time = time() - ($expire_time - time());
179 }
180 $this->cacheExpireTime = strftime("%Y-%m-%d %H:%M", $expire_time);
181 }
182 $this->cachingOn = true;
183 return true;
184 }
185
186 //turns the caching off
187 public function disableCaching(){
188 if ($this->cachingOn){
189 $this->log .= "Disabling caching\n";
190 $this->cachingOn = false;
191 }
192 }
193
194 public function cachingOn(){
195 return $this->cachingOn;
196 }
197
198 //If the last response returned was cached, this will return true.
199 public function cachedLastResponse(){
200 return $this->cachedResponse;
201 }
202
203 //If the last response came from the cache this will return true;
204 public function lastResponseFromCache(){
205 return $this->responseFromCache;
206 }
207
208 public function enableOfflineMode(){
209 if ($this->cachingOn){
210 $this->log .= "Enabling offline mode\n";
211 $this->offlineMode = true;
212 }
213 }
214
215 public function disableOfflineMode(){
216 if ($this->offlineMode === true){
217 $this->log .= "Disabling offline mode\n";
218 $this->offlineMode = false;
219 }
220 }
221
222 private function getAuthHeaders(){
223 //this function is used to get the proper headers for inclusion in our own __soapCall method
224
225 // if we don't have a saved auth token get one
226 if ( (! isset($this->authToken)) || trim($this->authToken == '')){
227 $this->log .= "Fetching new authToken\n";
228 //these are the params set in the constructor
229 $authReqParams = Array('userName'=>$this->userName, 'password' => $this->userPass);
230 $responseHeaders = '';
231 try{
232 //run the soap call to get it - with the headers. Use the parent soap call in case we overload our soap method
233 $response = parent::__SoapCall("Authenticate", array('parameters'=>$authReqParams), null,null, $responseHeaders);
234 $this->authToken = $responseHeaders['AuthorizationToken']->Token;
235 //store the auth token with drupal for later use
236 //variable_set('netforum_auth_token',$this->authToken);
237 $this->xwebNamespace = $response->AuthenticateResult;
238 } catch(SoapFault $exception) {
239 throw $exception;
240 }
241 }
242
243 //return the header we oh so want.
244 return new SoapHeader($this->xwebNamespace, 'AuthorizationToken', Array('Token'=>$this->authToken), true);
245 }
246
247 private function setOverloadedWsdlFunctions(){
248 //this method will grab a list of wsdl defined functions that we will be overloading using the magic __call() method
249 $functions = parent::__getFunctions();
250 foreach ($functions as $fname){
251 //strip the actual function name out for our uses
252 $start = strpos($fname,' ');
253 $end = strpos($fname,'(');
254 //append the name of the function to our internal list, which we check in every __call()
255 $this->overloadedWsdlFunctions[] = trim(substr($fname, $start, ($end - $start)));
256 }
257 }
258
259
260 //this will cache the request and for a given function call and arguments.
261 private function cacheStore($fname='', $arguments='', $response=''){
262 if ( $fname == '' || $arguments == '' || (! is_object($response) && $response == '')){
263 $this->log .= "Could not store response, invalid parameters passed\n";
264 return false;
265 }
266 if ( ! in_array($fname,$this->cachedFunctions)){
267 $this->log .= "Could not store response, $fnanme is not on the list of cacheable functions\n";
268 return false;
269 }
270 $res = db_query("INSERT INTO {netforum_request_cache} (user_name, wsdl_loc, request, ". $this->argumentsColName() .", response, add_date)
271 VALUES('%s', '%s', '%s', '%s', '%s', '%s')",$this->userName, $this->cacheWsdlLoc, $fname, $this->argumentsDbPrep($arguments), serialize($response), strftime("%Y-%m-%d %H:%M"));
272
273 if ($res){
274 $this->log .= "Cached call to $fname\n";
275 return true;
276 }
277 else{
278 $this->log .= "Error on insert - ".db_error()."\n";
279 return false;
280 }
281
282 }
283
284 private function cacheRetreive($fname='', $arguments=''){
285 if ($fname == '' || $arguments == '' ){
286 $this->log .= "Could not fetch response from cache, invalid parameters passed\n";
287 return false;
288 }
289 if ( ! in_array($fname,$this->cachedFunctions)){
290 $this->log .= "Could not fetch response from cache, $fname is not on the list of cacheable functions\n";
291 return false;
292 }
293
294 $res = db_query("SELECT response FROM {netforum_request_cache}
295 WHERE user_name = '%s' AND
296 wsdl_loc = '%s' AND
297 request = '%s' AND
298 ". $this->argumentsColName() ." = '%s' AND
299 add_date >= '%s'
300 ORDER BY add_date DESC LIMIT 1", $this->userName, $this->cacheWsdlLoc, $fname, $this->argumentsDbPrep($arguments), $this->cacheExpireTime);
301 if ($res && db_num_rows($res) > 0){
302 $this->log .= "Found cached response to $fname, returning from database\n";
303 $this->responseFromCache = true;
304 $data = db_fetch_object($res);
305 return unserialize($data->response); //since fetch row returns an array, we just want the plain ol' response
306 }
307 else{
308 $this->log .= "No cached response found for $fname in database\n";
309 return false;
310 }
311 }
312
313 private function argumentsColName(){
314 if ($this->useSha1){
315 return "arguments_sha1_hash";
316 }
317 else{
318 return "arguments";
319 }
320 }
321 private function argumentsDbPrep($arguments){
322 if ($this->useSha1){
323 return sha1(serialize($arguments));
324 }
325 else{
326 return serialize($arguments);
327 }
328 }
329 }
330
331 ?>

  ViewVC Help
Powered by ViewVC 1.1.2