Location: PHPKode > projects > Simple Way to Usenet > swun/libs/core/auth/realm_ticket.class.php
<?php
/**
 * a ticket is defined by
 * a key 				=> hashed, ticketkey (the thing client must provide in each request)
 * a realm				=> hashed, realm ref
 * a host				=> hashed, ip used to pass the challenge
 * a ruid				=> crypted (notyet), the granted ruid
 * a status				=> 1 (actif account), 0 (not granted), NULL (multilogin-passive)
 * a creat date			=> when challenge was requested ? for lifetime, chal_timeout
 * a chal date			=> when challenge was passed ?	  							
 * a lastgrant			=> when this ticket was last used by client ? (passive are also updated)
 * 
 * got 4 status
 * 1 - unchallenged			=> status=0, chaldate=0
 * 2 - challenged failed	=> status=0, chaldate!=0
 * 3 - granted active		=> status=1, chaldate!=0
 * 4 - granted passive		=> status=NULL, chaldate!=0
 * 
 * @author  Benjamin Gillissen <hide@address.com>
 * 
 *	**************************************************************

	Copyright (C) 2009  Benjamin Gillissen
	
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.
	
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details at:
	http://www.gnu.org/copyleft/gpl.html

 *	**************************************************************
 */
class realm_ticket extends dbobject {

	protected $realm;
	private static $active_ticket;
	
	public function __construct($realm){ 
		$this->realm = $realm;
		unset($realm);
		$cnf = configs::get('realm', 'realm', Array($this->realm, 'ticket_opt'));
		if ( FALSE === $cnf ){ 
			errors::raise('Missing Realm Ticket DB CNF option for realm '.$this->realm, CORE_LOG_FATAL, 'REALM');
			return; 
		}
		parent::__construct($cnf);
	}

//-------------------------------------------------------------------------------------CLEANUP
		
	protected function cleanup_tickets(){
		$aticket = $this->get_active_ticket();
		$ptickets = $this->get_passive_ticket();
		$to = configs::get('realm', 'realm', Array($this->realm, 'timeout'));
		$timeout =( time() - $to );
		$lifetime=( time() - configs::get('realm', 'realm', Array($this->realm, 'lifetime')) );
		$chalto=( time() - configs::get('realm', 'realm', Array($this->realm, 'chal_timeout')) );
		$arg=Array( 'realm'=>md5($this->realm), 'host'=>md5(client::host()), 'timeout'=>$timeout, 'lifetime'=>$lifetime, 'chalto'=>$chalto);
		//Host Granted timeout (active / passive)
		while( FALSE !== ( $ticket = $this->dbquery($arg, 'get_grantimeout', 'key')) ){
			if ( md5($aticket) == $ticket ){
				pagegen::add_event("Active Ticket has been droped : no activity within $to secondes");
				//if is ajax, enforce dummy call (next req will take care of inactive TO, EXP or restore)
				if ( isset($_GET['ajax']) ){ ajax::EnforceReq('dummy'); }
			} elseif ( is_array($ptickets) ){
				foreach($ptickets as $k => $pticket ){
					if ( md5($pticket) == $ticket ){ pagegen::add_event("Passive Ticket has been droped : no activity within $to secondes"); }
				}
			}
			$this->drop_ticket($ticket);
		}
		//Host Granted expire (active / passive)
		while( FALSE !== ( $ticket = $this->dbquery($arg, 'get_grantexpire', 'key')) ){
			if ( md5($aticket) == $ticket ){
				pagegen::add_event("Active Ticket has been droped : maximum lifetime reached");
			} elseif ( count($ptickets) != 0 ){
				foreach($ptickets as $k => $pticket ){
					if ( md5($pticket) == $ticket ){ pagegen::add_event("Passive Ticket has been droped : maximum lifetime reached"); }
				}
			}
			$this->drop_ticket($ticket);
		}
		//Failed Challenge expire
		while( FALSE !== ( $ticket = $this->dbquery($arg, 'get_failedexpire', 'key')) ){ $this->drop_ticket($ticket); }
		//Unchallenged timeout
		while( FALSE !== ( $ticket = $this->dbquery($arg, 'get_unchaltimeout', 'key')) ){ $this->drop_ticket($ticket); }
	}
	
