summaryrefslogblamecommitdiffstats
path: root/inc/user.inc.php
blob: 6e3c06da6aaa910aff7ce9b46ca97233ff8c0101 (plain) (tree)
1
2
3
4
5
6
7
8
9








                                            
                                            




















                                                                        




                                            




                                        



                                                  
                                             

         






                                                 






                                                                                






                                                













                                                                                                                    
                                                                                     
         


                                        

                                                                                     
         
 




                                                 







                                                   







                                                    




                                                    











                                                        

                                                                                                                          
                                                                                                                       


                                           






                                                 


                                     
                                                                                    

                                       
                                              
                                                       

                                                                          
                                                                                                                     
                                                                                                                           
                                                                                                                                                       
                                 
                                                  
                                             
                         
                                                 
                                                                                                                                                                                                                         
                                                              


                                                  
                                             

                                 
                                   





                                                                                            


                                                                                                                                                  

                                                                                 
                 
                                     





                                                   

                                                         
                                         
                                            




                                                                           
                                                                                                                   

                                                                                                        
                                                      
                                                                                                                              


                                                        
                                                 
                                                                                                               
                                                              



                                                                                                                                                                        
                                               
                                                                                                                                                                          



                                                                      
                                                        



                                                         
                                                                                
                                     
                                                                                             






                                                                           
                                                                         


                                                      




                                                                                                                                                   
                                                                                   
                                                                                  
                                                                          


                                                                                                                                                                      
                                                                                   
                                                                                  
                                                                           








                                                                                        
                                 
                                                                                                                       
                                                                                 
                                                                                                                             

                                                                  

                           
                                                                                                                       
                                                                                                    
                                                                                                                                                                     




                                                                        

                           
                            

         





                                                                                                             

                                                       



                                 




                                                                                                          

                                                       


                                                                 
 

                                                  
                                                                                                                                       

                                     
                                                             









                                                                                                                                                                                              


                                                            
                                                                                                                                                          
                 
                                  
                                    
                                                                   


                                                     


                        






                                                                                                                                     
 
<?php

class User
{

	private static $user = false;
	private static $organization = NULL;
	private static $isShib = false;
	private static $isInDb = false;
	private static $isAnonymous = false;

	public static function isLoggedIn()
	{
		return self::$user !== false;
	}

	public static function isShibbolethAuth()
	{
		return self::$isShib;
	}

	public static function isInDatabase()
	{
		return self::$isInDb;
	}

	public static function isLocalOnly()
	{
		return self::$user !== false && self::$isShib === false;
	}

	public static function isAnonymous()
	{
		return self::$isAnonymous;
	}

	public static function getData()
	{
		return self::$user;
	}

	public static function getId()
	{
		if (!isset(self::$user['userid']))
			return false;
		return self::$user['userid'];
	}

	public static function getMail()
	{
		if (!isset(self::$user['email']))
			return false;
		return self::$user['email'];
	}

	public static function getName()
	{
		if (!self::isLoggedIn())
			return false;
		return self::$user['firstname'] . ' ' . self::$user['lastname'];
	}

	public static function getFirstName()
	{
		if (!self::isLoggedIn())
			return false;
		return self::$user['firstname'];
	}

	public static function getLastName()
	{
		if (!self::isLoggedIn())
			return false;
		return self::$user['lastname'];
	}

	public static function hasFullName()
	{
		return self::$user !== false && !empty(self::$user['firstname']) && !empty(self::$user['lastname']);
	}

	public static function isTutor()
	{
		return isset(self::$user['role']) && self::$user['role'] === 'TUTOR';
	}
	
	public static function isAdmin()
	{
		// TODO: per Institution...
		return in_array(self::getShibId(), unserialize(CONFIG_ADMINS), true);
	}

	/**
	 * Organization ID used locally in our DB
	 *
	 * @return string
	 */
	public static function getOrganizationId()
	{
		$org = self::getOrganization();
		if (!isset($org['organizationid']))
			return false;
		return $org['organizationid'];
	}

	public static function getOrganizationName()
	{
		$org = self::getOrganization();
		if (!isset($org['name']))
			return false;
		return $org['name'];
	}

	/**
	 * Organization ID as supplied by shibboleth
	 *
	 * @return string
	 */
	public static function getRemoteOrganizationId()
	{
		if (empty(self::$user['organization']))
			return false;
		return self::$user['organization'];
	}

