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

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

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


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

  ViewVC Help
Powered by ViewVC 1.1.2