Location: PHPKode > scripts > ooeLite > ooelite/ooeSecuritySession.class.php
<?php

/**
* This class can be used to authenticate Web users securely.
* It creates a key encoded with SHA1 based on the IP address and the current time when an user accesses the login page.
* The key is used to generate a salt value that is used to encrypt the password that the user enters in the login form.
* On the server side the class uses the same salt to verify whether the password entered by the user matches the password stored in a database.
* If the authentication is successful, the class starts an authenticated user session.
* The login keys, user and session information is stored in a database. 
* @author Marcelo Soares da Costa
* @email phpmafia at yahoo dot com dot br
* @copyright Marcelo Soares da Costa © 2007/2008.
* @license FreeBSD http://www.freebsd.org/copyright/freebsd-license.html
* @version 3.0
* @access public
* @package OOE
* @chagelog 2009-07-02 Port for OOE Framework V2.0
* @data 2009-07-02
*/

################################################################################

class ooeSecuritySession extends ooeInheritance  {

	private static $objSql = false;

	/**
	* Cria uma referencia para o objeto de conexão do banco de dados
	* @access private
	*/
	private static function __sqlQuery() {
		return parent :: callClassParent('ooePDO');
	}

	/**
	* Verifica a referencia para o objeto sqlQuery
	* @access private
	*/
	private function __checkObjSql() {
		if ($this->objSql == false) {
			$this->objSql = self :: __sqlQuery();
		}
	}

	/**
	* Importa o metodo prepareSQL
	* @access public
	*/
	public function prepareSQL($String) {
		self :: __checkObjSql();
		return $this->objSql->prepareSQL($String);
	}
	/**
	* Importa o metodo getRow
	* @access public
	*/
	public function getRow() {
		return $this->objSql->getRow();
	}
	/**
	* Importa o metodo getLineArray
	* @access public
	*/
	public function getLineArray() {
		return $this->objSql->getLineArray();
	}
	/**
	* Importa o metodo getAssocArray
	* @access public
	*/
	public function getAssocArray() {
		return $this->objSql->getAssocArray();
	}
	/**
	* Importa o metodo beginTransaction
	* @access public
	*/
	public function beginTransaction() {
		self :: __checkObjSql();
		return $this->objSql->beginTransaction();
	}
	/**
	* Importa o metodo commit
	* @access public
	*/
	public function commit() {
		return $this->objSql->commit();
	}
	/**
	* Importa o metodo rollBack
	* @access public
	*/
	public function rollBack() {
		return $this->objSql->rollBack();
	}

	/**
	* Importa o metodo executeSql
	* @access public
	*/
	public function executeSql($String) {
		self :: __checkObjSql();
		return $this->objSql->executeSql($String);
	}

	/**
	* seta o tempo limite para login
	* returnt time for login
	* @access private
	* @input time {string}
	* @return 
	*/
	private function __setTimeLogin($timeIni) {
		unset ($this->timeLogin);
		$this->timeLogin = $timeIni;
	}
	/**
	* seta o tempo limite para a verificacao de sessao em segundos
	* return time session limit
	* @access private
	* @input time {string}
	* @return 
	*/
	private function __setTimeLimit($lifeTime) {
		unset ($this->timeLimit);
		$this->timeLimit = $lifeTime;
	}

	/**
	* Retorna uma nova chave de autenticacao
	* return public form key for login
	* @access public
	* @input 
	* @return array keys
	*/
	public function newServerKey() {
		self :: createServerKey(self :: insertKeydata());
		return array (
			"idKey" => $this->idKey,
			"serverKey" => $this->serverKey
		);
	}

