openrat-cms

OpenRat Content Management System
git clone http://git.code.weiherhei.de/openrat-cms.git
Log | Files | Refs | README

RememberAuth.class.php (3591B)


      1 <?php
      2 
      3 namespace cms\auth;
      4 
      5 use cms\action\Action;
      6 use cms\base\Configuration;
      7 use cms\base\DB;
      8 use cms\base\Startup;
      9 use database\Database;
     10 use cms\model\User;
     11 use logger\Logger;
     12 use util\Cookie;
     13 use security\Password;
     14 use \util\exception\ObjectNotFoundException;
     15 use util\Session;
     16 use util\text\TextMessage;
     17 
     18 /**
     19  * Authentifizierung mit einem Login-Token.
     20  *
     21  * @author dankert
     22  */
     23 class RememberAuth implements Auth
     24 {
     25 	/**
     26 	 * @return null
     27 	 */
     28 	public function username()
     29 	{
     30 		// Ermittelt den Benutzernamen aus den Login-Cookies.
     31 		if ( Cookie::has(Action::COOKIE_TOKEN) &&
     32 			 Cookie::has(Action::COOKIE_DB_ID)    ) {
     33 			try {
     34 				list($selector, $token) = array_pad(explode('.', Cookie::get(Action::COOKIE_TOKEN)), 2, '');
     35 				$dbid = Cookie::get( Action::COOKIE_DB_ID );
     36 
     37 				$allDbConfig = Configuration::subset('database');
     38 
     39 				if (!$allDbConfig->has($dbid)) {
     40 
     41 					Logger::warn( TextMessage::create('Unknown DB-Id ${0}, no login with token possible',[$dbid]) );
     42 					return null;
     43 				}
     44 
     45 				$dbConfig = $allDbConfig->subset($dbid);
     46 
     47 				if (! $dbConfig->is('enabled',true)) {
     48 
     49 					Logger::warn( TextMessage::create('DB-Id ${0} is disabled, no login with login token possible',[$dbid]) );
     50 					return null;
     51 				}
     52 
     53 				$key = 'read'; // Only reading in database.
     54 
     55 				$db = new Database($dbConfig->merge( $dbConfig->subset($key) )->getConfig());
     56 				$db->id = $dbid;
     57 				$db->start();
     58 
     59 				$stmt = $db->sql(<<<SQL
     60                     SELECT userid,{{user}}.name as username,token,token_algo FROM {{auth}}
     61                        LEFT JOIN {{user}} ON {{auth}}.userid = {{user}}.id
     62                     WHERE selector = {selector} AND expires > {now}
     63 SQL
     64 				);
     65 				$stmt->setString('selector', $selector);
     66 				$stmt->setInt   ('now'     , Startup::getStartTime() );
     67 
     68 				$auth = $stmt->getRow();
     69 				$db->disconnect();
     70 
     71 
     72 				if ($auth) {
     73 					$this->makeDBWritable( $dbid ); // FIXME: This is a hack, how to do this better?
     74 					// serial was found.
     75 					$username = $auth['username'];
     76 					$userid   = $auth['userid'  ];
     77 					$user     = new User( $userid );
     78 
     79 					if (Password::check($token, $auth['token'], $auth['token_algo'])) {
     80 						Cookie::set(Action::COOKIE_TOKEN   ,$user->createNewLoginTokenForSerial($selector) );
     81 						DB::get()->commit();
     82 						return $username;
     83 					}
     84 					else {
     85 						// serial match but token mismatched.
     86 						// this means, the token was used on another device before, probably stolen.
     87 						Logger::warn( TextMessage::create('Possible breakin-attempt detected for user ${0}',[$username]));
     88 						$user->deleteAllLoginTokens(); // Disable all token logins for this user.
     89 						Cookie::set(Action::COOKIE_TOKEN ); // Delete token cookie
     90 
     91 						// we must not reset the password here, because the thief might not have it.
     92 
     93 						return null;
     94 					}
     95 				} else {
     96 					// The serial is not found, maybe expired.
     97 					// There is nothing we should do here.
     98 				}
     99 
    100 
    101 			} catch (ObjectNotFoundException $e) {
    102 				// Benutzer nicht gefunden.
    103 			}
    104 		}
    105 
    106 		return null;
    107 	}
    108 
    109 
    110 	/**
    111 	 * Ueberpruefen des Kennwortes ist über den Cookie nicht möglich.
    112 	 */
    113 	public function login($user, $password, $token)
    114 	{
    115 		return Auth::STATUS_FAILED;
    116 	}
    117 
    118 	protected function makeDBWritable( $dbid ) {
    119 
    120 		$oldDB = Session::getDatabase();
    121 		if   ( $oldDB ) {
    122 			$oldDB->rollback();
    123 			$oldDB->disconnect();
    124 		}
    125 
    126 		$dbConfig = Configuration::subset(['database',$dbid]);
    127 
    128 		$key = 'write';
    129 		$writableDB = new Database($dbConfig->merge( $dbConfig->subset($key) )->getConfig());
    130 		$writableDB->id = $dbid;
    131 		$writableDB->start();
    132 
    133 		Session::setDatabase( $writableDB );
    134 	}
    135 }