Commit 92e0ac4c39ec27c137c4be3b240dff452fa3447f

Authored by Jarrett Jordaan
2 parents ea6f8f46 5fec8b8b

Merge branch 'edge' of git@github.com:ktgit/knowledgetree into edge

webservice/clienttools/ajaxhandler.php
1 <?php 1 <?php
2 class ajaxHandler{ 2 class ajaxHandler{
  3 + protected $rawRequestObject=NULL;
  4 + protected $digestToken=NULL;
  5 + protected $remoteIp=NULL;
  6 +
3 public $ret=NULL; 7 public $ret=NULL;
4 public $req=NULL; 8 public $req=NULL;
5 public $version=NULL; 9 public $version=NULL;
@@ -9,60 +13,310 @@ class ajaxHandler{ @@ -9,60 +13,310 @@ class ajaxHandler{
9 public $authenticator=NULL; 13 public $authenticator=NULL;
10 public $noAuthRequireList=array(); 14 public $noAuthRequireList=array();
11 public $standardServices=array('system'); 15 public $standardServices=array('system');
  16 +
  17 + protected $errors=array();
  18 +
  19 + /**
  20 + * 1.Parse JSON
  21 + * 2.Check Request Validity (hash/ip/expiration token)
  22 + * 3.Preliminary Session Check
  23 + * if no session or invalid session
  24 + * 3.1 Use credentials to create a new session.
  25 + * 3.3 Update Authentication segment with new sessionid
  26 + * 4.Authentication Check
  27 + * 5.Service Dispatch
  28 + */
  29 +
  30 + public function __construct(&$response=NULL,&$kt,$noAuthRequests=''){
  31 +
  32 + //========================= Preparations
  33 + // set the response object
  34 + if(get_class($response)=='jsonResponseObject'){
  35 + $this->ret=&$response;
  36 + }else{
  37 + $this->ret=new jsonResponseObject();
  38 + }
  39 + $this->log("[__construct]ENTERING PREPARATIONS");
  40 +
  41 + $this->remoteIp = (getenv(HTTP_X_FORWARDED_FOR)) ? getenv(HTTP_X_FORWARDED_FOR) : getenv(REMOTE_ADDR);
  42 + $this->log("[__construct]Remote IP determined as: {$this->remoteIp}");
12 43
13 - public function __construct(&$ret=NULL,&$kt,$noAuthRequests=''){  
14 - // set a local copy of the json request wrapper  
15 $noAuthRequests=is_array($noAuthRequests)?$noAuthRequests:split(',',(string)$noAuthRequests); 44 $noAuthRequests=is_array($noAuthRequests)?$noAuthRequests:split(',',(string)$noAuthRequests);
16 $this->registerNoAuthRequest($noAuthRequests); 45 $this->registerNoAuthRequest($noAuthRequests);
17 - $this->req=new jsonWrapper(isset($_GET['request'])?$_GET['request']:(isset($_POST['request'])?$_POST['request']:'')); 46 +
  47 + $this->rawRequestObject=isset($_GET['request'])?$_GET['request']:(isset($_POST['request'])?$_POST['request']:'');
  48 + $this->digestToken=isset($_GET['msgAuth'])?$_GET['msgAuth']:(isset($_POST['msgAuth'])?$_POST['msgAuth']:'');
  49 + $this->log("[__construct]DigestToken Found: {$this->digestToken}");
  50 +
  51 + $this->ret->addDebug('Raw Request',$this->rawRequestObject);
  52 + $this->ret->addDebug('DigestToken Received',$this->digestToken);
  53 + $this->ret->addDebug('Remote IP',$this->remoteIp);
  54 +
  55 +
  56 + if($this->auth['session'])session_id($this->auth['session']);
  57 + $this->session=session_id();
  58 + $this->log("[__construct]Session Restarted as: {$this->session}");
  59 + // session_id('BLANK_SESSION');
  60 +
  61 +
  62 +
  63 + //========================= 1. Parse Json
  64 + $this->log("[__construct]ENTERING Parse Json");
  65 + $this->req=new jsonWrapper($this->rawRequestObject);
18 $this->auth=$this->structArray('user,pass,passhash,appType,session,token,version',$this->req->jsonArray['auth']); 66 $this->auth=$this->structArray('user,pass,passhash,appType,session,token,version',$this->req->jsonArray['auth']);
19 $this->request=$this->structArray('service,function,parameters',$this->req->jsonArray['request']); 67 $this->request=$this->structArray('service,function,parameters',$this->req->jsonArray['request']);
20 68
  69 + //Add additional parameters
21 $add_params=array_merge($_GET,$_POST); 70 $add_params=array_merge($_GET,$_POST);
22 unset($add_params['request'],$add_params['datasource']); 71 unset($add_params['request'],$add_params['datasource']);
23 $this->request['parameters']=array_merge($this->request['parameters'],$add_params); 72 $this->request['parameters']=array_merge($this->request['parameters'],$add_params);
24 -  
25 -  
26 - // set the response object  
27 - if(get_class($ret)=='jsonResponseObject'){  
28 - $this->ret=&$ret;  
29 - }else{  
30 - $this->ret=new jsonResponseObject();  
31 - } 73 +
  74 + if(!$this->auth['debug'])$this->ret->includeDebug=false;
  75 +
32 $this->ret->setRequest($this->req->jsonArray); 76 $this->ret->setRequest($this->req->jsonArray);
33 $this->ret->setTitle($this->request['service'].'::'.$this->request['function']); 77 $this->ret->setTitle($this->request['service'].'::'.$this->request['function']);
34 $this->ret->setDebug('Server Versions',$this->getServerVersions()); 78 $this->ret->setDebug('Server Versions',$this->getServerVersions());
35 - 79 +
  80 +
  81 +
  82 +
  83 +
  84 + //========================= 2. Test System Requirements
  85 + $this->log("[__construct]ENTERING Test System Requirements");
36 if(get_class($kt)=='KTAPI'){ 86 if(get_class($kt)=='KTAPI'){
37 $this->kt=&$kt; 87 $this->kt=&$kt;
38 }else{ 88 }else{
39 $this->ret->addError('KnowledgeTree Object not Received in '.__CLASS__.' constructor. Quitting.'); 89 $this->ret->addError('KnowledgeTree Object not Received in '.__CLASS__.' constructor. Quitting.');
40 return $this->render(); 90 return $this->render();
41 } 91 }
  92 +
  93 +
  94 + //TODO: Get rid of this service
  95 + $this->loadService('auth');
  96 + $this->authenticator=new auth($this,$this->ret,$this->kt,$this->request,$this->auth);
  97 +
  98 +
  99 +
  100 + //========================= 3. Check Request Validity
  101 + $this->log("[__construct]ENTERING Check Request Validity");
  102 + if(!$this->checkRequestValidity())return $this->render();
  103 + if(!$this->checkTokenValidity())return $this->render();
  104 +
  105 +
  106 +
  107 +
  108 + //========================= 4. Preliminary Session Check
  109 + $this->log("[__construct]ENTERING Preliminary Session Check");
  110 + if(!$this->checkSessionValidity()){
  111 + $this->creatNewSession(); //(login) This may fail, be the user is still allowed to dispatch to the
  112 + }
  113 +
  114 +
  115 +
  116 +
  117 +
  118 + //========================= 5. Authentication Check
  119 + $this->log("[__construct]ENTERING Authentication Check");
  120 + if(!$this->isStandardService() && !$this->isNoAuthRequiredRequest()){
  121 + //Authentication is Required
  122 + $this->log("[__construct]Determined Authentication is required");
  123 + if(!$this->checkCredentials()){
  124 + throw new Exception('User Credentials Necessary for Requested Service');
  125 + return $this->render();
  126 + }
  127 + }
  128 +
  129 +
  130 +
  131 +
  132 +
  133 +
  134 + //========================= 6. Service Dispatch
  135 + $this->log("[__construct]ENTERING Service Dispatch");
  136 + $this->dispatch();
  137 + return $this->render();
  138 + }
  139 +
  140 +
  141 +
  142 +
  143 +
  144 +
  145 +
  146 +
  147 +
  148 +
  149 +
  150 +
  151 + protected function checkRequestValidity(){
  152 + $this->log("[checkRequestvalidity]Entering...");
  153 + $securityHash=md5(md5($this->rawRequestObject).'_'.$this->auth['token'].'_'.$this->getUserPass());
  154 + $digestToken=$this->digestToken;
  155 + $this->log("[checkRequestvalidity]comparing {$securityHash} with {$digestToken} as received");
42 156
43 - // Prepare  
44 - if(!$this->isStandardService()){  
45 - $this->loadService('auth');  
46 - $this->authenticator=new auth($this,$this->ret,$this->kt,$this->request,$this->auth);  
47 - 157 + $passed=$securityHash==$digestToken;
  158 +
  159 + $data=array(
  160 + 'Received Token' =>$digestToken,
  161 + 'Expected Token' =>$securityHash,
  162 + 'Passed' =>$passed,
  163 + ''
  164 + );
  165 + $this->ret->addDebug('Message Digest Security',$data);
  166 +
  167 + if(!$passed){
  168 + $this->log("[checkRequestvalidity]Failed Validity Test");
  169 + throw new Exception('Message Integrity Was Compromised.');
  170 + }
  171 + return $passed;
  172 + }
48 173
49 - //Make sure a token exists before continuing  
50 - if(!$this->verifyToken())return $this->render();  
51 174
  175 + protected function checkSessionValidity(){
  176 + $valid=$this->start_session();
  177 + $this->auth['session']=session_id();
  178 + $this->ret->setStatus('session_id',session_id());
  179 + $this->ret->addDebug('Auth',array('Session Check'=>$valid));
  180 +// echo $valid?'true':'false'.'<br /><br /><br /><br /><br /><br /><br />';
  181 + return $valid;
  182 + }
52 183
53 - if(!$this->verifySession()){  
54 - $this->doLogin();  
55 - $isAuthRequired=$this->isNoAuthRequiredRequest();  
56 - $isAuthenticated=$this->isAuthenticated();  
57 - if(!$isAuthRequired && !$isAuthenticated)return $this->render();  
58 - } 184 + //TODO: Alter this to verify whether token was used before or whether it is new
  185 + protected function checkTokenValidity(){
  186 + $token=$this->auth['token'];
  187 + $tokenList=$_SESSION['JAPI_TOKEN_STORE']?$_SESSION['JAPI_TOKEN_STORE']:array();
  188 + $valid=!in_array($token,$tokenList);
  189 + if($valid){
  190 + $tokenList[$token]=$token;
  191 + $_SESSION['JAPI_TOKEN_STORE']=$tokenList;
  192 + }else{
  193 + $this->error('Invalid Token - Already Used');
  194 + $this->log('Invalid Token - Already Used');
59 } 195 }
60 196
61 - $this->dispatch();  
62 -  
63 - return $this->render(); 197 + return $valid;
  198 + }
  199 +
  200 +
  201 + protected function creatNewSession(){
  202 + $this->ret->addDebug('Auth',array('Attempting to Create a New Session'));
  203 + if($this->checkCredentials()){
  204 + $ssession=KTAPI_UserSession::_check_session($this->getUserObject(),$this->remoteIp,$this->auth['appType']);
  205 + $session=$ssession[0];
  206 + $this->ret->addDebug('####################################Session Created : '.$session);
  207 + $this->auth['session']=session_id();
  208 + $this->ret->setStatus('session_id',session_id());
  209 + return true;
  210 + }else{
  211 + return false;
  212 + }
  213 + }
  214 +
  215 + protected function start_session(){
  216 + $app_type=$this->auth['appType'];
  217 + $session_id=$this->auth['session'];
  218 + $ip=$this->remoteIp;
  219 +
  220 + $session=$this->kt->get_session();
  221 +
  222 + if(get_class($session)=='KTAPI_UserSession'){
  223 + return true;
  224 + }else{
  225 + $session = $this->kt->get_active_session($session_id, $ip, $app_type);
  226 +
  227 + if (PEAR::isError($session)){
  228 + return false;
  229 + }
  230 + $this->auth['session']=session_id();
  231 + $this->ret->setStatus('session_id',session_id());
  232 + return true;
  233 + }
  234 +
  235 +
  236 + }
  237 +
  238 +
  239 + protected function getUserPass(){
  240 + $l_pass=md5('@NO_AUTH_NEEDED@');
  241 + $u=$this->getUserObject();
  242 + if($u){
  243 + $l_pass=$this->getUserObject()->getPassword();
  244 + }
  245 + return $l_pass;
  246 + }
  247 +
  248 + protected function getUserObject(){
  249 + $kt=$this->kt;
  250 + $user=$this->auth['user'];
  251 + $o_user=$kt->get_user_object_by_username($user);
  252 +
  253 + if(PEAR::isError($o_user)){
  254 + if(!isset($this->errors['usernotfound']))$this->ret->addError('User '.$user.' not found');
  255 + $this->errors['usernotfound']=true;
  256 + return false;
  257 + }else{
  258 + $this->log("[getUserObject] Found User: ".$o_user->getName());
  259 + }
  260 + return $o_user;
  261 + }
  262 +
  263 + protected function checkCredentials(){
  264 + $user=$this->auth['user'];
  265 + $passHash=$this->auth['passhash'];
  266 +
  267 + $kt=$this->kt;
  268 +
  269 + $o_user=$kt->get_user_object_by_username($user);
  270 +
  271 + if(PEAR::isError($o_user)){
  272 + if(!isset($this->errors['usernotfound']))$this->ret->addError('User '.$user.' not found');
  273 + $this->errors['usernotfound']=true;
  274 + return false;
  275 + }
  276 +
  277 + try{
  278 + $l_pass=$o_user->getPassword();
  279 + $l_passHash=md5($l_pass.$this->auth['token']);
  280 +
  281 + $passed=$passHash==$l_passHash;
  282 +
  283 + $this->ret->setDebug('Auth',array(
  284 + 'User Real Password'=>$l_pass,
  285 + 'User Real Password Hash'=>$l_passHash,
  286 + 'Received Password Hash'=>$passHash,
  287 + 'passed'=>$passed
  288 + ));
  289 +
  290 + return $passed;
  291 +
  292 + }catch(Exception $e){
  293 + throw new Exception('Unknown credentialCheck error encountered');
  294 + return false;
  295 + }
  296 +
  297 + return ture;
  298 + }
  299 +
  300 +
  301 +
  302 + protected function log($str=''){
  303 + $this->ret->log($str);
  304 + }
  305 +
  306 +
  307 + protected function error($errMsg=NULL){
  308 + $this->ret->addError($errMsg);
64 } 309 }
65 310
  311 +
  312 +
  313 +
  314 +
  315 +
  316 +
  317 +
  318 +
  319 +
66 private function structArray($structString=NULL,$arr=NULL){ 320 private function structArray($structString=NULL,$arr=NULL){
67 $struct=array_flip(split(',',(string)$structString)); 321 $struct=array_flip(split(',',(string)$structString));
68 return array_merge($struct,is_array($arr)?$arr:array()); 322 return array_merge($struct,is_array($arr)?$arr:array());
@@ -91,7 +345,17 @@ class ajaxHandler{ @@ -91,7 +345,17 @@ class ajaxHandler{
91 } 345 }
92 346
93 public function isStandardService(){ 347 public function isStandardService(){
94 - return in_array($this->request['service'],$this->standardServices); 348 + $isStandardService=in_array($this->request['service'],$this->standardServices);
  349 +
  350 + $debug=array(
  351 + 'requested service' =>$this->request['service'],
  352 + 'standard services' =>$this->standardServices,
  353 + 'isStandardService' =>$isStandardService
  354 + );
  355 +
  356 + $this->ret->addDebug('ajaxhandler::isStandardService',$debug);
  357 +
  358 + return $isStandardService;
95 } 359 }
96 360
97 361
@@ -188,7 +452,17 @@ class ajaxHandler{ @@ -188,7 +452,17 @@ class ajaxHandler{
188 public function isNoAuthRequiredRequest(){ 452 public function isNoAuthRequiredRequest(){
189 $req=$this->request; 453 $req=$this->request;
190 $reqString=strtolower("{$req['service']}.{$req['function']}"); 454 $reqString=strtolower("{$req['service']}.{$req['function']}");
191 - return in_array($reqString,$this->noAuthRequireList); 455 + $requiresAuth=in_array($reqString,$this->noAuthRequireList);
  456 +
  457 + $debug=array(
  458 + 'requested service method' =>$reqString,
  459 + 'no auth required list' =>$this->noAuthRequireList,
  460 + 'requires auth' =>$requiresAuth
  461 + );
  462 +
  463 + $this->ret->addDebug('ajaxhandler::isNoAuthRequiredRequest',$debug);
  464 +
  465 + return $requiresAuth;
192 } 466 }
193 467
194 } 468 }
webservice/clienttools/comms.php
@@ -50,7 +50,7 @@ if($_GET[&#39;datasource&#39;])$RET-&gt;isDataSource=true; @@ -50,7 +50,7 @@ if($_GET[&#39;datasource&#39;])$RET-&gt;isDataSource=true;
50 50
51 $noAuthRequests=array( 51 $noAuthRequests=array(
52 'auth.ping', 52 'auth.ping',
53 - 'auth.japiLogin', 53 + //'auth.japiLogin',
54 'kt.get_all_client_policies', 54 'kt.get_all_client_policies',
55 'kt.get_languages', 55 'kt.get_languages',
56 'kt.switchlang' 56 'kt.switchlang'
webservice/clienttools/jsonWrapper.php
@@ -9,6 +9,7 @@ class jsonResponseObject{ @@ -9,6 +9,7 @@ class jsonResponseObject{
9 protected $errors=array(); 9 protected $errors=array();
10 protected $status=array('session_id'=>'','random_token'=>''); 10 protected $status=array('session_id'=>'','random_token'=>'');
11 protected $data=array(); 11 protected $data=array();
  12 + protected $log=array();
12 protected $request=array(); 13 protected $request=array();
13 protected $debug=array(); 14 protected $debug=array();
14 public $additional=array(); 15 public $additional=array();
@@ -28,7 +29,8 @@ class jsonResponseObject{ @@ -28,7 +29,8 @@ class jsonResponseObject{
28 ), 29 ),
29 'data' =>array(), 30 'data' =>array(),
30 'request' =>array(), 31 'request' =>array(),
31 - 'debug' =>array() 32 + 'debug' =>array(),
  33 + 'log' =>array()
32 ); 34 );
33 35
34 36
@@ -49,9 +51,12 @@ class jsonResponseObject{ @@ -49,9 +51,12 @@ class jsonResponseObject{
49 } 51 }
50 52
51 public function setDebug($varName=NULL,$value=NULL){ 53 public function setDebug($varName=NULL,$value=NULL){
  54 + if(is_array($this->debug[$varName]) && is_array($value))$value=array_merge($this->debug[$varName],$value);
52 $this->debug[$varName]=$value; 55 $this->debug[$varName]=$value;
53 } 56 }
54 57
  58 + public function addDebug($varName=NULL,$value=NULL){$this->setDebug($varName,$value);}
  59 +
55 public function setRequest($request=NULL){ 60 public function setRequest($request=NULL){
56 $this->request=$request; 61 $this->request=$request;
57 } 62 }
@@ -61,6 +66,10 @@ class jsonResponseObject{ @@ -61,6 +66,10 @@ class jsonResponseObject{
61 $this->title=$title; 66 $this->title=$title;
62 } 67 }
63 68
  69 + public function log($str){
  70 + $this->log[]='['.date('h:i:s').'] '.$str;
  71 + }
  72 +
64 public function getJson(){ 73 public function getJson(){
65 $response=array_merge(array( 74 $response=array_merge(array(
66 'requestName' =>$this->title, 75 'requestName' =>$this->title,
@@ -72,6 +81,7 @@ class jsonResponseObject{ @@ -72,6 +81,7 @@ class jsonResponseObject{
72 'data' =>$this->data, 81 'data' =>$this->data,
73 'request' =>$this->request, 82 'request' =>$this->request,
74 'debug' =>$this->debug, 83 'debug' =>$this->debug,
  84 + 'log' =>$this->log
75 ),$this->additional); 85 ),$this->additional);
76 if(!$this->includeDebug) unset($response['debug']); 86 if(!$this->includeDebug) unset($response['debug']);
77 87
@@ -91,7 +101,6 @@ class jsonWrapper{ @@ -91,7 +101,6 @@ class jsonWrapper{
91 public $jsonArray=array(); 101 public $jsonArray=array();
92 102
93 public function __construct($content=NULL){ 103 public function __construct($content=NULL){
94 -// $content=stripslashes($content);  
95 $this->raw=$content; 104 $this->raw=$content;
96 $content=@json_decode($content,true); 105 $content=@json_decode($content,true);
97 if(!is_array($content))throw new jsonContentException('Invalid JSON input',jsonContentException::INPUT_ERROR); 106 if(!is_array($content))throw new jsonContentException('Invalid JSON input',jsonContentException::INPUT_ERROR);