openrat-cms

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

RememberAuth.class.php (3609B)


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