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