	protected function cleanup_client_tickets(){
		$utickets = $this->get_client_tickets();
		if ( FALSE === $utickets ){ return FALSE; }
		foreach($utickets as $k => $ticket){
			if ( FALSE === $this->isticket($ticket) ){
				errors::raise("Client Ticket [$k] as been cleaned", CORE_LOG_NOTICE, 'REALM'); 
				unset($utickets[$k]); 
			}
		}
		return $this->set_client_tickets($utickets);
	}

//-------------------------------------------------------------------------------------CLEANUP	
	
	
//-------------------------------------------------------------------------------------CLIENT TICKET
	private function get_client_tickets(){
		//has set into client cookies
		$COOKRef = configs::get('realm', 'realm', Array($this->realm, 'cookname'));
		$utickets = cookies::read('tickets', $COOKRef);
		unset($COOKRef);
		if ( FALSE === is_array($utickets) ){ return FALSE; }
		if ( FALSE === isset($utickets[$this->realm]) ){ return FALSE; }
		//decode, decrypt, unserialize, $utickets[$this->realm]
		//errors::raise('Ticket cookies has been restored with :'.print_r($utickets[$this->realm], TRUE), CORE_LOG_NOTICE, 'REALM');
		return $utickets[$this->realm];
	}
	
	private function set_client_tickets($rtickets){
		$COOKRef = configs::get('realm', 'realm', Array($this->realm, 'cookname'));
		$utickets = cookies::read('tickets', $COOKRef);
		//serialize, crypt, encode $rtickets
		$utickets[$this->realm] = $rtickets;
		//errors::raise('Ticket cookies has been updated with :'.print_r($rtickets, TRUE), CORE_LOG_NOTICE, 'REALM');
		return cookies::set('tickets', $utickets, $COOKRef);
		
	}
	
	//return the active ticket from the client's tickets list
	protected function get_active_ticket(){
		$utickets = $this->get_client_tickets();
		if ( FALSE === $utickets ){
			errors::raise('No Ticket in cook', CORE_LOG_NOTICE, 'REALM'); 
			return FALSE; 
		}
		foreach($utickets as $k => $ticket){
			//errors::raise('checking Ticket '.md5($ticket), CORE_LOG_DEBUG, 'REALM');
			if ( TRUE === $this->isactif($ticket) ){ return $ticket; }
		}
		errors::raise('No active Ticket in cook', CORE_LOG_NOTICE, 'REALM');
		return FALSE;
	}

	//return the passive tickets from the client's tickets list
	protected function get_passive_ticket(){
		$utickets = $this->get_client_tickets();
		if ( FALSE === $utickets ){ return FALSE; }
		foreach($utickets as $k => $ticket){
			if ( TRUE === $this->isgranted($ticket) ){
				//errors::raise("Ticket ".md5($ticket)." is granted", CORE_LOG_NOTICE, 'REALM');
				if ( FALSE === $this->isactif($ticket) ){
					//errors::raise("Ticket ".md5($ticket)." is NOT actif, so is passive eh", CORE_LOG_NOTICE, 'REALM');
					$o[]=$ticket;
				} else {
					//errors::raise("Ticket ".md5($ticket)." is ACTIF", CORE_LOG_NOTICE, 'REALM');
				}
			} else {
				//errors::raise("Ticket ".md5($ticket)." is NOT granted", CORE_LOG_NOTICE, 'REALM');
			}
		}
		if ( isset($o) ){ return $o; }
		return FALSE;
	}
	
//-------------------------------------------------------------------------------------CLIENT TICKET


	
//-------------------------------------------------------------------------------------REALM ACTION
	protected function newticket($key, $chaldata){
		//check for offending maxticketbyclient
		$limit = configs::get('realm', 'realm', Array($this->realm, 'maxchalticket'));
		if ( $limit != 0 ){
			$cur = $this->count_failed();
			if ( $cur >= $limit ){
				errors::raise("Host '".client::host()."' has exceeded maxchalticket rule", CORE_LOG_WARNING, 'REALM'); 
				return 'realmsg_maxchalticket';	
			}
		}
		//check for offending maxticketbyhost		
		$limit = configs::get('realm', 'realm', Array($this->realm, 'maxticketbyhost'));
		if ( $limit != 0 ){
			$cur = $this->count_ticket();
			if ( $cur >= $limit ){
				errors::raise("Host '".client::host()."' has exceeded maxticketbyhost rule", CORE_LOG_WARNING, 'REALM'); 
				return 'realmsg_maxticketbyhost';	
			}
		}
		if ( FALSE === $this->create_ticket($key, $chaldata) ){	return 'realmsg_nonewticket'; }
		$utickets = $this->get_client_tickets();
		$utickets[] = $key;
		if ( FALSE === $this->set_client_tickets($utickets) ){ return 'realmsg_nocookset'; }
		return TRUE;
	}
	
