ILIAS  Release_4_4_x_branch Revision 61816
 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 require_once('Auth/Auth.php');
25 require_once('./Services/AuthShibboleth/classes/class.ilShibbolethRoleAssignmentRules.php');
26 require_once('include/Unicode/UtfNormal.php');
27 require_once('./Services/AuthShibboleth/classes/class.ilShibbolethPluginWrapper.php');
28 
29 
40 class ShibAuth extends Auth {
41 
47  var $username;
53  var $_sessionName = '_authsession';
59  var $status = '';
68  var $expire = 0;
79  var $idle = 0;
86  var $idled = false;
87 
88 
93  public function __construct($authParams, $updateUserData = false) {
94  if ($authParams['sessionName'] != '') {
95  parent::Auth('', array( 'sessionName' => $authParams['sessionName'] ));
96  } else {
97  parent::Auth('');
98  }
99  $this->updateUserData = $updateUserData;
100  if (! empty($authParams['sessionName'])) {
101  $this->setSessionName($authParams['sessionName']);
102  unset($authParams['sessionName']);
103  }
104  }
105 
106 
110  public function supportsRedirects() {
111  return true;
112  }
113 
114 
128  public function setIdle($time, $add = false) {
129  if ($add) {
130  $this->idle += $time;
131  } else {
132  $this->idle = $time;
133  }
134  }
135 
136 
147  public function setExpire($time, $add = false) {
148  if ($add) {
149  $this->expire += $time;
150  } else {
151  $this->expire = $time;
152  }
153  }
154 
155 
162  public function login() {
163  global $ilias, $ilSetting;
164  if (! empty($_SERVER[$ilias->getSetting('shib_login')])) {
165  // Store user's Shibboleth sessionID for logout
166  $this->session['shibboleth_session_id'] = $_SERVER['Shib-Session-ID'];
167  // Get loginname of user, new login name is generated if user is new
168  $username = $this->generateLogin();
169  // Authorize this user
170  $userObj = new ilObjUser();
171  $this->setAuth($username, $userObj);
172  // Check wether this account exists already, if not create it
174 
175  $newUser['firstname'] = self::getFirstString($_SERVER[$ilias->getSetting('shib_firstname')]);
176  $newUser['lastname'] = self::getFirstString($_SERVER[$ilias->getSetting('shib_lastname')]);
177  $newUser['login'] = $username;
178  // Password must be random to prevent users from manually log in using the login data from Shibboleth users
179  $newUser['passwd'] = md5(end(ilUtil::generatePasswords(1)));
180  $newUser['passwd_type'] = IL_PASSWD_MD5;
181  if ($ilias->getSetting('shib_update_gender') AND ($_SERVER[$ilias->getSetting('shib_gender')] == 'm' OR
182  $_SERVER[$ilias->getSetting('shib_gender')] == 'f')
183  ) {
184  $newUser['gender'] = $_SERVER[$ilias->getSetting('shib_gender')];
185  }
186  // Save mapping between ILIAS user and Shibboleth uniqueID
187  $newUser['ext_account'] = $_SERVER[$ilias->getSetting('shib_login')];
188  // other data
189  $newUser['title'] = $_SERVER[$ilias->getSetting('shib_title')];
190  $newUser['institution'] = $_SERVER[$ilias->getSetting('shib_institution')];
191  $newUser['department'] = $_SERVER[$ilias->getSetting('shib_department')];
192  $newUser['street'] = $_SERVER[$ilias->getSetting('shib_street')];
193  $newUser['city'] = $_SERVER[$ilias->getSetting('shib_city')];
194  $newUser['zipcode'] = $_SERVER[$ilias->getSetting('shib_zipcode')];
195  $newUser['country'] = $_SERVER[$ilias->getSetting('shib_country')];
196  $newUser['phone_office'] = self::getFirstString($_SERVER[$ilias->getSetting('shib_phone_office')]);
197  $newUser['phone_home'] = self::getFirstString($_SERVER[$ilias->getSetting('shib_phone_home')]);
198  $newUser['phone_mobile'] = self::getFirstString($_SERVER[$ilias->getSetting('shib_phone_mobile')]);
199  $newUser['fax'] = self::getFirstString($_SERVER[$ilias->getSetting('shib_fax')]);
200  $newUser['matriculation'] = $_SERVER[$ilias->getSetting('shib_matriculation')];
201  $newUser['email'] = self::getFirstString($_SERVER[$ilias->getSetting('shib_email')]);
202  $newUser['hobby'] = $_SERVER[$ilias->getSetting('shib_hobby')];
203  $newUser['auth_mode'] = 'shibboleth';
204  // system data
205  $userObj->assignData($newUser);
206  $userObj->setTitle($userObj->getFullname());
207  $userObj->setDescription($userObj->getEmail());
208  $userObj->setLanguage(self::getFirstString($_SERVER[$ilias->getSetting('shib_language')]));
209  // Time limit
210  $userObj->setTimeLimitOwner(7);
211  $userObj->setTimeLimitUnlimited(1);
212  $userObj->setTimeLimitFrom(time());
213  $userObj->setTimeLimitUntil(time());
214  // Modify user data before creating the user
215  // Include custom code that can be used to further modify
216  // certain Shibboleth user attributes
217  if ($ilias->getSetting('shib_data_conv') AND
218  $ilias->getSetting('shib_data_conv') != '' AND is_readable($ilias->getSetting('shib_data_conv'))
219  ) {
220  include($ilias->getSetting('shib_data_conv'));
221  }
222  // Create use in DB
223  $userObj = ilShibbolethPluginWrapper::getInstance()->beforeCreateUser($userObj);
224  $userObj->create();
225  $userObj->setActive(1);
226  $userObj->updateOwner();
227  //insert user data in table user_data
228  $userObj->saveAsNew();
229  // store acceptance of user agreement
230  //$userObj->writeAccepted();
231  // Default prefs
232  $userObj->setPref('hits_per_page', $ilSetting->get('hits_per_page', 30));
233  $userObj->setPref('show_users_online', $ilSetting->get('show_users_online', 'y'));
234  // setup user preferences
235  $userObj->writePrefs();
236  $userObj = ilShibbolethPluginWrapper::getInstance()->afterCreateUser($userObj);
237  //set role entries
238  #$rbacadmin->assignUser($ilias->getSetting('shib_user_default_role'), $userObj->getId(),true);
239  // New role assignment
240  ilShibbolethRoleAssignmentRules::doAssignments($userObj->getId(), $_SERVER);
241  // Authorize this user
242  $this->setAuth($userObj->getLogin(), $userObj);
243  } else {
244  // Update user account
245  $uid = $userObj->checkUserId();
246  $userObj->setId($uid);
247  $userObj->read($uid);
248  if ($ilias->getSetting('shib_update_gender') AND ($_SERVER[$ilias->getSetting('shib_gender')] == 'm' OR
249  $_SERVER[$ilias->getSetting('shib_gender')] == 'f')
250  ) {
251  $userObj->setGender($_SERVER[$ilias->getSetting('shib_gender')]);
252  }
253  if ($ilias->getSetting('shib_update_title')) {
254  $userObj->setTitle($_SERVER[$ilias->getSetting('shib_title')]);
255  }
256  $userObj->setFirstname(self::getFirstString($_SERVER[$ilias->getSetting('shib_firstname')]));
257  $userObj->setLastname(self::getFirstString($_SERVER[$ilias->getSetting('shib_lastname')]));
258  $userObj->setFullname();
259  $userObj->setTitle($userObj->getFullname());
260  $userObj->setDescription($userObj->getEmail());
261  if ($ilias->getSetting('shib_update_institution')) {
262  $userObj->setInstitution($_SERVER[$ilias->getSetting('shib_institution')]);
263  }
264  if ($ilias->getSetting('shib_update_department')) {
265  $userObj->setDepartment($_SERVER[$ilias->getSetting('shib_department')]);
266  }
267  if ($ilias->getSetting('shib_update_street')) {
268  $userObj->setStreet($_SERVER[$ilias->getSetting('shib_street')]);
269  }
270  if ($ilias->getSetting('shib_update_city')) {
271  $userObj->setCity($_SERVER[$ilias->getSetting('shib_city')]);
272  }
273  if ($ilias->getSetting('shib_update_zipcode')) {
274  $userObj->setZipcode($_SERVER[$ilias->getSetting('shib_zipcode')]);
275  }
276  if ($ilias->getSetting('shib_update_country')) {
277  $userObj->setCountry($_SERVER[$ilias->getSetting('shib_country')]);
278  }
279  if ($ilias->getSetting('shib_update_phone_office')) {
280  $userObj->setPhoneOffice(self::getFirstString($_SERVER[$ilias->getSetting('shib_phone_office')]));
281  }
282  if ($ilias->getSetting('shib_update_phone_home')) {
283  $userObj->setPhoneHome(self::getFirstString($_SERVER[$ilias->getSetting('shib_phone_home')]));
284  }
285  if ($ilias->getSetting('shib_update_phone_mobile')) {
286  $userObj->setPhoneMobile(self::getFirstString($_SERVER[$ilias->getSetting('shib_phone_mobile')]));
287  }
288  if ($ilias->getSetting('shib_update_fax')) {
289  $userObj->setFax($_SERVER[$ilias->getSetting('shib_fax')]);
290  }
291  if ($ilias->getSetting('shib_update_matriculation')) {
292  $userObj->setMatriculation($_SERVER[$ilias->getSetting('shib_matriculation')]);
293  }
294  if ($ilias->getSetting('shib_update_email')) {
295  $userObj->setEmail(self::getFirstString($_SERVER[$ilias->getSetting('shib_email')]));
296  }
297  if ($ilias->getSetting('shib_update_hobby')) {
298  $userObj->setHobby($_SERVER[$ilias->getSetting('shib_hobby')]);
299  }
300  if ($ilias->getSetting('shib_update_language')) {
301  $userObj->setLanguage($_SERVER[$ilias->getSetting('shib_language')]);
302  }
303  // Include custom code that can be used to further modify
304  // certain Shibboleth user attributes
305  if ($ilias->getSetting('shib_data_conv') AND
306  $ilias->getSetting('shib_data_conv') != '' AND is_readable($ilias->getSetting('shib_data_conv'))
307  ) {
308  include($ilias->getSetting('shib_data_conv'));
309  }
310  $userObj = ilShibbolethPluginWrapper::getInstance()->beforeUpdateUser($userObj);
311  $userObj->update();
312  $userObj = ilShibbolethPluginWrapper::getInstance()->afterUpdateUser($userObj);
313  // Update role assignments
314  ilShibbolethRoleAssignmentRules::updateAssignments($userObj->getId(), $_SERVER);
315  }
316  ilObjUser::_updateLastLogin($userObj->getId());
317  // we are authenticated: redirect, if possible
318  if ($_GET['target'] != '') {
319  ilUtil::redirect('goto.php?target=' . $_GET['target'] . '&client_id=' . CLIENT_ID);
320  }
321  } else {
322  // This should never occur unless Shibboleth is not configured properly
323  $this->status = AUTH_WRONG_LOGIN;
324  }
325  }
326 
327 
332  public function setAuth($username, ilObjUser $userObj = NULL) {
333  if ($userObj) {
334  ilShibbolethPluginWrapper::getInstance()->beforeLogin($userObj);
335  }
337  if ($userObj) {
338  ilShibbolethPluginWrapper::getInstance()->afterLogin($userObj);
339  }
340  }
341 
342 
353  public function logout() {
354  global $ilUser;
355  ilShibbolethPluginWrapper::getInstance()->beforeLogout($ilUser);
356  parent::logout();
357  ilShibbolethPluginWrapper::getInstance()->afterLogout($ilUser);
358  }
359 
360 
368  public function generateLogin() {
369  global $ilias, $ilDB;
370  $shibID = $_SERVER[$ilias->getSetting('shib_login')];
371  $lastname = self::getFirstString($_SERVER[$ilias->getSetting('shib_lastname')]);
372  $firstname = self::getFirstString($_SERVER[$ilias->getSetting('shib_firstname')]);
373  if (trim($shibID) == '') {
374  return;
375  }
376  //***********************************************//
377  // For backwards compatibility with previous versions
378  // We use the passwd field as mapping attribute for Shibboleth users
379  // because they don't need a password
380  $ilias->db->query("UPDATE usr_data SET auth_mode='shibboleth', passwd="
381  . $ilDB->quote(md5(end(ilUtil::generatePasswords(1)))) . ', ext_account=' . $ilDB->quote($shibID)
382  . ' WHERE passwd=' . $ilDB->quote($shibID));
383  //***********************************************//
384  // Let's see if user already is registered
385  $local_user = ilObjUser::_checkExternalAuthAccount('shibboleth', $shibID);
386  if ($local_user) {
387  return $local_user;
388  }
389  // Let's see if user already is registered but authenticates by ldap
390  $local_user = ilObjUser::_checkExternalAuthAccount('ldap', $shibID);
391  if ($local_user) {
392  return $local_user;
393  }
394  // User doesn't seem to exist yet
395  // Generate new username
396  // This can be overruled by the data conversion API but you have
397  // to do it yourself in that case
398  // Generate the username out of the first character of firstname and the
399  // first word in lastname (adding the second one if the login is too short,
400  // avoiding meaningless last names like 'von' or 'd' and eliminating
401  // non-ASCII-characters, spaces, dashes etc.
402  $ln_arr = preg_split("/[ ' -;]/", $lastname);
403  $login = substr($this->toAscii($firstname), 0, 1) . '.' . $this->toAscii($ln_arr[0]);
404  if (strlen($login) < 6) {
405  $login .= $this->toAscii($ln_arr[1]);
406  }
407  $prefix = strtolower($login);
408  // If the user name didn't contain any ASCII characters, assign the
409  // name 'shibboleth' followed by a number, starting with 1.
410  if (strlen($prefix) == 0) {
411  $prefix = 'shibboleth';
412  $number = 1;
413  } else {
414  // Try if the login name is not already taken
415  if (! ilObjUser::getUserIdByLogin($prefix)) {
416  return $prefix;
417  }
418  // If the login name is in use, append a number, starting with 2.
419  $number = 2;
420  }
421  // Append a number, if the username is already taken
422  while (ilObjUser::getUserIdByLogin($prefix . $number)) {
423  $number ++;
424  }
425 
426  return $prefix . $number;
427  }
428 
429 
441  private static function getFirstString($string) {
442  $list = explode(';', $string);
443  $clean_string = rtrim($list[0]);
444 
445  return $clean_string;
446  }
447 
448 
462  static public function toAscii($string) {
463  // Normalize to NFKD.
464  // This separates letters from combining marks.
465  // See http://unicode.org/reports/tr15
466  $string = UtfNormal::toNFKD($string);
467  // Replace german usages of diaeresis by appending an e
468  $string = preg_replace('/([aouAOU])\\xcc\\x88/', '\\1e', $string);
469  // Replace the combined ae character by separated a and e
470  $string = preg_replace('/\\xc3\\x86/', 'AE', $string);
471  $string = preg_replace('/\\xc3\\xa6/', 'ae', $string);
472  // Replace the combined thorn character by th
473  $string = preg_replace('/\\xc3\\x9e/', 'TH', $string);
474  $string = preg_replace('/\\xc3\\xbe/', 'th', $string);
475  // Replace the letter eth by d
476  $string = preg_replace('/\\xc3\\x90/', 'D', $string);
477  $string = preg_replace('/\\xc4\\x91/', 'd', $string);
478  $string = preg_replace('/\\xc4\\x90/', 'D', $string);
479  // Replace the combined ss character
480  $string = preg_replace('/\\xc3\\x9f/', 'ss', $string);
481  // Get rid of everything except the characters a to z and the hyphen
482  $string = preg_replace('/[^a-zA-Z\-]/i', '', $string);
483 
484  return $string;
485  }
486 } // END class.ilShibAuth
487 ?>