openrat-cms

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

User.class.php (26396B)


      1 <?php
      2 
      3 namespace cms\model;
      4 
      5 // OpenRat Content Management System
      6 // Copyright (C) 2002-2012 Jan Dankert, cms@jandankert.de
      7 //
      8 // This program is free software; you can redistribute it and/or
      9 // modify it under the terms of the GNU General Public License
     10 // as published by the Free Software Foundation; either version 2
     11 // of the License, or (at your option) any later version.
     12 //
     13 // This program is distributed in the hope that it will be useful,
     14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16 // GNU General Public License for more details.
     17 //
     18 // You should have received a copy of the GNU General Public License
     19 // along with this program; if not, write to the Free Software
     20 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     21 use security\Password;
     22 
     23 
     24 /**
     25  * Darstellen eines Benutzers
     26  *
     27  * @author Jan Dankert
     28  */
     29 class User extends ModelBase
     30 {
     31 	var $userid   = 0;
     32 	var $error    = '';
     33 
     34 	var $name     = '';
     35 	var $fullname = '';
     36 	var $ldap_dn;
     37 	var $tel;
     38 	var $mail;
     39 	var $desc;
     40 	var $style;
     41 	var $isAdmin;
     42 	var $rights;
     43 	var $loginDate = 0;
     44 
     45 	var $language;
     46 	var $timezone;
     47 	var $passwordExpires;
     48 	var $passwordAlgo;
     49 	
     50 	var $lastLogin;
     51 	var $otpSecret;
     52 	var $hotp     ;
     53 	var $hotpCount;
     54 	var $totp     ;
     55 	
     56 	
     57 	
     58 	var $mustChangePassword = false;
     59 	var $groups = null;
     60 	var $loginModuleName = null;
     61 
     62 	// Konstruktor
     63 	public function __construct( $userid='' )
     64 	{
     65 		if   ( is_numeric($userid) )
     66 			$this->userid = $userid;
     67 	}
     68 
     69 
     70     /**
     71      * get all users.
     72      *
     73      * @return array
     74      */
     75 	public static function listAll()
     76 	{
     77 		$sql = db()->sql( 'SELECT id,name '.
     78 		                '  FROM {{user}}'.
     79 		                '  ORDER BY name' );
     80 
     81 		return $sql->getAssoc();
     82 	}
     83 
     84 
     85     /**
     86      * Get all users.
     87      *
     88      * @return array with user objects
     89      */
     90 	public static function getAllUsers()
     91 	{
     92 		$list = array();
     93 		$sql = db()->sql( 'SELECT * '.
     94 		                '  FROM {{user}}'.
     95 		                '  ORDER BY name' );
     96 
     97 		foreach($sql->getAll() as $row )
     98 		{
     99 			$user = new User();
    100 			$user->setDatabaseRow( $row );
    101 
    102 			$list[] = $user;
    103 		}
    104 		
    105 		return $list;
    106 	}
    107 
    108 
    109 	/**
    110 	  * Benutzer als aktiven Benutzer in die Session schreiben.
    111 	  */
    112 	public function setCurrent()
    113 	{
    114 		$this->loginDate = time();
    115 
    116 		\Session::setUser( $this );
    117 	}
    118 
    119 
    120 
    121 	/**
    122 	  * Benutzer als aktiven Benutzer in die Session schreiben.
    123 	  */
    124 	public function updateLoginTimestamp()
    125 	{
    126 	    $stmt = db()->sql( <<<SQL
    127                      UPDATE {{user}}
    128 	                 SET last_login={time}
    129 	                 WHERE id={userid}
    130 SQL
    131 	        );
    132 	    $stmt->setInt( 'time'  ,time() );
    133 	    $stmt->setInt( 'userid',$this->userid  );
    134 
    135 	    // Datenbankabfrage ausfuehren
    136 	    $stmt->query();
    137 	}
    138 
    139 
    140 	/**
    141 	 * Erzeugt eine WHERE-Bedingung zur Verwendung in einer SQL-Anfrage.<br>
    142 	 * Es wird eine Oder-Liste mit allen Gruppen-Ids erzeugt.
    143 	 *
    144 	 * @return String SQL-WHERE-Bedingung
    145 	 */
    146 	function getGroupClause()
    147 	{
    148 		$groupIds = $this->getGroupIds();
    149 		
    150 		if	( count($groupIds) > 0 )
    151 			$groupclause = ' groupid='.implode(' OR groupid=',$groupIds );
    152 		else
    153 			$groupclause = ' 1=0 ';
    154 
    155 		return $groupclause;
    156 	}
    157 
    158 
    159 	/**
    160 	 * Lesen aller Projekte, fuer die der Benutzer berechtigt ist.
    161 	 *
    162 	 * @return Array [Projekt-Id] = Projekt-Name
    163 	 */
    164 	public function getReadableProjects()
    165 	{
    166 		$db = db_connection();
    167 
    168 		if	( $this->isAdmin )
    169 		{
    170 			// Administratoren haben Rechte auf alle Projekte.
    171 			return Project::getAllProjects();
    172 		}
    173 		else
    174 		{
    175 			$groupClause = $this->getGroupClause();
    176 			$sql = $db->sql(<<<SQL
    177 SELECT DISTINCT {{project}}.id,{{project}}.name
    178   FROM {{object}}
    179   LEFT JOIN {{acl}}     ON {{object}}.id  = {{acl}}.objectid 
    180   LEFT JOIN {{project}} ON {{project}}.id = {{object}}.projectid 
    181  WHERE {{object}}.parentid IS NULL     AND
    182        {{acl}}.id          IS NOT NULL AND
    183        (  {{acl}}.userid={userid} OR
    184        $groupClause OR 
    185        ({{acl}}.userid IS NULL AND {{acl}}.groupid IS NULL)) 
    186  ORDER BY {{project}}.name
    187 SQL
    188 );
    189 		$sql->setInt   ( 'userid',$this->userid );
    190 
    191 			return $sql->getAssoc();
    192 		}
    193 		
    194 	}
    195 
    196 
    197 
    198 	/**
    199 	 * Ermittelt alls Projekte, fuer die der Benutzer berechtigt ist.
    200 	 * @return Array [0..n] = Projekt-Id
    201 	 */
    202 	function getReadableProjectIds()
    203 	{
    204 		return array_keys( $this->getReadableProjects() );
    205 	}
    206 
    207 
    208 
    209 	/**
    210 	 * Ermittelt zu diesem Benutzer den Login-Token.
    211 	 */ 
    212 	function createNewLoginToken()
    213 	{
    214 	    $selector = Password::randomHexString(24);
    215 	    $token    = Password::randomHexString(24);
    216 
    217 	    $tokenHash = Password::hash($token,Password::ALGO_SHA1);
    218 
    219 		$stmt = db()->sql( 'SELECT max(id) FROM {{auth}}');
    220 		$count = $stmt->getOne();
    221 
    222 		$stmt = db()->sql( <<<SQL
    223               INSERT INTO {{auth}} (id,userid,selector,token,token_algo,expires,create_date,platform,name)
    224                  VALUES( {id},{userid},{selector},{token},{token_algo},{expires},{create_date},{platform},{name} )
    225 SQL
    226         );
    227 		$expirationPeriodDays = Conf()->subset('user')->subset('security')->get('token_expires_after_days',730);
    228 
    229 		$stmt->setInt( 'id'         ,++$count      );
    230 		$stmt->setInt( 'userid'     ,$this->userid );
    231 
    232 		$stmt->setString( 'selector'   ,$selector     );
    233 		$stmt->setString( 'token'      ,$tokenHash    );
    234 		$stmt->setInt   ( 'token_algo' ,Password::ALGO_SHA1        );
    235 
    236 		$stmt->setInt( 'expires'    ,time() + ($expirationPeriodDays*24*60*60) );
    237 		$stmt->setInt( 'create_date',time()                           );
    238 
    239 		$browser = new \Browser();
    240 		$stmt->setString( 'platform',$browser->platform );
    241 		$stmt->setString( 'name'    ,$browser->name     );
    242 		$row = $stmt->getRow();
    243 
    244 		// Zusammensetzen des Tokens
    245 		return $selector.'.'.$token;
    246 	}
    247 
    248 
    249     /**
    250      * Ermittelt zu diesem Benutzer den Login-Token.
    251      */
    252     function deleteLoginToken( $selector )
    253     {
    254         $stmt = db()->sql( <<<SQL
    255               DELETE FROM {{auth}}
    256                WHERE selector = {selector}
    257 SQL
    258         );
    259         $stmt->setString('selector',$selector );
    260         $stmt->execute();
    261     }
    262 
    263 
    264     /**
    265 	 * Lesen Benutzer aus der Datenbank.
    266 	 */ 
    267 	public function load()
    268 	{
    269 		$stmt = db()->sql( 'SELECT * FROM {{user}}'.
    270 		                ' WHERE id={userid}' );
    271 		$stmt->setInt( 'userid',$this->userid );
    272 		$row = $stmt->getRow();
    273 
    274 		if	( count($row) == 0 )
    275 			throw new \ObjectNotFoundException();
    276 		
    277 		$this->setDatabaseRow( $row );		
    278 	}
    279 
    280 
    281 	/**
    282 	 * Benutzerobjekt �ber Benutzernamen ermitteln.<br>
    283 	 * Liefert ein neues Benutzerobjekt zur�ck.
    284 	 * 
    285 	 * @static 
    286 	 * @param name Benutzername
    287 	 */
    288 	public static function loadWithName( $name )
    289 	{
    290 		// Benutzer �ber Namen suchen
    291 		$sql = db()->sql( 'SELECT id FROM {{user}}'.
    292 		                ' WHERE name={name}' );
    293 		//Html::debug($sql);
    294 		$sql->setString( 'name',$name );
    295 
    296 		$userId = $sql->getOne();
    297 
    298 		if (empty($userId))
    299 		    return null; // no user found.
    300 
    301 		// Benutzer �ber Id instanziieren
    302 		$neuerUser = new \cms\model\User( $userId );
    303 		
    304 		$neuerUser->load();
    305 		
    306 		return $neuerUser;
    307 	}
    308 	
    309 	
    310 	
    311 	/**
    312 	 * Stellt fest, ob der Benutzer korrekt geladen ist.
    313 	 */
    314 	public function isValid()
    315 	{
    316 		return intval($this->userid) > 0;
    317 	}
    318 
    319 
    320 
    321 	/**
    322 	 * Lesen Benutzer aus der Datenbank
    323 	 */
    324 	protected function setDatabaseRow( $row )
    325 	{
    326 		global $conf;
    327 		
    328 		$this->userid    = $row['id'      ];
    329 		$this->name      = $row['name'    ];
    330 		$this->style     = $row['style'   ];
    331 		$this->isAdmin   = ( $row['is_admin'] == '1');
    332 		$this->ldap_dn   = $row['ldap_dn' ];
    333 		$this->fullname  = $row['fullname'];
    334 		$this->tel       = $row['tel'     ];
    335 		$this->mail      = $row['mail'    ];
    336 		$this->desc      = $row['descr'   ];
    337 		$this->language  = $row['language'];
    338 		$this->timezone  = $row['timezone'];
    339 		$this->lastLogin = $row['last_login'];
    340 		$this->otpSecret = $row['otp_secret'];
    341 		$this->hotp      = ($row['hotp']==1);
    342 		$this->hotpCount = $row['hotp_counter'];
    343 		$this->totp      = ($row['totp']==1);
    344 		$this->passwordExpires = $row['password_expires'];
    345 		$this->passwordAlgo    = $row['password_algo'];
    346 		
    347 		if	( $this->fullname == '' )
    348 			$this->fullname = $this->name;
    349 			
    350 		if	( empty($this->style) )
    351 				$this->style = $conf['interface']['style']['default'];
    352 	}
    353 
    354 
    355 
    356 	/**
    357 	 * Namen ermitteln.<br>
    358 	 * Wenn "fullname" gefuellt, dann diesen benutzen, sonst den Benutzernamen.
    359 	 */
    360 	function getName()
    361 	{
    362 		if	( empty($this->fullname))
    363 			return $this->name;
    364 		else
    365 			return $this->fullname;
    366 	}
    367 	
    368 	
    369 	
    370 	/**
    371 	 * Liest einen Benutzernamen aus der Datenbank.
    372 	 * 
    373 	 * @param int Benutzer-Id
    374 	 * @return String Benutzername
    375 	 */
    376 	function getUserName( $userid )
    377 	{
    378 		$db = db_connection();
    379 
    380 		$sql = $db->sql( 'SELECT name FROM {{user}}'.
    381 		                ' WHERE id={userid}' );
    382 		$sql->setInt( 'userid',$userid );
    383 
    384 		$name = $sql->getOne();
    385 		
    386 		if	( $name == '' )
    387 			return lang('UNKNOWN');
    388 		else return $name;
    389 	}
    390 
    391 
    392 	/**
    393 	 * Speichern Benutzer in der Datenbank.
    394 	 */
    395 	function save()
    396 	{
    397 		$db = db_connection();
    398 
    399 		$sql = $db->sql( <<<SQL
    400                          UPDATE {{user}}
    401 		                 SET name={name},
    402 		                     fullname={fullname},
    403 		                     ldap_dn ={ldap_dn} ,
    404 		                     tel     ={tel}     ,
    405 		                     descr   ={desc}    ,
    406 		                     mail    ={mail}    ,
    407 		                     style   ={style}   ,
    408 		                     language = {language},
    409 		                     timezone = {timezone},
    410 		                     is_admin = {isAdmin},
    411 		                     totp     = {totp},
    412 		                     hotp     = {hotp}
    413 		                 WHERE id={userid}
    414 SQL
    415  );
    416 		$sql->setString ( 'name'    ,$this->name    );
    417 		$sql->setString ( 'fullname',$this->fullname);
    418 		$sql->setString ( 'ldap_dn' ,$this->ldap_dn );
    419 		$sql->setString ( 'tel'     ,$this->tel     );
    420 		$sql->setString ( 'desc'    ,$this->desc    );
    421 		$sql->setString ( 'mail'    ,$this->mail    );
    422 		$sql->setString ( 'style'   ,$this->style   );
    423 		$sql->setString ( 'language',$this->language);
    424 		$sql->setString ( 'timezone',$this->timezone);
    425 		$sql->setBoolean( 'isAdmin' ,$this->isAdmin );
    426 		$sql->setBoolean( 'totp'    ,$this->totp    );
    427 		$sql->setBoolean( 'hotp'    ,$this->hotp    );
    428 		$sql->setInt    ( 'userid'  ,$this->userid  );
    429 		
    430 		// Datenbankabfrage ausfuehren
    431 		$sql->query();
    432 	}
    433 
    434 
    435 	/**
    436 	 * Benutzer hinzuf�gen
    437 	 *
    438 	 * @param String $name Benutzername
    439 	 */
    440 	function add( $name = '' )
    441 	{
    442 		if	( $name != '' )
    443 			$this->name = $name;
    444 
    445 		$db = db_connection();
    446 
    447 		$sql = $db->sql('SELECT MAX(id) FROM {{user}}');
    448 		$this->userid = intval($sql->getOne())+1;
    449 
    450 		$sql = $db->sql('INSERT INTO {{user}}'.
    451 		               ' (id,name,password_hash,ldap_dn,fullname,tel,mail,descr,style,is_admin,password_salt)'.
    452 		               " VALUES( {userid},{name},'','','','','','','default',0,'' )" );
    453 		$sql->setInt   ('userid',$this->userid);
    454 		$sql->setString('name'  ,$this->name  );
    455 
    456 		// Datenbankbefehl ausfuehren
    457 		$sql->query();
    458 		
    459 		$this->addNewUserGroups(); // Neue Gruppen hinzufuegen.
    460 		
    461 		$this->renewOTPSecret();
    462 	}
    463 
    464 	
    465 
    466 	/**
    467 	 * Zu einem neuen Benutzer automatisch Gruppen hinzufuegen.
    468 	 * Diese Methode wird automatisch in "add()" aufgerufen.
    469 	 */
    470 	function addNewUserGroups()
    471 	{
    472 		global $conf;
    473 		$groupNames = explode(',',@$conf['security']['newuser']['groups']);
    474 		
    475 		if	( count($groupNames) == 0 )
    476 			return; // Nichts zu tun.
    477 			
    478 		$db = db_connection();
    479 
    480 		$groupNames = "'".implode("','",$groupNames)."'";
    481 		$sql = $db->sql("SELECT id FROM {{group}} WHERE name IN($groupNames)");
    482 		$groupIds = array_unique( $sql->getCol() );
    483 		
    484 		// Wir brauchen hier nicht weiter pr�fen, ob der Benutzer eine Gruppe schon hat, denn
    485 		// - passiert dies nur bei der Neuanlage eines Benutzers
    486 		// - Enth�lt die Group-Id-Liste eine ID nur 1x.
    487 
    488 		// Gruppen diesem Benutzer zuordnen.
    489 		foreach( $groupIds as $groupId )
    490 			$this->addGroup( $groupId );
    491 	}
    492 
    493 
    494 	/**
    495 	 * Benutzer entfernen.<br>
    496 	 * Vor dem Entfernen werden alle Referenzen auf diesen Benutzer entfernt:<br>
    497 	 * - "Erzeugt von" f�r diesen Benutzer entfernen.<br>
    498 	 * - "Letzte �nderung von" f�r diesen Benutzer entfernen<br>
    499 	 * - Alle Archivdaten in Dateien mit diesem Benutzer entfernen<br>
    500 	 * - Alle Berechtigungen dieses Benutzers l?schen<br>
    501 	 * - Alle Gruppenzugehoerigkeiten dieses Benutzers l?schen<br>
    502 	 * - Benutzer loeschen<br>
    503 	 */
    504 	public function delete()
    505 	{
    506 		$db = db_connection();
    507 
    508 		// "Erzeugt von" f�r diesen Benutzer entfernen.
    509 		$sql = $db->sql( 'UPDATE {{object}} '.
    510 		                'SET create_userid=null '.
    511 		                'WHERE create_userid={userid}' );
    512 		$sql->setInt   ('userid',$this->userid );
    513 		$sql->query();
    514 
    515 		// "Letzte �nderung von" f�r diesen Benutzer entfernen
    516 		$sql = $db->sql( 'UPDATE {{object}} '.
    517 		                'SET lastchange_userid=null '.
    518 		                'WHERE lastchange_userid={userid}' );
    519 		$sql->setInt   ('userid',$this->userid );
    520 		$sql->query();
    521 
    522 		// Alle Archivdaten in Dateien mit diesem Benutzer entfernen
    523 		$sql = $db->sql( 'UPDATE {{value}} '.
    524 		                'SET lastchange_userid=null '.
    525 		                'WHERE lastchange_userid={userid}' );
    526 		$sql->setInt   ('userid',$this->userid );
    527 		$sql->query();
    528 
    529 		// Alle Berechtigungen dieses Benutzers l?schen
    530 		$sql = $db->sql( 'DELETE FROM {{acl}} '.
    531 		                'WHERE userid={userid}' );
    532 		$sql->setInt   ('userid',$this->userid );
    533 		$sql->query();
    534 
    535 		// Alle Gruppenzugehoerigkeiten dieses Benutzers l?schen
    536 		$sql = $db->sql( 'DELETE FROM {{usergroup}} '.
    537 		                'WHERE userid={userid}' );
    538 		$sql->setInt   ('userid',$this->userid );
    539 		$sql->query();
    540 
    541         $stmt = db()->sql( <<<SQL
    542               DELETE FROM {{auth}}
    543                WHERE userid={userid}
    544 SQL
    545         );
    546         $stmt->setInt   ('userid',$this->userid );
    547         $stmt->execute();
    548 
    549         // Benutzer loeschen
    550 		$sql = $db->sql( 'DELETE FROM {{user}} '.
    551 		                'WHERE id={userid}' );
    552 		$sql->setInt   ('userid',$this->userid );
    553 		$sql->query();
    554 	}
    555 
    556 
    557 	/**
    558 	 * Ermitteln der Eigenschaften zu diesem Benutzer
    559 	 *
    560 	 * @return array Liste der Eigenschaften als assoziatives Array
    561 	 */
    562 	public function getProperties()
    563 	{
    564 	    return parent::getProperties() + array('id'=>$this->userid,'is_admin'=> $this->isAdmin);
    565 	}
    566 
    567 
    568 
    569 	/**
    570 	 * Setzt ein neues Kennwort fuer diesen Benutzer.
    571 	 * 
    572 	 * @param password Kennwortt
    573 	 * @param always true, wenn Kennwort dauerhaft.
    574 	 */
    575 	function setPassword( $password, $always=true )
    576 	{
    577 		$db = db_connection();
    578 
    579 		$sql = $db->sql( 'UPDATE {{user}} SET password_hash={password},password_algo={algo},password_expires={expires} '.
    580 		                'WHERE id={userid}' );
    581 		                
    582 		if	( $always )
    583 		{
    584 			$algo   = Password::bestAlgoAvailable();
    585 			$expire = null;
    586 		}
    587 		else
    588 		{
    589 			// Klartext-Kennwort, der Benutzer muss das Kennwort beim nä. Login ändern.
    590 			$algo   = Password::ALGO_PLAIN;
    591 			$expire = time();
    592 		}
    593 
    594 		// Hashsumme für Kennwort erzeugen
    595 		if	( $expire == null )
    596 			$sql->setNull('expires');
    597 		else
    598 			$sql->setInt('expires',$expire);
    599 		
    600 		$sql->setInt   ('algo'    ,$algo                                                  );
    601 		$sql->setString('password',Password::hash(User::pepperPassword($password),$algo) );
    602 		$sql->setInt   ('userid'  ,$this->userid  );
    603 
    604 		$sql->query();
    605 	}
    606 
    607 
    608 	/**
    609 	 * Gruppen ermitteln, in denen der Benutzer Mitglied ist.
    610 	 *
    611 	 * @return array mit Id:Name
    612 	 */
    613 	function getGroups()
    614 	{
    615 		if	( !is_array($this->groups) )
    616 		{
    617 			$db = db_connection();
    618 	
    619 			$sql = $db->sql( 'SELECT {{group}}.id,{{group}}.name FROM {{group}} '.
    620 			                'LEFT JOIN {{usergroup}} ON {{usergroup}}.groupid={{group}}.id '.
    621 			                'WHERE {{usergroup}}.userid={userid}' );
    622 			$sql->setInt('userid',$this->userid );
    623 			$this->groups = $sql->getAssoc();
    624 		}
    625 		
    626 		return $this->groups;
    627 	}
    628 	
    629 
    630 	// Gruppen ermitteln, in denen der Benutzer Mitglied ist
    631 	function getGroupIds()
    632 	{
    633 		return array_keys( $this->getGroups() );
    634 
    635 		/*
    636 		$db = db_connection();
    637 
    638 		$sql = $db->sql( 'SELECT groupid FROM {{usergroup}} '.
    639 		                'WHERE userid={userid}' );
    640 		$sql->setInt('userid',$this->userid );
    641 
    642 		return $sql->getCol( $sql );
    643 		*/
    644 	}
    645 	
    646 
    647 	// Gruppen ermitteln, in denen der Benutzer *nicht* Mitglied ist
    648 	function getOtherGroups()
    649 	{
    650 		$db = db_connection();
    651 
    652 		$sql = $db->sql( 'SELECT {{group}}.id,{{group}}.name FROM {{group}}'.
    653 		                '   LEFT JOIN {{usergroup}} ON {{usergroup}}.groupid={{group}}.id AND {{usergroup}}.userid={userid}'.
    654 		                '   WHERE {{usergroup}}.userid IS NULL' );
    655 		$sql->setInt('userid'  ,$this->userid );
    656 
    657 		return $sql->getAssoc();
    658 	}
    659 
    660 
    661 	
    662 	/**
    663 	 * Benutzer zu einer Gruppe hinzufuegen.
    664 	 * 
    665 	 * @param groupid die Gruppen-Id
    666 	 */
    667 	function addGroup( $groupid )
    668 	{
    669 		$db = db_connection();
    670 
    671 		$sql = $db->sql('SELECT MAX(id) FROM {{usergroup}}');
    672 		$usergroupid = intval($sql->getOne())+1;
    673 
    674 		$sql = $db->sql( 'INSERT INTO {{usergroup}} '.
    675 		                '       (id,userid,groupid) '.
    676 		                '       VALUES( {usergroupid},{userid},{groupid} )' );
    677 		$sql->setInt('usergroupid',$usergroupid  );
    678 		$sql->setInt('userid'     ,$this->userid );
    679 		$sql->setInt('groupid'    ,$groupid      );
    680 
    681 		$sql->query();
    682 	
    683 	}
    684 
    685 
    686 	
    687 	/**
    688 	 * Benutzer aus Gruppe entfernen.
    689 	 * 
    690 	 * @param groupid die Gruppen-Id
    691 	 */
    692 	function delGroup( $groupid )
    693 	{
    694 		$db = db_connection();
    695 
    696 		$sql = $db->sql( 'DELETE FROM {{usergroup}} '.
    697 		                '  WHERE userid={userid} AND groupid={groupid}' );
    698 		$sql->setInt   ('userid'  ,$this->userid );
    699 		$sql->setInt   ('groupid' ,$groupid      );
    700 
    701 		$sql->query();
    702 	}
    703 	
    704 
    705 	/**
    706 	 * Ermitteln aller Rechte des Benutzers im aktuellen Projekt.
    707 	 *
    708 	 * @param Integer $projectid  Projekt-Id
    709 	 * @param Integer $languageid Sprache-Id
    710 	 */
    711 	function loadRights( $projectid,$languageid )
    712 	{
    713 	}
    714 
    715 
    716 	/**
    717 	 * Ermitteln aller Berechtigungen des Benutzers.<br>
    718 	 * Diese Daten werden auf der Benutzerseite in der Administration angezeigt.
    719 	 *
    720 	 * @return array
    721 	 */
    722 	function getAllAcls()
    723 	{
    724 
    725 		$this->delRights();
    726 
    727 		$group_clause = $this->getGroupClause();
    728 
    729 		$sql = db()->sql( 'SELECT {{acl}}.*,{{object}}.projectid,{{language}}.name AS languagename FROM {{acl}}'.
    730 		                '  LEFT JOIN {{object}} '.
    731 		                '         ON {{object}}.id={{acl}}.objectid '.
    732 		                '  LEFT JOIN {{language}} '.
    733 		                '         ON {{language}}.id={{acl}}.languageid '.
    734 		                '  WHERE ( {{acl}}.userid={userid} OR '.$group_clause.
    735 		                                                 ' OR ({{acl}}.userid IS NULL AND {{acl}}.groupid IS NULL) )'.
    736 		                '  ORDER BY {{object}}.projectid,{{acl}}.languageid' );
    737 		$sql->setInt  ( 'userid'    ,$this->userid );
    738 
    739 		$aclList = array();
    740 
    741 		foreach($sql->getAll() as $row )
    742 		{
    743 			$acl = new Acl();
    744 			$acl->setDatabaseRow( $row );
    745 			$acl->projectid    = $row['projectid'   ];
    746 			if	( intval($acl->languageid) == 0 )
    747 				$acl->languagename = lang('GLOBAL_ALL_LANGUAGES');
    748 			else
    749 				$acl->languagename = $row['languagename'];
    750 			$aclList[] = $acl;
    751 		}
    752 		
    753 		return $aclList;
    754 	}
    755 
    756 
    757 	/**
    758 	 * Ermitteln aller Berechtigungen.
    759 	 * @return array Berechtigungen
    760 	 */
    761 	function getRights()
    762 	{
    763 		throw new \DomainException('User.class::getRights()');
    764 		
    765 //		$db = db_connection();
    766 //		$var = array();
    767 //
    768 //		// Alle Projekte lesen
    769 //		$sql = $db->sql( 'SELECT id,name FROM {{project}}' );
    770 //		$projects = $sql->getAssoc( $sql );	
    771 //
    772 //		foreach( $projects as $projectid=>$projectname )
    773 //		{
    774 //			$var[$projectid] = array();
    775 //			$var[$projectid]['name'] = $projectname;
    776 //			$var[$projectid]['folders'] = array();
    777 //			$var[$projectid]['rights'] = array();
    778 //
    779 //			$sql = $db->sql( 'SELECT {{acl}}.* FROM {{acl}}'.
    780 //			                '  LEFT JOIN {{folder}} ON {{acl}}.folderid = {{folder}}.id'.
    781 //			                '  WHERE {{folder}}.projectid={projectid}'.
    782 //			                '    AND {{acl}}.userid={userid}' );
    783 //			$sql->setInt('projectid',$projectid    );
    784 //			$sql->setInt('userid'   ,$this->userid );
    785 //			
    786 //			$acls = $sql->getAll( $sql );
    787 //
    788 //			foreach( $acls as $acl )
    789 //			{
    790 //				$aclid = $acl['id'];
    791 //				$folder = new Folder( $acl['folderid'] );
    792 //				$folder->load();
    793 //				$var[$projectid]['rights'][$aclid] = $acl;
    794 //				$var[$projectid]['rights'][$aclid]['foldername'] = implode(' &raquo; ',$folder->parentfolder( false,true ));
    795 //				$var[$projectid]['rights'][$aclid]['delete_url'] = Html::url(array('action'=>'user','subaction'=>'delright','aclid'=>$aclid));
    796 //			}
    797 //			
    798 //			$sql = $db->sql( 'SELECT id FROM {{folder}}'.
    799 //			                '  WHERE projectid={projectid}' );
    800 //			$sql->setInt('projectid',$projectid);
    801 //			$folders = $sql->getCol( $sql );
    802 //
    803 //			$var[$projectid]['folders'] = array();
    804 //
    805 //			foreach( $folders as $folderid )
    806 //			{
    807 //				$folder = new Folder( $folderid );
    808 //				$folder->load();
    809 //				$var[$projectid]['folders'][$folderid] = implode(' &raquo; ',$folder->parentfolder( false,true ));
    810 //			}
    811 //
    812 //			asort( $var[$projectid]['folders'] );
    813 //		}
    814 //		
    815 //		return $var;
    816 	}
    817 
    818 
    819 	/**
    820 	 * Entfernt alle Rechte aus diesem Benutzerobjekt.
    821 	 */
    822 	function delRights()
    823 	{
    824 		$this->rights = array();
    825 	}
    826 
    827 
    828 	/**
    829 	 * Ueberpruft, ob der Benutzer ein bestimmtes Recht hat
    830 	 *
    831 	 * @param $objectid Objekt-Id zu dem Objekt, dessen Rechte untersucht werden sollen
    832 	 * @param $type Typ des Rechts (Lesen,Schreiben,...) als Konstante Acl::ACL_*
    833 	 */ 
    834 	function hasRight( $objectid,$type )
    835 	{
    836 		global $conf;
    837 		if	( $this->isAdmin && !$conf['security']['readonly'] )
    838 			return true;
    839 
    840 		if	( $this->isAdmin && $type & Acl::ACL_READ )
    841 			return true;
    842 			
    843 		if	( !isset($this->rights[$objectid]) )
    844 			return false;
    845 
    846 		return $this->rights[$objectid] & $type;
    847 	}
    848 
    849 
    850 	/**
    851 	 * Berechtigung dem Benutzer hinzufuegen.
    852 	 * 
    853 	 * @param objectid Objekt-Id, zu dem eine Berechtigung hinzugefuegt werden soll
    854 	 * @param Art des Rechtes, welches hinzugefuegt werden soll
    855 	 */
    856 	function addRight( $objectid,$type )
    857 	{
    858 		global $conf;
    859 		
    860 		if	( $conf['security']['readonly'] )
    861 			if	( $type & Acl::ACL_READ )
    862 				$type = Acl::ACL_READ;
    863 			else
    864 				$type = 0;
    865 
    866 		if	( $type & Acl::ACL_PUBLISH && $conf['security']['nopublish'] )
    867 			$type -= Acl::ACL_PUBLISH;
    868 
    869 
    870 		if	( !isset($this->rights[$objectid]) )
    871 			$this->rights[$objectid] = 0;
    872 
    873 		$this->rights[$objectid] = $this->rights[$objectid] | $type;
    874 	}
    875 
    876 
    877 	/**
    878 	 * Ermitteln aller zur Verfuegung stehenden Stylesheets
    879 	 */
    880 	public function getAvailableStyles()
    881 	{
    882 		global $conf;
    883 		$styles = array();
    884 		
    885 		foreach( $conf['style'] as $key=>$values)
    886 			$styles[$key] = $values['name'];
    887 
    888 		return $styles;	
    889 	}
    890 	
    891 	/**
    892 	 * Ueberpruefen des Kennwortes.
    893 	 *
    894 	 * Es wird festgestellt, ob das Kennwort dem des Benutzers entspricht.
    895 	 * Es wird dabei nur gegen die interne Datenbank geprüft. Weitere
    896 	 * Loginmodule werden nicht aufgerufen!
    897 	 * Diese Methode darf kein Bestandteil des Logins sein, da nur das Kennwort geprüft wird!
    898 	 * Kennwortablauf und Token werden nicht geprüft!
    899 	 */
    900 	function checkPassword( $password )
    901 	{
    902 		$db = db_connection();
    903 		// Laden des Benutzers aus der Datenbank, um Password-Hash zu ermitteln.
    904 		$sql = $db->sql( 'SELECT * FROM {{user}}'.
    905 			' WHERE id={userid}' );
    906 		$sql->setInt( 'userid',$this->userid );
    907 		$row_user = $sql->getRow();
    908 		
    909 		// Pruefen ob Kennwort mit Datenbank uebereinstimmt.
    910 		return Password::check(User::pepperPassword($password),$row_user['password_hash'],$row_user['password_algo']);
    911 	}
    912 	
    913 	
    914 	/**
    915 	 * Erzeugt ein aussprechbares Kennwort.
    916 	 * 
    917 	 * Inspired by http://www.phpbuilder.com/annotate/message.php3?id=1014451
    918 	 * 
    919 	 * @return String Zuf�lliges Kennwort
    920 	 */
    921 	function createPassword()
    922 	{
    923 		global $conf;
    924 		
    925 		$pw = '';
    926 		$c  = 'bcdfghjklmnprstvwz'; //consonants except hard to speak ones
    927 		$v  = 'aeiou';              //vowels
    928 		$a  = $c.$v;                //both
    929 		 
    930 		//use two syllables...
    931 		for ( $i=0; $i < intval($conf['security']['password']['min_length'])/3; $i++ )
    932 		{
    933 			$pw .= $c[rand(0, strlen($c)-1)];
    934 			$pw .= $v[rand(0, strlen($v)-1)];
    935 			$pw .= $a[rand(0, strlen($a)-1)];
    936 		}
    937 		//... and add a nice number
    938 		$pw .= rand(10,99);
    939 		 
    940 		return $pw;
    941 	}
    942 
    943 	
    944 	/**
    945 	 * Das Kennwort "pfeffern".
    946 	 * 
    947 	 * Siehe http://de.wikipedia.org/wiki/Salt_%28Kryptologie%29#Pfeffer
    948 	 * für weitere Informationen.
    949 	 * 
    950 	 * @param Kennwort
    951 	 * @return Das gepfefferte Kennwort
    952 	 */
    953 	public static function pepperPassword( $pass )
    954 	{
    955 		$salt = Conf()->subset('security')->subset('password')->get('pepper');
    956 
    957 		return $salt.$pass;
    958 	}
    959 	
    960 	
    961 	/**
    962 	 * Ermittelt projektübergreifend die letzten Änderungen des Benutzers.
    963 	 *
    964 	 * @return array <string, unknown>
    965 	 */
    966 	public function getLastChanges()
    967 	{
    968 		$db = db_connection();
    969 	
    970 		$sql = $db->sql( <<<SQL
    971 		SELECT {{object}}.id       as objectid,
    972 		       {{object}}.filename as filename,
    973 		       {{object}}.typeid   as typeid,
    974 		       {{object}}.lastchange_date as lastchange_date,
    975 		       {{project}}.id      as projectid,
    976 			   {{project}}.name    as projectname
    977 		  FROM {{object}}
    978 		LEFT JOIN {{project}}
    979 		       ON {{object}}.projectid = {{project}}.id
    980 		   WHERE {{object}}.lastchange_userid = {userid}
    981 		ORDER BY {{object}}.lastchange_date DESC
    982 SQL
    983 		);
    984 	
    985 		$sql->setInt( 'userid', $this->userid );
    986 	
    987 		return $sql->getAll();
    988 	
    989 	}
    990 	
    991 	
    992 	/**
    993 	 * Calculate the code, with given secret and point in time.
    994 	 *
    995 	 * @param string   $secret
    996 	 * @param int|null $timeSlice
    997 	 *
    998 	 * @return string
    999 	 */
   1000 	public function getTOTPCode()
   1001 	{
   1002 	    $codeLength = 6;
   1003 	    $timeSlice = floor(time() / 30);
   1004 	    $secretkey = @hex2bin($this->otpSecret);
   1005 	    // Pack time into binary string
   1006 	    $time = chr(0).chr(0).chr(0).chr(0).pack('N*', $timeSlice);
   1007 	    // Hash it with users secret key
   1008 	    $hm = hash_hmac('SHA1', $time, $secretkey, true);
   1009 	    // Use last nipple of result as index/offset
   1010 	    $offset = ord(substr($hm, -1)) & 0x0F;
   1011 	    // grab 4 bytes of the result
   1012 	    $hashpart = substr($hm, $offset, 4);
   1013 	    // Unpak binary value
   1014 	    $value = unpack('N', $hashpart);
   1015 	    $value = $value[1];
   1016 	    // Only 32 bits
   1017 	    $value = $value & 0x7FFFFFFF;
   1018 	    $modulo = pow(10, $codeLength);
   1019 	    return str_pad($value % $modulo, $codeLength, '0', STR_PAD_LEFT);
   1020 	}
   1021 	
   1022 	
   1023 	/**
   1024 	 * Erzeugt ein neues OTP-Secret.
   1025 	 */
   1026 	public function renewOTPSecret() {
   1027 	    
   1028 	    $secret = Password::randomHexString(64);
   1029 	    
   1030 	    $db = db_connection();
   1031 	    
   1032 	    $stmt = $db->sql('UPDATE {{user}} SET otp_secret={secret} WHERE id={id}');
   1033 	    
   1034 	    $stmt->setString( 'secret', $secret       );
   1035 	    $stmt->setInt   ( 'id'    , $this->userid );
   1036 	    
   1037 	    $stmt->execute();
   1038 	    
   1039 	}
   1040 	
   1041 }
   1042