	/**
	* insere no banco de dados as informacoes para criar uma chave de autenticacao
	* insert public key form login
	* retorna o id inserido
	* @access private
	* @input 
	* @return insertid
	*/
	private function insertKeyData() {
		$this->keyTime = time();
		$this->REMOTE_ADDR = str_replace(".", '', $_SERVER["REMOTE_ADDR"]);
		if ($this->REMOTE_ADDR == "::1") {
			$this->REMOTE_ADDR = 127001;
		}

		if ($_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"] == str_replace("http://", '', LOGINURL)) {
			session_unset();
			session_destroy();

			$this->REQUEST_URI = $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];
			$this->clienteData = $this->REMOTE_ADDR . $this->REQUEST_URI . $this->keyTime;

			$SQL_CLEAN = "DELETE FROM acs_sessao  WHERE KEYTIME<=" . ($this->keyTime - $this->timeLogin);
			$SQL_CLEAN .= " AND KEEPALIVE=0";
			self :: executeSql($SQL_CLEAN);

			$SQL_KEY = "INSERT INTO acs_sessao (REMOTE_ADDR,KEYTIME,KEEPALIVE) VALUES ('" . $this->REMOTE_ADDR . "'," . $this->keyTime . ",0)";
			$this->idKey = self :: executeSql($SQL_KEY);

			return $this->idKey;
		} else {
			throw new Exception("Invalid form login", 404);
		}
	}

	/**
	* cria a chave sha256 de autenticação a partir dos dados gravados no bd
	* create a sha256 key server 
	* @access private
	* @input id session
	* @return bolean
	*/
	private function createServerKey($id) {
		$SQL_KEY = "SELECT * FROM acs_sessao WHERE ID_SESSION=" . $id;
		self :: prepareSQL($SQL_KEY);
		extract(self :: getLineArray(), EXTR_OVERWRITE);
		$this->serverKey = hash('sha256', $REMOTE_ADDR . str_replace("http://", '', LOGINURL) . $KEYTIME);
		return true;
	}

	/**
	* Ataualiza a tabela quando a chave é validada
	* update time session for valid key
	* retorna o id inserido
	* @access privado
	* @input id session
	* @return bolean
	*/
	private function validKey($id) {
		$this->timeCurrent = time();
		$SQL = "UPDATE acs_sessao set KEEPALIVE=" . $this->timeCurrent . " WHERE ID_SESSION=" . $id;
		self :: executeSql($SQL);
		return true;
	}

	/**
	* Verifica se a chave de autenticação eh identica 
	* check if key server and client key is valid, identical
	* @access private
	* @input id ,  key
	* @return bolean
	*/
	private function checkServerKey($id, $keyServer) {
		try {
			$SQL_KEY = "SELECT * FROM acs_sessao WHERE ID_SESSION=" . $id;
			self :: prepareSQL($SQL_KEY);
			extract(self :: getLineArray(), EXTR_OVERWRITE);
		} catch (Exception $e) {
			throw new Exception("Sessão Inválida ", 4001);
		}

		$this->keyDb = hash('sha256', $REMOTE_ADDR . str_replace("http://", '', LOGINURL) . $KEYTIME);

		if (($keyServer === $this->keyDb)) {
			return true;
		} else {
			throw new Exception("Chave de autenticação inválida ", 4001);
		}
	}

	/**
	* Registra no banco de dados a chave de keepaive
	* register key for keepalive
	* @access private
	* @input 
	* @return array keys
	*/
	private function registerKey($id, $keyServer) {
		if (self :: checkServerKey($id, $keyServer) == true) {
			return self :: validKey($id);
		} else {
			return false;
		}
	}

	/**
	* Registra em sessao os dados para verificacao
	* register session for valid hmac keys
	* @access public
	* @input $_POST form
	* @return redirect url
	*/
	public function registerSession() {
		if (is_array($_POST)) {

			if (self :: registerKey($_POST['id'], $_POST['salt']) == true) {
				list ($senhaMD5, $senhaSHA1) = explode("|", base64_decode($_POST['password']));

				if (self :: checkPasswd(base64_decode($_POST['username']), $_POST['salt'], $senhaMD5, $senhaSHA1) == true) {

					$_SESSION['SS_IDKEY'] = $_POST['id'];
					$_SESSION['SS_KEYLOGIN'] = $_POST['salt'];
					$_SESSION['SS_TIME'] = $this->timeCurrent;
					$_SESSION['SS_KEYSSESSION'] = hash_hmac('sha256', $_SERVER["REMOTE_ADDR"] . $_POST['username'] . $this->timeCurrent, SESSIONKEY);
					$_SESSION['SS_REMOTE_ADDR'] = $_SERVER["REMOTE_ADDR"];
					$_SESSION['SS_USER_AGENT'] = $_SERVER["HTTP_USER_AGENT"];

					$_SESSION['SS_IDUSER'] = $this->idUser;
					$_SESSION['SS_LOGIN'] = $this->login;
					$_SESSION['SS_QTACESS'] = $this->qtAcess + 1;
					$_SESSION['SS_TRY'] = $this->try;
						;
					$_SESSION['SS_DTACESS'] = $this->lastAcess;
					$_SESSION['SS_NAME'] = $this->name;
					$_SESSION['SS_MAIL'] = $this->mail;
					//self :: logRegister($_SERVER["REMOTE_ADDR"], $this->idUser, 0, "S");

					header("Location: " . LOGINOKURL . "");
					exit; /* Redirect browser */
				} else {
					header("Location: " . LOGINURL . "");
					exit; /* Redirect browser */
				}
			}
		}
	}

	/**
	* Verifica por hmac se a senha eh valida
	* check hmac keys is identical
	* @access private
	* @input user,login,passwd md5, passwd sha1
	* @return id user
	*/
	private function checkPasswd($user, $salt, $passwdMD5, $passwdSHA1) {
		$SQL_PASS = "SELECT  
		A.CD_USUARIO,
		A.TX_LOGIN,
		A.TX_SENHA_MD5,
		A.TX_SENHA_SHA1,
		A.QT_ACESSOS,
		A.ST_REG,
		A.QT_TENTATIVAS,
		DATE_FORMAT(A.DT_ULT_ACESSO,'%d/%m/%Y %H:%i:%s') as LASTACESS,
		A.TX_IP,
		B.NM_USUARIO,
		B.TX_EMAIL
		FROM acs_usuarios_login A
		JOIN acs_usuarios B ON B.CD_USUARIO=A.CD_USUARIO
		WHERE A.TX_LOGIN='" . $user . "'";
		
		//echo $SQL_PASS;die();

		// OBS se for data do acesso anterior seria "DATE_FORMAT(A.DT_ULT_ACESSO,'%d/%m/%Y %H:%i:%s') as LASTACESS,"
		// Se for o acesso atual DATE_FORMAT(CURRENT_TIMESTAMP,'%d/%m/%Y %H:%i:%s') as LASTACESS,

		try {
			self :: prepareSQL($SQL_PASS);
			extract(self :: getLineArray(), EXTR_OVERWRITE);
		} catch (Exception $e) {

			throw new Exception("Senha ou Login Inválido", 4002);
		}

		if ($ST_REG != "A") {

			throw new Exception("Acesso negado", 4003);
		}

		if ($QT_TENTATIVAS > LIMITLOGIN) {
			throw new Exception("Numero de tentativas excedido", 4004);
		}

		if ($TX_IP != null) {
			if ($TX_IP != str_replace(".", '', $_SERVER["REMOTE_ADDR"])) {

				throw new Exception("Usuario sem logoff", 4009);
			}
		}

		//aplico hmac para verificar se as senhas correpondem

		$hashMD5 = hash_hmac('md5', $salt, $TX_SENHA_MD5);
		$hashSHA1 = hash_hmac('sha1', $salt, $TX_SENHA_SHA1);

		if (($passwdMD5 === $hashMD5) AND ($passwdSHA1 === $hashSHA1)) {
			try {
				$SQL_OK = "UPDATE acs_usuarios_login SET QT_ACESSOS=QT_ACESSOS+1,QT_TENTATIVAS=0,DT_ULT_ACESSO=NOW(),TX_IP='" . str_replace(".", '', $_SERVER["REMOTE_ADDR"]) . "' WHERE CD_USUARIO=" . $CD_USUARIO;
				$update = self :: executeSql($SQL_OK);
				//echo $SQL_OK;die();
			} catch (Exception $e) {
				throw new Exception("Falha em atualizar a quantidade de acessos", 4002);
			}

			$this->idUser = $CD_USUARIO;
			$this->login = $TX_LOGIN;
			$this->qtAcess = $QT_ACESSOS;
			$this->try= $QT_TENTATIVAS;
			$this->lastAcess = $LASTACESS;
			$this->name = $NM_USUARIO;
			$this->mail = $TX_EMAIL;

			return $this->idUser;
		} else {
			$SQL_FAIL = "UPDATE acs_usuarios_login SET QT_TENTATIVAS=QT_TENTATIVAS+1 WHERE CD_USUARIO=" . $CD_USUARIO;
			$update = self :: executeSql($SQL_FAIL);
			throw new Exception("Usuário ou senha Inválido", 4005);
		}

	}
	/**
	* Grava na tabela de log 
	* Register log in database 
	* @access private
	* @input ip,id user,exception,sucess or not
	* @return id user
	*/
	private function logRegister($TX_IP, $CD_USUARIO, $CD_EXCEPTION=0, $IN_AUT_OK = "N") {
		try {
			$SQL = "INSERT INTO acs_log_acesso";
			$SQL .= " (TX_IP,CD_USUARIO,CD_EXCEPTION,IN_AUT_OK)";
			$SQL .= " VALUES ";
			$SQL .= " ('" . $TX_IP . "'," . $CD_USUARIO . "," . $CD_EXCEPTION . ",'" . $IN_AUT_OK . "')";

			$INSERT = self :: executeSql($SQL);

			return true;
		} catch (Exception $e) {
			throw new Exception("Falha na gravação do log".$e->getMessage(), 4999);
			return false;
		}

	}
	/**
	* Verifica se a sessão corrente ainda eh valida
	* Atualiza a chave da sessao ou destroi a sessao
	* Check if keys in session are valid
	* @access public
	* @input 
	* @return redirect url , bolean
	*/
	public function checkSession() {

		if (($_SESSION['SS_REMOTE_ADDR'] === $_SERVER["REMOTE_ADDR"]) AND ($_SESSION['SS_USER_AGENT'] === $_SERVER["HTTP_USER_AGENT"])) {

			if (time() > ($_SESSION['SS_TIME'] + (TIMESESSION * 60) + 1)) {
				header("Location: " . LOGINURL . "");
				exit; /* Redirect browser */
			}

			if (time() > $_SESSION['SS_TIME'] + TIMEKEY) {
				if (self :: keepAlive() == false) {
					self :: logRegister($_SERVER["REMOTE_ADDR"], $_SESSION['SS_IDUSER'], 4006, "S");
					throw new Exception("Desconectado por Inatividade", 4006);
				}
			} else {
				return true;
			}

		} else {
			header("Location: " . KICKURL . ""); /* Redirect browser */
		}

	}

	/**
	* Verifica se a chave da sessão eh valida e atualiza
	* update key in session on keealive  
	* @access private
	* @input 
	* @return  bolean
	*/
	private function keepAlive() {
		$keepAlive = false;
		$SQL_PASS = "SELECT TX_LOGIN FROM acs_usuarios_login WHERE CD_USUARIO=" . $_SESSION['SS_IDUSER'];
		self :: prepareSQL($SQL_PASS);
		$login = self :: getRow();

		if ($_SESSION['SS_KEYSSESSION'] === hash_hmac('sha256', $_SERVER["REMOTE_ADDR"] . base64_encode($login) . $_SESSION['SS_TIME'], SESSIONKEY)) {
			if (self :: checkServerKey($_SESSION['SS_IDKEY'], $_SESSION['SS_KEYLOGIN']) == true) {
				if (self :: validKey($_SESSION['SS_IDKEY']) == true) {
					$_SESSION['SS_TIME'] = $this->timeCurrent;
					$_SESSION['SS_KEYSSESSION'] = hash_hmac('sha256', $_SERVER["REMOTE_ADDR"] . base64_encode($login) . $this->timeCurrent, SESSIONKEY);
					$keepAlive = true;
				}
			}
		}
		return $keepAlive;
	}

	# fim da classe
}
?>
Return current item: ooeLite