	public static function getOrganization()
	{
		if (!self::isLoggedIn())
			return false;
		if (is_null(self::$organization)) {
			self::$organization = Database::queryFirst('SELECT organizationid, name FROM organization_suffix '
					. ' INNER JOIN organization USING (organizationid) '
					. ' WHERE suffix = :org LIMIT 1', array('org' => self::$user['organization']));
		}
		return self::$organization;
	}
	
	public static function getShibId()
	{
		if (empty(self::$user['shibid']))
			return false;
		return self::$user['shibid'];
	}

	public static function load()
	{
		//file_put_contents('/tmp/test-' . time(), print_r($_SERVER, true));
		if (self::isLoggedIn())
			return true;
		$hasSession = Session::load();
		if (empty($_SERVER['persistent-id'])) {
			if (Session::getUid() === false) {
				if (!empty($_SERVER['Shib-Session-ID'])) {
					Message::addError('Sie haben sich erfolgreich mittels {{0}} authentifiziert,'
						. ' aber der IdP Ihrer Einrichtung scheint die benötigten Metadaten nicht'
						. ' an den {{1}}-SP zu übermitteln. Bitte wenden Sie sich an den Support.', CONFIG_IDM, CONFIG_SUITE);
				}
				Session::delete();
				return false;
			}
			// Try user from local DB
			self::$user = Database::queryFirst('SELECT userid, shibid, organizationid AS organization, firstname, lastname, email FROM user WHERE userid = :uid LIMIT 1', array('uid' => Session::getUid()));
			self::$isInDb = self::$user !== false;
			if (!self::$isInDb) {
				Session::delete();
			}
			return self::$isInDb;
		}
		// Try bwIDM etc.
		if (!$hasSession) {
			// Make sure cookies are enabled
			if (!empty($_SERVER['Shib-Session-ID'])) {
				if (isset($_GET['force-cookie']))
					die('Bitte aktivieren Sie Cookies und Javascript!');

			}
			Session::create();
			Session::set('token', md5(mt_rand() . $_SERVER['REMOTE_ADDR'] . microtime(true) . $_SERVER['persistent-id'] . mt_rand()));
			Session::save();
			if (!empty($_SERVER['Shib-Session-ID']))
				Util::redirect('?do=Main&force-cookie=true.dat');
		}
		self::$isShib = true;
		if (!isset($_SERVER['sn']))
			$_SERVER['sn'] = '';
		if (!isset($_SERVER['givenName']))
			$_SERVER['givenName'] = '';
		if (!isset($_SERVER['mail']))
			$_SERVER['mail'] = '';
		$shibId = md5($_SERVER['persistent-id']);
		self::$user = array(
			'userid' => NULL,
			'shibid' => $shibId,
			'firstname' => $_SERVER['givenName'],
			'lastname' => $_SERVER['sn'],
			'email' => $_SERVER['mail'],
		);
		// Figure out whether the user should be considered a tutor
		if (isset($_SERVER['affiliation']) && (strpos(";{$_SERVER['affiliation']}", ';employee@') !== false
					|| strpos(";{$_SERVER['affiliation']}", ';staff@') !== false
					|| strpos(";{$_SERVER['affiliation']}", ';faculty@') !== false))
			self::$user['role'] = 'TUTOR';
		elseif (isset($_SERVER['entitlement']) && strpos(";{$_SERVER['entitlement']};", CONFIG_ENTITLEMENT) !== false)
			self::$user['role'] = 'TUTOR';
		else
			self::$user['role'] = 'STUDENT';
		// Try to figure out organization
		if (isset($_SERVER['eppn']) && preg_match('/@([0-9a-zA-Z\-\._]+)$/', $_SERVER['eppn'], $out)) {
			self::$user['organization'] = $out[1];
		}
		if (!isset(self::$user['organization']) && isset($_SERVER['affiliation']) && preg_match('/@([0-9a-zA-Z\-\._]+)(;|$)/', $_SERVER['affiliation'], $out)) {
			self::$user['organization'] = $out[1];
		}
		// Get matching db entry if any
		$user = Database::queryFirst('SELECT userid, firstname, lastname, email, fixedname FROM user WHERE shibid = :shibid LIMIT 1', array('shibid' => $shibId));
		if ($user === false) {
			// No match in database, user is not signed up
			return true;
		}
		self::$user['userid'] = $user['userid'];
		if (Session::getUid() === false) {
			Session::setUid($user['userid']);
			Session::save();
		}
		// Already signed up, see if we can fetch missing fields from DB
		self::$isInDb = true;
		self::$isAnonymous = (empty($user['firstname']) && empty($user['lastname']));
		foreach (array('firstname', 'lastname', 'email') as $key) {
			if (empty(self::$user[$key]))
				self::$user[$key] = $user[$key];
		}
		return true;
	}

