diff --git a/webservice/clienttools/ajaxhandler.php b/webservice/clienttools/ajaxhandler.php index 4e3e9a5..1538e47 100644 --- a/webservice/clienttools/ajaxhandler.php +++ b/webservice/clienttools/ajaxhandler.php @@ -1,5 +1,9 @@ ret=&$response; + }else{ + $this->ret=new jsonResponseObject(); + } + $this->log("[__construct]ENTERING PREPARATIONS"); + + $this->remoteIp = (getenv(HTTP_X_FORWARDED_FOR)) ? getenv(HTTP_X_FORWARDED_FOR) : getenv(REMOTE_ADDR); + $this->log("[__construct]Remote IP determined as: {$this->remoteIp}"); - public function __construct(&$ret=NULL,&$kt,$noAuthRequests=''){ - // set a local copy of the json request wrapper $noAuthRequests=is_array($noAuthRequests)?$noAuthRequests:split(',',(string)$noAuthRequests); $this->registerNoAuthRequest($noAuthRequests); - $this->req=new jsonWrapper(isset($_GET['request'])?$_GET['request']:(isset($_POST['request'])?$_POST['request']:'')); + + $this->rawRequestObject=isset($_GET['request'])?$_GET['request']:(isset($_POST['request'])?$_POST['request']:''); + $this->digestToken=isset($_GET['msgAuth'])?$_GET['msgAuth']:(isset($_POST['msgAuth'])?$_POST['msgAuth']:''); + $this->log("[__construct]DigestToken Found: {$this->digestToken}"); + + $this->ret->addDebug('Raw Request',$this->rawRequestObject); + $this->ret->addDebug('DigestToken Received',$this->digestToken); + $this->ret->addDebug('Remote IP',$this->remoteIp); + + + if($this->auth['session'])session_id($this->auth['session']); + $this->session=session_id(); + $this->log("[__construct]Session Restarted as: {$this->session}"); + // session_id('BLANK_SESSION'); + + + + //========================= 1. Parse Json + $this->log("[__construct]ENTERING Parse Json"); + $this->req=new jsonWrapper($this->rawRequestObject); $this->auth=$this->structArray('user,pass,passhash,appType,session,token,version',$this->req->jsonArray['auth']); $this->request=$this->structArray('service,function,parameters',$this->req->jsonArray['request']); + //Add additional parameters $add_params=array_merge($_GET,$_POST); unset($add_params['request'],$add_params['datasource']); $this->request['parameters']=array_merge($this->request['parameters'],$add_params); - - - // set the response object - if(get_class($ret)=='jsonResponseObject'){ - $this->ret=&$ret; - }else{ - $this->ret=new jsonResponseObject(); - } + + if(!$this->auth['debug'])$this->ret->includeDebug=false; + $this->ret->setRequest($this->req->jsonArray); $this->ret->setTitle($this->request['service'].'::'.$this->request['function']); $this->ret->setDebug('Server Versions',$this->getServerVersions()); - + + + + + + //========================= 2. Test System Requirements + $this->log("[__construct]ENTERING Test System Requirements"); if(get_class($kt)=='KTAPI'){ $this->kt=&$kt; }else{ $this->ret->addError('KnowledgeTree Object not Received in '.__CLASS__.' constructor. Quitting.'); return $this->render(); } + + + //TODO: Get rid of this service + $this->loadService('auth'); + $this->authenticator=new auth($this,$this->ret,$this->kt,$this->request,$this->auth); + + + + //========================= 3. Check Request Validity + $this->log("[__construct]ENTERING Check Request Validity"); + if(!$this->checkRequestValidity())return $this->render(); + if(!$this->checkTokenValidity())return $this->render(); + + + + + //========================= 4. Preliminary Session Check + $this->log("[__construct]ENTERING Preliminary Session Check"); + if(!$this->checkSessionValidity()){ + $this->creatNewSession(); //(login) This may fail, be the user is still allowed to dispatch to the + } + + + + + + //========================= 5. Authentication Check + $this->log("[__construct]ENTERING Authentication Check"); + if(!$this->isStandardService() && !$this->isNoAuthRequiredRequest()){ + //Authentication is Required + $this->log("[__construct]Determined Authentication is required"); + if(!$this->checkCredentials()){ + throw new Exception('User Credentials Necessary for Requested Service'); + return $this->render(); + } + } + + + + + + + //========================= 6. Service Dispatch + $this->log("[__construct]ENTERING Service Dispatch"); + $this->dispatch(); + return $this->render(); + } + + + + + + + + + + + + + protected function checkRequestValidity(){ + $this->log("[checkRequestvalidity]Entering..."); + $securityHash=md5(md5($this->rawRequestObject).'_'.$this->auth['token'].'_'.$this->getUserPass()); + $digestToken=$this->digestToken; + $this->log("[checkRequestvalidity]comparing {$securityHash} with {$digestToken} as received"); - // Prepare - if(!$this->isStandardService()){ - $this->loadService('auth'); - $this->authenticator=new auth($this,$this->ret,$this->kt,$this->request,$this->auth); - + $passed=$securityHash==$digestToken; + + $data=array( + 'Received Token' =>$digestToken, + 'Expected Token' =>$securityHash, + 'Passed' =>$passed, + '' + ); + $this->ret->addDebug('Message Digest Security',$data); + + if(!$passed){ + $this->log("[checkRequestvalidity]Failed Validity Test"); + throw new Exception('Message Integrity Was Compromised.'); + } + return $passed; + } - //Make sure a token exists before continuing - if(!$this->verifyToken())return $this->render(); + protected function checkSessionValidity(){ + $valid=$this->start_session(); + $this->auth['session']=session_id(); + $this->ret->setStatus('session_id',session_id()); + $this->ret->addDebug('Auth',array('Session Check'=>$valid)); +// echo $valid?'true':'false'.'






'; + return $valid; + } - if(!$this->verifySession()){ - $this->doLogin(); - $isAuthRequired=$this->isNoAuthRequiredRequest(); - $isAuthenticated=$this->isAuthenticated(); - if(!$isAuthRequired && !$isAuthenticated)return $this->render(); - } + //TODO: Alter this to verify whether token was used before or whether it is new + protected function checkTokenValidity(){ + $token=$this->auth['token']; + $tokenList=$_SESSION['JAPI_TOKEN_STORE']?$_SESSION['JAPI_TOKEN_STORE']:array(); + $valid=!in_array($token,$tokenList); + if($valid){ + $tokenList[$token]=$token; + $_SESSION['JAPI_TOKEN_STORE']=$tokenList; + }else{ + $this->error('Invalid Token - Already Used'); + $this->log('Invalid Token - Already Used'); } - $this->dispatch(); - - return $this->render(); + return $valid; + } + + + protected function creatNewSession(){ + $this->ret->addDebug('Auth',array('Attempting to Create a New Session')); + if($this->checkCredentials()){ + $ssession=KTAPI_UserSession::_check_session($this->getUserObject(),$this->remoteIp,$this->auth['appType']); + $session=$ssession[0]; + $this->ret->addDebug('####################################Session Created : '.$session); + $this->auth['session']=session_id(); + $this->ret->setStatus('session_id',session_id()); + return true; + }else{ + return false; + } + } + + protected function start_session(){ + $app_type=$this->auth['appType']; + $session_id=$this->auth['session']; + $ip=$this->remoteIp; + + $session=$this->kt->get_session(); + + if(get_class($session)=='KTAPI_UserSession'){ + return true; + }else{ + $session = $this->kt->get_active_session($session_id, $ip, $app_type); + + if (PEAR::isError($session)){ + return false; + } + $this->auth['session']=session_id(); + $this->ret->setStatus('session_id',session_id()); + return true; + } + + + } + + + protected function getUserPass(){ + $l_pass=md5('@NO_AUTH_NEEDED@'); + $u=$this->getUserObject(); + if($u){ + $l_pass=$this->getUserObject()->getPassword(); + } + return $l_pass; + } + + protected function getUserObject(){ + $kt=$this->kt; + $user=$this->auth['user']; + $o_user=$kt->get_user_object_by_username($user); + + if(PEAR::isError($o_user)){ + if(!isset($this->errors['usernotfound']))$this->ret->addError('User '.$user.' not found'); + $this->errors['usernotfound']=true; + return false; + }else{ + $this->log("[getUserObject] Found User: ".$o_user->getName()); + } + return $o_user; + } + + protected function checkCredentials(){ + $user=$this->auth['user']; + $passHash=$this->auth['passhash']; + + $kt=$this->kt; + + $o_user=$kt->get_user_object_by_username($user); + + if(PEAR::isError($o_user)){ + if(!isset($this->errors['usernotfound']))$this->ret->addError('User '.$user.' not found'); + $this->errors['usernotfound']=true; + return false; + } + + try{ + $l_pass=$o_user->getPassword(); + $l_passHash=md5($l_pass.$this->auth['token']); + + $passed=$passHash==$l_passHash; + + $this->ret->setDebug('Auth',array( + 'User Real Password'=>$l_pass, + 'User Real Password Hash'=>$l_passHash, + 'Received Password Hash'=>$passHash, + 'passed'=>$passed + )); + + return $passed; + + }catch(Exception $e){ + throw new Exception('Unknown credentialCheck error encountered'); + return false; + } + + return ture; + } + + + + protected function log($str=''){ + $this->ret->log($str); + } + + + protected function error($errMsg=NULL){ + $this->ret->addError($errMsg); } + + + + + + + + + private function structArray($structString=NULL,$arr=NULL){ $struct=array_flip(split(',',(string)$structString)); return array_merge($struct,is_array($arr)?$arr:array()); @@ -91,7 +345,17 @@ class ajaxHandler{ } public function isStandardService(){ - return in_array($this->request['service'],$this->standardServices); + $isStandardService=in_array($this->request['service'],$this->standardServices); + + $debug=array( + 'requested service' =>$this->request['service'], + 'standard services' =>$this->standardServices, + 'isStandardService' =>$isStandardService + ); + + $this->ret->addDebug('ajaxhandler::isStandardService',$debug); + + return $isStandardService; } @@ -188,7 +452,17 @@ class ajaxHandler{ public function isNoAuthRequiredRequest(){ $req=$this->request; $reqString=strtolower("{$req['service']}.{$req['function']}"); - return in_array($reqString,$this->noAuthRequireList); + $requiresAuth=in_array($reqString,$this->noAuthRequireList); + + $debug=array( + 'requested service method' =>$reqString, + 'no auth required list' =>$this->noAuthRequireList, + 'requires auth' =>$requiresAuth + ); + + $this->ret->addDebug('ajaxhandler::isNoAuthRequiredRequest',$debug); + + return $requiresAuth; } } diff --git a/webservice/clienttools/comms.php b/webservice/clienttools/comms.php index b62270e..5cd541e 100644 --- a/webservice/clienttools/comms.php +++ b/webservice/clienttools/comms.php @@ -50,7 +50,7 @@ if($_GET['datasource'])$RET->isDataSource=true; $noAuthRequests=array( 'auth.ping', - 'auth.japiLogin', + //'auth.japiLogin', 'kt.get_all_client_policies', 'kt.get_languages', 'kt.switchlang' diff --git a/webservice/clienttools/jsonWrapper.php b/webservice/clienttools/jsonWrapper.php index b8b1c94..9173c52 100644 --- a/webservice/clienttools/jsonWrapper.php +++ b/webservice/clienttools/jsonWrapper.php @@ -9,6 +9,7 @@ class jsonResponseObject{ protected $errors=array(); protected $status=array('session_id'=>'','random_token'=>''); protected $data=array(); + protected $log=array(); protected $request=array(); protected $debug=array(); public $additional=array(); @@ -28,7 +29,8 @@ class jsonResponseObject{ ), 'data' =>array(), 'request' =>array(), - 'debug' =>array() + 'debug' =>array(), + 'log' =>array() ); @@ -49,9 +51,12 @@ class jsonResponseObject{ } public function setDebug($varName=NULL,$value=NULL){ + if(is_array($this->debug[$varName]) && is_array($value))$value=array_merge($this->debug[$varName],$value); $this->debug[$varName]=$value; } + public function addDebug($varName=NULL,$value=NULL){$this->setDebug($varName,$value);} + public function setRequest($request=NULL){ $this->request=$request; } @@ -61,6 +66,10 @@ class jsonResponseObject{ $this->title=$title; } + public function log($str){ + $this->log[]='['.date('h:i:s').'] '.$str; + } + public function getJson(){ $response=array_merge(array( 'requestName' =>$this->title, @@ -72,6 +81,7 @@ class jsonResponseObject{ 'data' =>$this->data, 'request' =>$this->request, 'debug' =>$this->debug, + 'log' =>$this->log ),$this->additional); if(!$this->includeDebug) unset($response['debug']); @@ -91,7 +101,6 @@ class jsonWrapper{ public $jsonArray=array(); public function __construct($content=NULL){ -// $content=stripslashes($content); $this->raw=$content; $content=@json_decode($content,true); if(!is_array($content))throw new jsonContentException('Invalid JSON input',jsonContentException::INPUT_ERROR);