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