	public static function deploy($anonymous, $existingLogin = false)
	{
		if (empty(self::$user['shibid']))
			Util::traceError('NO SHIBID');

		// Merging with test-account:
		if (!empty($existingLogin)) {
			if ($anonymous) {
				$ret = Database::exec("UPDATE user SET shibid = :shibid, firstname = '', lastname = '', email = '', password = '' "
					. " WHERE userid = :userid LIMIT 1", array(
						'shibid' => self::$user['shibid'],
						'userid' => $existingLogin
					));
			} else {
				$ret = Database::exec("UPDATE user SET shibid = :shibid, password = '', firstname = :firstname, lastname = :lastname, email = :email "
					. " WHERE userid = :userid LIMIT 1", array(
						'shibid' => self::$user['shibid'],
						'userid' => $existingLogin,
						'firstname' => self::$user['firstname'],
						'lastname' => self::$user['lastname'],
						'email' => self::$user['email']
					));
			}
			return $ret > 0;
		}
		
		// New account
		if ($anonymous) {
			Database::exec("INSERT INTO user (shibid, userid, organizationid, firstname, lastname, email) "
				. " VALUES (:shibid, :shibid, :org, '', '', '') "
				. " ON DUPLICATE KEY UPDATE firstname = '', lastname = '', email = '', password = ''", array(
				'shibid' => self::$user['shibid'],
				'org' => self::getOrganizationId()
			));
		} else {
			Database::exec("INSERT INTO user (shibid, userid, organizationid, firstname, lastname, email) "
				. " VALUES (:shibid, :shibid, :org, :firstname, :lastname, :email) "
				. " ON DUPLICATE KEY UPDATE firstname = VALUES(firstname), lastname = VALUES(lastname), email = VALUES(email), password = ''", array(
				'shibid' => self::$user['shibid'],
				'firstname' => self::$user['firstname'],
				'lastname' => self::$user['lastname'],
				'email' => self::$user['email'],
				'org' => self::getOrganizationId()
			));
		}
		return true;
	}

	public static function updatePassword($pass)
	{
		if (!self::isLoggedIn() || self::$isShib || !self::$isInDb)
			return false;
		$pw = Crypto::hash6($pass);
		$ret = Database::exec('UPDATE user SET password = :pass WHERE userid = :user LIMIT 1', array(
				'pass' => $pw,
				'user' => self::getId()
		));
		return $ret == 1;
	}

	public static function updateMail($mail)
	{
		if (!self::isLoggedIn() || self::$isShib || !self::$isInDb)
			return false;
		$ret = Database::exec('UPDATE user SET email = :mail WHERE userid = :user LIMIT 1', array(
				'mail' => $mail,
				'user' => self::getId()
		));
		return $ret == 1 || $mail === self::get('email');
	}

	public static function login($user, $pass)
	{
		$ret = Database::queryFirst('SELECT userid, password FROM user WHERE userid = :user LIMIT 1', array(':user' => $user));
		if ($ret === false)
			return false;
		if (!Crypto::verify($pass, $ret['password']))
			return false;
		Session::create();
		Session::setUid($ret['userid']);
		Session::set('token', md5(rand() . time() . mt_rand() . $_SERVER['REMOTE_ADDR'] . rand() . $_SERVER['REMOTE_PORT'] . rand() . $_SERVER['HTTP_USER_AGENT'] . microtime(true)));
		Session::save();
		return true;
	}

	public static function logout()
	{
		foreach ($_COOKIE as $name => $value) {
			if (substr($name, 0, 5) !== '_shib')
				continue;
			@setcookie($name, '', time() - CONFIG_SESSION_TIMEOUT, null, null, !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off', true);
		}
		Session::delete();
		if (self::$isShib) {
			Header('Location: /Shibboleth.sso/Logout');
		} else {
			Header('Location: ?do=Main');
		}
		exit(0);
	}

	public static function delete()
	{
		if (!User::isLoggedIn() || !User::isInDatabase())
			return true;
		return Database::exec("DELETE FROM user WHERE userid = :userid LIMIT 1", array('userid' => User::getId()), true) > 0;
	}

}