ILIAS  Release_3_10_x_branch Revision 61812
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.ilShibboleth.php
Go to the documentation of this file.
1 <?php
2 /*
3  +-----------------------------------------------------------------------------+
4  | ILIAS open source |
5  +-----------------------------------------------------------------------------+
6  | Copyright (c) 1998-2001 ILIAS open source, University of Cologne |
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  +-----------------------------------------------------------------------------+
22 */
23 
24 
25 define('AUTH_IDLED', -1);
26 define('AUTH_EXPIRED', -2);
27 define('AUTH_WRONG_LOGIN', -3);
28 
39 class ShibAuth
40 {
46  var $username;
47 
53  var $_sessionName = '_authsession';
54 
60  var $status = '';
61 
70  var $expire = 0;
71 
82  var $idle = 0;
83 
90  var $idled = false;
91 
96  function ShibAuth($authParams, $updateUserData = false)
97  {
98  $this->updateUserData = $updateUserData;
99 
100  if (!empty($authParams['sessionName'])) {
101  $this->_sessionName = $authParams['sessionName'];
102  unset($authParams['sessionName']);
103  }
104 
105  }
106 
112  function getAuth()
113  {
114  $session = &$this->_importGlobalVariable('session');
115 
116  if (!empty($session) &&
117  (isset($session[$this->_sessionName]['registered']) &&
118  $session[$this->_sessionName]['registered'] === true))
119  {
120  return true;
121  } else {
122  return false;
123  }
124  }
125 
133  function setIdle($time, $add = false)
134  {
135  if ($add) {
136  $this->idle += $time;
137  } else {
138  $this->idle = $time;
139  }
140  }
141 
142 
151  function setExpire($time, $add = false)
152  {
153  if ($add) {
154  $this->expire += $time;
155  } else {
156  $this->expire = $time;
157  }
158  }
159 
166  function checkAuth()
167  {
168  $session = &$this->_importGlobalVariable('session');
169 
170  if (isset($session[$this->_sessionName])) {
171  // Check if authentication session is expired
172  if ($this->expire > 0 &&
173  isset($session[$this->_sessionName]['timestamp']) &&
174  ($session[$this->_sessionName]['timestamp'] + $this->expire) < time()) {
175 
176  $this->logout();
177  $this->expired = true;
178  $this->status = AUTH_EXPIRED;
179 
180  return false;
181  }
182 
183  // Check if maximum idle time is reached
184  if ($this->idle > 0 &&
185  isset($session[$this->_sessionName]['idle']) &&
186  ($session[$this->_sessionName]['idle'] + $this->idle) < time()) {
187 
188  $this->logout();
189  $this->idled = true;
190  $this->status = AUTH_IDLED;
191 
192  return false;
193  }
194 
195  if (isset($session[$this->_sessionName]['registered']) &&
196  isset($session[$this->_sessionName]['username']) &&
197  $session[$this->_sessionName]['registered'] == true &&
198  $session[$this->_sessionName]['username'] != '') {
199 
200  Auth::updateIdle();
201 
202  return true;
203  }
204  }
205 
206  return false;
207  }
208 
215  function start()
216  {
217  @session_start();
218 
219  if (!$this->checkAuth()) {
220  //$this->login();
221  }
222  }
223 
230  function login()
231  {
232 
233  global $ilias, $rbacadmin;
234 
235  if (!empty($_SERVER[$ilias->getSetting('shib_login')]))
236  {
237  // Store user's Shibboleth sessionID for logout
238  $session = &$this->_importGlobalVariable('session');
239  $session[$this->_sessionName]['shibboleth_session_id'] = $_SERVER['Shib-Session-ID'];
240 
241  // Get loginname of user, new login name is generated if user is new
242  $username = $this->generateLogin();
243 
244  // Authorize this user
245  $this->setAuth($username);
246 
247  $userObj = new ilObjUser();
248 
249  // Check wether this account exists already, if not create it
251  {
252 
253  $newUser["firstname"] = $this->getFirstString($_SERVER[$ilias->getSetting('shib_firstname')]);
254  $newUser["lastname"] = $this->getFirstString($_SERVER[$ilias->getSetting('shib_lastname')]);
255  $newUser["login"] = $username;
256 
257  // Password must be random to prevent users from manually log in using the login data from Shibboleth users
258  $newUser["passwd"] = md5(end(ilUtil::generatePasswords(1)));
259  $newUser["passwd_type"] = IL_PASSWD_MD5;
260 
261  if (
262  $ilias->getSetting('shib_update_gender')
263  && ($_SERVER[$ilias->getSetting('shib_gender')] == 'm'
264  || $_SERVER[$ilias->getSetting('shib_gender')] =='f')
265  )
266  {
267  $newUser["gender"] = $_SERVER[$ilias->getSetting('shib_gender')];
268  }
269 
270  // Save mapping between ILIAS user and Shibboleth uniqueID
271  $newUser["ext_account"] = $_SERVER[$ilias->getSetting('shib_login')];
272 
273  // other data
274  $newUser["title"] = $_SERVER[$ilias->getSetting('shib_title')];
275  $newUser["institution"] = $_SERVER[$ilias->getSetting('shib_institution')];
276  $newUser["department"] = $_SERVER[$ilias->getSetting('shib_department')];
277  $newUser["street"] = $_SERVER[$ilias->getSetting('shib_street')];
278  $newUser["city"] = $_SERVER[$ilias->getSetting('shib_city')];
279  $newUser["zipcode"] = $_SERVER[$ilias->getSetting('shib_zipcode')];
280  $newUser["country"] = $_SERVER[$ilias->getSetting('shib_country')];
281  $newUser["phone_office"] = $this->getFirstString($_SERVER[$ilias->getSetting('shib_phone_office')]);
282  $newUser["phone_home"] = $this->getFirstString($_SERVER[$ilias->getSetting('shib_phone_home')]);
283  $newUser["phone_mobile"] = $this->getFirstString($_SERVER[$ilias->getSetting('shib_phone_mobile')]);
284  $newUser["fax"] = $this->getFirstString($_SERVER[$ilias->getSetting('shib_fax')]);
285  $newUser["matriculation"] = $_SERVER[$ilias->getSetting('shib_matriculation')];
286  $newUser["email"] = $this->getFirstString($_SERVER[$ilias->getSetting('shib_email')]);
287  $newUser["hobby"] = $_SERVER[$ilias->getSetting('shib_hobby')];
288  $newUser["auth_mode"] = "shibboleth";
289 
290 
291  // system data
292  $userObj->assignData($newUser);
293  $userObj->setTitle($userObj->getFullname());
294  $userObj->setDescription($userObj->getEmail());
295  $userObj->setLanguage($this->getFirstString($_SERVER[$ilias->getSetting('shib_language')]));
296 
297  // Time limit
298  $userObj->setTimeLimitOwner(7);
299  $userObj->setTimeLimitUnlimited(1);
300  $userObj->setTimeLimitFrom(time());
301  $userObj->setTimeLimitUntil(time());
302 
303  // Modify user data before creating the user
304  // Include custom code that can be used to further modify
305  // certain Shibboleth user attributes
306  if ( $ilias->getSetting('shib_data_conv')
307  && $ilias->getSetting('shib_data_conv') != ''
308  && is_readable($ilias->getSetting('shib_data_conv'))
309  )
310  {
311  include($ilias->getSetting('shib_data_conv'));
312  }
313 
314  // Create use in DB
315  $userObj->create();
316  $userObj->setActive(1, 6);
317 
318  $userObj->updateOwner();
319 
320  //insert user data in table user_data
321  $userObj->saveAsNew();
322 
323  // store acceptance of user agreement
324  //$userObj->writeAccepted();
325 
326  // setup user preferences
327  $userObj->writePrefs();
328 
329  //set role entries
330  $rbacadmin->assignUser($ilias->getSetting('shib_user_default_role'), $userObj->getId(),true);
331 
332  unset($userObj);
333 
334  }
335  else
336  {
337  // Update user account
338  $userObj->checkUserId();
339  $userObj->read();
340 
341  if (
342  $ilias->getSetting('shib_update_gender')
343  && ($_SERVER[$ilias->getSetting('shib_gender')] == 'm'
344  || $_SERVER[$ilias->getSetting('shib_gender')] =='f')
345  )
346  $userObj->setGender($_SERVER[$ilias->getSetting('shib_gender')]);
347 
348  if ($ilias->getSetting('shib_update_title'))
349  $userObj->setTitle($_SERVER[$ilias->getSetting('shib_title')]);
350 
351  $userObj->setFirstname($this->getFirstString($_SERVER[$ilias->getSetting('shib_firstname')]));
352  $userObj->setLastname($this->getFirstString($_SERVER[$ilias->getSetting('shib_lastname')]));
353  $userObj->setFullname();
354  if ($ilias->getSetting('shib_update_institution'))
355  $userObj->setInstitution($_SERVER[$ilias->getSetting('shib_institution')]);
356  if ($ilias->getSetting('shib_update_department'))
357  $userObj->setDepartment($_SERVER[$ilias->getSetting('shib_department')]);
358  if ($ilias->getSetting('shib_update_street'))
359  $userObj->setStreet($_SERVER[$ilias->getSetting('shib_street')]);
360  if ($ilias->getSetting('shib_update_city'))
361  $userObj->setCity($_SERVER[$ilias->getSetting('shib_city')]);
362  if ($ilias->getSetting('shib_update_zipcode'))
363  $userObj->setZipcode($_SERVER[$ilias->getSetting('shib_zipcode')]);
364  if ($ilias->getSetting('shib_update_country'))
365  $userObj->setCountry($_SERVER[$ilias->getSetting('shib_country')]);
366  if ($ilias->getSetting('shib_update_phone_office'))
367  $userObj->setPhoneOffice($this->getFirstString($_SERVER[$ilias->getSetting('shib_phone_office')]));
368  if ($ilias->getSetting('shib_update_phone_home'))
369  $userObj->setPhoneHome($this->getFirstString($_SERVER[$ilias->getSetting('shib_phone_home')]));
370  if ($ilias->getSetting('shib_update_phone_mobile'))
371  $userObj->setPhoneMobile($this->getFirstString($_SERVER[$ilias->getSetting('shib_phone_mobile')]));
372  if ($ilias->getSetting('shib_update_fax'))
373  $userObj->setFax($_SERVER[$ilias->getSetting('shib_fax')]);
374  if ($ilias->getSetting('shib_update_matriculation'))
375  $userObj->setMatriculation($_SERVER[$ilias->getSetting('shib_matriculation')]);
376  if ($ilias->getSetting('shib_update_email'))
377  $userObj->setEmail($this->getFirstString($_SERVER[$ilias->getSetting('shib_email')]));
378  if ($ilias->getSetting('shib_update_hobby'))
379  $userObj->setHobby($_SERVER[$ilias->getSetting('shib_hobby')]);
380 
381  if ($ilias->getSetting('shib_update_language'))
382  $userObj->setLanguage($_SERVER[$ilias->getSetting('shib_language')]);
383 
384  // Include custom code that can be used to further modify
385  // certain Shibboleth user attributes
386  if ( $ilias->getSetting('shib_data_conv')
387  && $ilias->getSetting('shib_data_conv') != ''
388  && is_readable($ilias->getSetting('shib_data_conv'))
389  )
390  {
391  include($ilias->getSetting('shib_data_conv'));
392  }
393 
394 
395  $userObj->update();
396 
397  }
398 
399  // we are authenticated: redirect, if possible
400  if ($_GET["target"] != "")
401  {
402  ilUtil::redirect("goto.php?target=".$_GET["target"]."&client_id=".CLIENT_ID);
403  }
404  }
405  else
406  {
407  // This should never occur unless Shibboleth is not configured properly
408  $this->status = AUTH_WRONG_LOGIN;
409  }
410  }
411 
420  function setAuth($username)
421  {
422  $session = &$this->_importGlobalVariable('session');
423 
424  if (!isset($session[$this->_sessionName]) && !isset($_SESSION)) {
425  session_register($this->_sessionName);
426  }
427 
428  if (!isset($session[$this->_sessionName]) || !is_array($session[$this->_sessionName])) {
429  $session[$this->_sessionName] = array();
430  }
431 
432  if(!isset($session[$this->_sessionName]['data'])){
433  $session[$this->_sessionName]['data'] = array();
434  }
435  $session[$this->_sessionName]['registered'] = true;
436  $session[$this->_sessionName]['username'] = $username;
437  $session[$this->_sessionName]['timestamp'] = time();
438  $session[$this->_sessionName]['idle'] = time();
439  }
440 
451  function logout()
452  {
453  $session = &$this->_importGlobalVariable('session');
454 
455 
456  $this->username = '';
457 
458  $session[$this->_sessionName] = array();
459  if (isset($_SESSION)) {
460  unset($session[$this->_sessionName]);
461  } else {
462  session_unregister($this->_sessionName);
463  }
464  }
465 
472  function getUsername()
473  {
474  $session = &$this->_importGlobalVariable('session');
475  if (!isset($session[$this->_sessionName]['username'])) {
476  return '';
477  }
478  return $session[$this->_sessionName]['username'];
479  }
480 
487  function getStatus()
488  {
489 
490  return $status;
491  }
492 
500  function &_importGlobalVariable($variable)
501  {
502  $var = null;
503 
504  switch (strtolower($variable)) {
505 
506  case 'server' :
507  if (isset($_SERVER)) {
508  $var = &$_SERVER;
509  } else {
510  $var = &$GLOBALS['HTTP_SERVER_VARS'];
511  }
512  break;
513 
514  case 'session' :
515  if (isset($_SESSION)) {
516  $var = &$_SESSION;
517  } else {
518  $var = &$GLOBALS['HTTP_SESSION_VARS'];
519  }
520  break;
521 
522  case 'post' :
523  if (isset($_POST)) {
524  $var = &$_POST;
525  } else {
526  $var = &$GLOBALS['HTTP_POST_VARS'];
527  }
528  break;
529 
530  case 'cookie' :
531  if (isset($_COOKIE)) {
532  $var = &$_COOKIE;
533  } else {
534  $var = &$GLOBALS['HTTP_COOKIE_VARS'];
535  }
536  break;
537 
538  case 'get' :
539  if (isset($_GET)) {
540  $var = &$_GET;
541  } else {
542  $var = &$GLOBALS['HTTP_GET_VARS'];
543  }
544  break;
545 
546  default:
547  break;
548 
549  }
550 
551  return $var;
552  }
553 
561  function generateLogin()
562  {
563  global $ilias, $ilDB;
564 
565  $shibID = $_SERVER[$ilias->getSetting('shib_login')];
566  $lastname = $this->getFirstString($_SERVER[$ilias->getSetting('shib_lastname')]);
567  $firstname = $this->getFirstString($_SERVER[$ilias->getSetting('shib_firstname')]);
568 
569  if (trim($shibID) == "")
570  {
571  return;
572  }
573 
574  //***********************************************//
575  // For backwards compatibility with previous versions
576  // We use the passwd field as mapping attribute for Shibboleth users
577  // because they don't need a password
578  $ilias->db->query("UPDATE usr_data SET auth_mode='shibboleth', passwd=".$ilDB->quote(md5(end(ilUtil::generatePasswords(1)))).", ext_account=".$ilDB->quote($shibID)." WHERE passwd=".$ilDB->quote($shibID));
579  //***********************************************//
580 
581  // Let's see if user already is registered
582  $local_user = ilObjUser::_checkExternalAuthAccount("shibboleth", $shibID);
583  if ($local_user)
584  {
585  return $local_user;
586  }
587 
588  // User doesn't seem to exist yet
589 
590  // Generate new username
591  // This can be overruled by the data conversion API but you have
592  // to do it yourself in that case
593 
594  // Generate the username out of the first character of firstname and the
595  // first word in lastname (adding the second one if the login is too short,
596  // avoiding meaningless last names like 'von' or 'd' and eliminating
597  // non-ASCII-characters, spaces, dashes etc.
598 
599  $ln_arr=preg_split("/[ '-;]/", $lastname);
600  $login=substr($this->toAscii($firstname),0,1) . "." . $this->toAscii($ln_arr[0]);
601  if (strlen($login) < 6) $login .= $this->toAscii($ln_arr[1]);
602  $prefix = strtolower($login);
603 
604  // If the user name didn't contain any ASCII characters, assign the
605  // name 'shibboleth' followed by a number, starting with 1.
606  if (strlen($prefix) == 0) {
607  $prefix = 'shibboleth';
608  $number = 1;
609  }
610  else
611  {
612  // Try if the login name is not already taken
613  if (!ilObjUser::getUserIdByLogin($prefix))
614  {
615  return $prefix;
616  }
617 
618  // If the login name is in use, append a number, starting with 2.
619  $number = 2;
620  }
621 
622  // Append a number, if the username is already taken
623  while (ilObjUser::getUserIdByLogin($prefix.$number))
624  {
625  $number++;
626  }
627 
628  return $prefix.$number;
629  }
630 
638  function getFirstString($string){
639 
640  $list = split( ';', $string);
641  $clean_string = rtrim($list[0]);
642 
643  return $clean_string;
644 
645  }
646 
654  function toAscii($string) {
655  require_once('include/Unicode/UtfNormal.php');
656 
657  // Normalize to NFKD.
658  // This separates letters from combining marks.
659  // See http://unicode.org/reports/tr15
660  $string = UtfNormal::toNFKD($string);
661 
662  // Replace german usages of diaeresis by appending an e
663  $string = preg_replace('/([aouAOU])\\xcc\\x88/','\\1e', $string);
664 
665  // Replace the combined ae character by separated a and e
666  $string = preg_replace('/\\xc3\\x86/','AE', $string);
667  $string = preg_replace('/\\xc3\\xa6/','ae', $string);
668 
669  // Replace the combined thorn character by th
670  $string = preg_replace('/\\xc3\\x9e/','TH', $string);
671  $string = preg_replace('/\\xc3\\xbe/','th', $string);
672 
673  // Replace the letter eth by d
674  $string = preg_replace('/\\xc3\\x90/','D', $string);
675  $string = preg_replace('/\\xc4\\x91/','d', $string);
676  $string = preg_replace('/\\xc4\\x90/','D', $string);
677 
678  // Replace the combined ss character
679  $string = preg_replace('/\\xc3\\x9f/','ss', $string);
680 
681  // Get rid of everything except the characters a to z and the hyphen
682  $string = preg_replace('/[^a-zA-Z\-]/i','', $string);
683 
684  return $string;
685  }
686 
687 } // END class.ilShibAuth
688 ?>