	protected function del_active_ticket(){
		$ticket = $this->get_active_ticket();
		if ( FALSE === $ticket ){ return FALSE; }
		if ( FALSE === $this->remove_ticket($ticket) ){ return FALSE; }
		$utickets = $this->get_client_tickets();
		foreach($utickets as &$ticket){
			if ( TRUE === $this->isgranted($ticket) ){
				return $this->grant_ticket($this->ticket_uid($ticket), $ticket);
			}
		}
		return TRUE;
	}
	
	protected function activate_ticket($ruid){
		$utickets = $this->get_client_tickets();
		if ( FALSE === $utickets ){ return 'realmsg_nocook'; }
		$found=FALSE;
		foreach($utickets as &$ticket){
			if ( TRUE === $this->isgranted($ticket) ){ 
				if ( $ruid == $this->ticket_uid($ticket) ){ $found=TRUE;break; }
			}
		}
		if ( !$found ){ return 'realmsg_noticket'; }
		//return $this->grant_ticket($ruid, $ticket);
		
		$utickets = $this->get_client_tickets();
		If ( !is_array($utickets) ){
			errors::raise('No ticket set in cookies and you want to switchTo !!!', CORE_LOG_ERROR, 'REALM'); 
			return 'realmsg_nocook'; 
		}
		$k = array_search($ticket, $utickets);
		if ( FALSE === $k ){ return 'realmsg_noclienticket'; }
		errors::raise('Ticket to grant found at K '.$k, CORE_LOG_NOTICE, 'REALM');
		if ( FALSE === $this->mark_active($ticket, $ruid, $ticket) ){ return 'realmsg_noticketgrant'; }
		foreach($utickets as $key => &$ticket ){
			if ( $k !== $key AND $this->isgranted($ticket) ){
				$this->mark_passive($ticket, $ticket);
			} 
		}
		return TRUE;
	}
	
	protected function grant_ticket($ruid, $ticket){
		//check for offending maxticketbyuser
		$limit = configs::get('realm', 'realm', Array($this->realm, 'maxticketbyuser'));
		if ( $limit != 0 ){
			$cur = $this->count_account($ruid);
			if ( $cur >= $limit ){ return 'realmsg_maxticketbyuser';	}
		}
		$limit = configs::get('realm', 'realm', Array($this->realm, 'maxgranticket'));
		if ( $limit != 0 ){
			$cur = $this->count_granted();
			if ( $cur >= $limit ){ return 'realmsg_maxgranticket';	}
		}
		$utickets = $this->get_client_tickets();
		If ( !is_array($utickets) ){
			errors::raise('No ticket set in cookies and you want to grant !!!', CORE_LOG_ERROR, 'REALM'); 
			return 'realmsg_nocook'; 
		}
		$k = array_search($ticket, $utickets);
		if ( FALSE === $k ){ return 'realmsg_noclienticket'; }
		errors::raise('Ticket to grant found at K '.$k, CORE_LOG_NOTICE, 'REALM');
		//update ticket and client cook with key. (credential stuff)
		//$new = CORE::hash();
		//$utickets[$k] = $new;
		//if ( FALSE === $this->mark_active($ticket, $ruid, $new) ){ return 'realmsg_noticketgrant'; }
		if ( FALSE === $this->mark_active($ticket, $ruid, $ticket) ){ return 'realmsg_noticketgrant'; }
		if ( count($utickets) != 1 ){
			foreach($utickets as $key => &$ticket ){
				if ( $k !== $key AND $this->isgranted($ticket) ){
					//$new = CORE::hash(); 
					//$this->mark_passive($ticket, $new);
					$this->mark_passive($ticket, $ticket);
					//$ticket=$new;
				} 
			}
			
		}
		//return $this->set_client_tickets($utickets);
		return TRUE;
	}
//-------------------------------------------------------------------------------------REALM ACTION


	
//----------------------------------------------------------------------DBCALL
	public function isticket($ticket){
		$arg=Array( 'ticket'=>md5($ticket), 'realm'=>md5($this->realm), 'host'=>md5(client::host()) );
		return $this->dbquery($arg, __FUNCTION__);
	}
	
	public function ischallenged($ticket){
		$arg=Array( 'ticket'=>md5($ticket), 'realm'=>md5($this->realm), 'host'=>md5(client::host()) );
		return $this->dbquery($arg, __FUNCTION__);
	}
	
	public function isactif($ticket){
		$arg=Array( 'ticket'=>md5($ticket), 'realm'=>md5($this->realm), 'host'=>md5(client::host()) );
		return $this->dbquery($arg, __FUNCTION__);
  		
	}
	
	public function isgranted($ticket){
		$arg=Array( 'ticket'=>md5($ticket), 'realm'=>md5($this->realm), 'host'=>md5(client::host()) );
		return $this->dbquery($arg, __FUNCTION__); 		
	}
	
	public function ticket_chaldata($ticket){
		$arg=Array( 'ticket'=>md5($ticket), 'realm'=>md5($this->realm), 'host'=>md5(client::host()) );
		return $this->dbquery($arg, __FUNCTION__, 'chaldata');  
	}
		
	public function count_ticket(){ 
	 	$arg=Array('host'=>md5(client::host()), 'realm'=>md5($this->realm) );
	 	return $this->dbquery($arg, __FUNCTION__);  
	}
	
	public function count_challenged(){ 
	 	$arg=Array('host'=>md5(client::host()), 'realm'=>md5($this->realm) );
	 	return $this->dbquery($arg, __FUNCTION__);  
	}
	
	public function count_granted(){ 
	 	$arg=Array('host'=>md5(client::host()), 'realm'=>md5($this->realm) );
	 	return $this->dbquery($arg, __FUNCTION__);  
	}
	
	public function count_failed(){	return $this->count_challenged() - $this->count_granted(); }
	
	public function count_account($ruid){ 
		$arg=Array( 'uid'=>$ruid, 'realm'=>md5($this->realm) );
		return $this->dbquery($arg, __FUNCTION__);
	} 
	
	protected function mark_challenged($ticket){
		errors::raise('Marking Ticket '.md5($ticket).' challenged', CORE_LOG_NOTICE, 'REALM');
		$arg=Array( 'ticket'=>md5($ticket), 'time'=>time(), 'realm'=>md5($this->realm), 'host'=>md5(client::host()) );
		return $this->dbquery($arg, __FUNCTION__);  
	}
	
	protected function ticket_uid($ticket){
		$arg=Array( 'ticket'=>md5($ticket), 'realm'=>md5($this->realm), 'host'=>md5(client::host()) );
		return $this->dbquery($arg, __FUNCTION__, 'uid');  
		return FALSE;
	}
	
	protected function create_time($ticket){
		$arg=Array( 'realm'=>md5($this->realm), 'ticket'=>md5($ticket), 'host'=>md5(client::host()));
		return $this->dbquery($arg, 'create_time', 'create');
	}
	
	protected function grant_time($ticket){
		$arg=Array( 'realm'=>md5($this->realm), 'ticket'=>md5($ticket), 'host'=>md5(client::host()));
		return $this->dbquery($arg, 'grant_time', 'chaldate');
	}
	
	protected function ticket_update($ticket){
		$arg=Array( 'realm'=>md5($this->realm), 'ticket'=>md5($ticket), 'time'=>time(), 'host'=>md5(client::host()));
		return $this->dbquery($arg, 'ticket_update');
	}
	
	private function create_ticket($ticket, $chaldata){
		$arg=Array( 'ticket'=>md5($ticket), 'realm'=>md5($this->realm), 'host'=>md5(client::host()), 'chaldata'=>$chaldata, 'time'=>time() );
		return $this->dbquery($arg, __FUNCTION__);
	}
	
	private function mark_passive($ticket, $new){
		$arg=Array( 'ticket'=>md5($ticket), 'new'=>md5($new), 'time'=>time(), 'realm'=>md5($this->realm), 'host'=>md5(client::host()) );
		return $this->dbquery($arg, __FUNCTION__);  
	}
	
	private function mark_active($ticket, $ruid, $new){
		$arg=Array( 'ticket'=>md5($ticket), 'uid'=>$ruid, 'time'=>time(), 'new'=>md5($new), 'realm'=>md5($this->realm), 'host'=>md5(client::host()) );
		return $this->dbquery($arg, __FUNCTION__); 
	}
	
	private function remove_ticket($ticket){
		$arg=Array( 'ticket'=>md5($ticket), 'realm'=>md5($this->realm), 'host'=>md5(client::host()) );
		return $this->dbquery($arg, 'drop_ticket');  
	}

	private function drop_ticket($ticket){
		$arg=Array( 'realm'=>md5($this->realm), 'ticket'=>$ticket );
		return $this->dbquery($arg, 'drop_ticket');
	}
//----------------------------------------------------------------------DBCALL	
}
return TRUE;
Return current item: Simple Way to Usenet