[ Index ] |
PHP Cross Reference of moodle-2.8 |
[Summary view] [Print] [Text view]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Authentication Plugin: Shibboleth Authentication 19 * Authentication using Shibboleth. 20 * 21 * Distributed under GPL (c)Markus Hagman 2004-2006 22 * 23 * @package auth_shibboleth 24 * @author Martin Dougiamas 25 * @author Lukas Haemmerle 26 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License 27 */ 28 29 defined('MOODLE_INTERNAL') || die(); 30 31 require_once($CFG->libdir.'/authlib.php'); 32 33 /** 34 * Shibboleth authentication plugin. 35 */ 36 class auth_plugin_shibboleth extends auth_plugin_base { 37 38 /** 39 * Constructor. 40 */ 41 function auth_plugin_shibboleth() { 42 $this->authtype = 'shibboleth'; 43 $this->config = get_config('auth/shibboleth'); 44 } 45 46 /** 47 * Returns true if the username and password work and false if they are 48 * wrong or don't exist. 49 * 50 * @param string $username The username (with system magic quotes) 51 * @param string $password The password (with system magic quotes) 52 * @return bool Authentication success or failure. 53 */ 54 function user_login($username, $password) { 55 global $SESSION; 56 57 // If we are in the shibboleth directory then we trust the server var 58 if (!empty($_SERVER[$this->config->user_attribute])) { 59 // Associate Shibboleth session with user for SLO preparation 60 $sessionkey = ''; 61 if (isset($_SERVER['Shib-Session-ID'])){ 62 // This is only available for Shibboleth 2.x SPs 63 $sessionkey = $_SERVER['Shib-Session-ID']; 64 } else { 65 // Try to find out using the user's cookie 66 foreach ($_COOKIE as $name => $value){ 67 if (preg_match('/_shibsession_/i', $name)){ 68 $sessionkey = $value; 69 } 70 } 71 } 72 73 // Set shibboleth session ID for logout 74 $SESSION->shibboleth_session_id = $sessionkey; 75 76 return (strtolower($_SERVER[$this->config->user_attribute]) == strtolower($username)); 77 } else { 78 // If we are not, the user has used the manual login and the login name is 79 // unknown, so we return false. 80 return false; 81 } 82 } 83 84 85 86 /** 87 * Returns the user information for 'external' users. In this case the 88 * attributes provided by Shibboleth 89 * 90 * @return array $result Associative array of user data 91 */ 92 function get_userinfo($username) { 93 // reads user information from shibboleth attributes and return it in array() 94 global $CFG; 95 96 // Check whether we have got all the essential attributes 97 if ( empty($_SERVER[$this->config->user_attribute]) ) { 98 print_error( 'shib_not_all_attributes_error', 'auth_shibboleth' , '', "'".$this->config->user_attribute."' ('".$_SERVER[$this->config->user_attribute]."'), '".$this->config->field_map_firstname."' ('".$_SERVER[$this->config->field_map_firstname]."'), '".$this->config->field_map_lastname."' ('".$_SERVER[$this->config->field_map_lastname]."') and '".$this->config->field_map_email."' ('".$_SERVER[$this->config->field_map_email]."')"); 99 } 100 101 $attrmap = $this->get_attributes(); 102 103 $result = array(); 104 $search_attribs = array(); 105 106 foreach ($attrmap as $key=>$value) { 107 // Check if attribute is present 108 if (!isset($_SERVER[$value])){ 109 $result[$key] = ''; 110 continue; 111 } 112 113 // Make usename lowercase 114 if ($key == 'username'){ 115 $result[$key] = strtolower($this->get_first_string($_SERVER[$value])); 116 } else { 117 $result[$key] = $this->get_first_string($_SERVER[$value]); 118 } 119 } 120 121 // Provide an API to modify the information to fit the Moodle internal 122 // data representation 123 if ( 124 $this->config->convert_data 125 && $this->config->convert_data != '' 126 && is_readable($this->config->convert_data) 127 ) { 128 129 // Include a custom file outside the Moodle dir to 130 // modify the variable $moodleattributes 131 include($this->config->convert_data); 132 } 133 134 return $result; 135 } 136 137 /** 138 * Returns array containg attribute mappings between Moodle and Shibboleth. 139 * 140 * @return array 141 */ 142 function get_attributes() { 143 $configarray = (array) $this->config; 144 145 $moodleattributes = array(); 146 foreach ($this->userfields as $field) { 147 if (isset($configarray["field_map_$field"])) { 148 $moodleattributes[$field] = $configarray["field_map_$field"]; 149 } 150 } 151 $moodleattributes['username'] = $configarray["user_attribute"]; 152 153 return $moodleattributes; 154 } 155 156 function prevent_local_passwords() { 157 return true; 158 } 159 160 /** 161 * Returns true if this authentication plugin is 'internal'. 162 * 163 * @return bool 164 */ 165 function is_internal() { 166 return false; 167 } 168 169 /** 170 * Returns true if this authentication plugin can change the user's 171 * password. 172 * 173 * @return bool 174 */ 175 function can_change_password() { 176 return false; 177 } 178 179 /** 180 * Hook for login page 181 * 182 */ 183 function loginpage_hook() { 184 global $SESSION, $CFG; 185 186 // Prevent username from being shown on login page after logout 187 $CFG->nolastloggedin = true; 188 189 return; 190 } 191 192 /** 193 * Hook for logout page 194 * 195 */ 196 function logoutpage_hook() { 197 global $SESSION, $redirect; 198 199 // Only do this if logout handler is defined, and if the user is actually logged in via Shibboleth 200 $logouthandlervalid = isset($this->config->logout_handler) && !empty($this->config->logout_handler); 201 if (isset($SESSION->shibboleth_session_id) && $logouthandlervalid ) { 202 // Check if there is an alternative logout return url defined 203 if (isset($this->config->logout_return_url) && !empty($this->config->logout_return_url)) { 204 // Set temp_redirect to alternative return url 205 $temp_redirect = $this->config->logout_return_url; 206 } else { 207 // Backup old redirect url 208 $temp_redirect = $redirect; 209 } 210 211 // Overwrite redirect in order to send user to Shibboleth logout page and let him return back 212 $redirect = $this->config->logout_handler.'?return='.urlencode($temp_redirect); 213 } 214 } 215 216 217 218 /** 219 * Prints a form for configuring this authentication plugin. 220 * 221 * This function is called from admin/auth.php, and outputs a full page with 222 * a form for configuring this plugin. 223 * 224 * @param array $page An object containing all the data for this page. 225 */ 226 function config_form($config, $err, $user_fields) { 227 include "config.html"; 228 } 229 230 /** 231 * Processes and stores configuration data for this authentication plugin. 232 * 233 * 234 * @param object $config Configuration object 235 */ 236 function process_config($config) { 237 global $CFG; 238 239 // set to defaults if undefined 240 if (!isset($config->auth_instructions) or empty($config->user_attribute)) { 241 $config->auth_instructions = get_string('auth_shib_instructions', 'auth_shibboleth', $CFG->wwwroot.'/auth/shibboleth/index.php'); 242 } 243 if (!isset ($config->user_attribute)) { 244 $config->user_attribute = ''; 245 } 246 if (!isset ($config->convert_data)) { 247 $config->convert_data = ''; 248 } 249 250 if (!isset($config->changepasswordurl)) { 251 $config->changepasswordurl = ''; 252 } 253 254 if (!isset($config->login_name)) { 255 $config->login_name = 'Shibboleth Login'; 256 } 257 258 // Clean idp list 259 if (isset($config->organization_selection) && !empty($config->organization_selection) && isset($config->alt_login) && $config->alt_login == 'on') { 260 $idp_list = get_idp_list($config->organization_selection); 261 if (count($idp_list) < 1){ 262 return false; 263 } 264 $config->organization_selection = ''; 265 foreach ($idp_list as $idp => $value){ 266 $config->organization_selection .= $idp.', '.$value[0].', '.$value[1]."\n"; 267 } 268 } 269 270 271 // save settings 272 set_config('user_attribute', $config->user_attribute, 'auth/shibboleth'); 273 274 if (isset($config->organization_selection) && !empty($config->organization_selection)) { 275 set_config('organization_selection', $config->organization_selection, 'auth/shibboleth'); 276 } 277 set_config('logout_handler', $config->logout_handler, 'auth/shibboleth'); 278 set_config('logout_return_url', $config->logout_return_url, 'auth/shibboleth'); 279 set_config('login_name', $config->login_name, 'auth/shibboleth'); 280 set_config('convert_data', $config->convert_data, 'auth/shibboleth'); 281 set_config('auth_instructions', $config->auth_instructions, 'auth/shibboleth'); 282 set_config('changepasswordurl', $config->changepasswordurl, 'auth/shibboleth'); 283 284 // Overwrite alternative login URL if integrated WAYF is used 285 if (isset($config->alt_login) && $config->alt_login == 'on'){ 286 set_config('alt_login', $config->alt_login, 'auth/shibboleth'); 287 set_config('alternateloginurl', $CFG->wwwroot.'/auth/shibboleth/login.php'); 288 } else { 289 // Check if integrated WAYF was enabled and is now turned off 290 // If it was and only then, reset the Moodle alternate URL 291 if (isset($this->config->alt_login) and $this->config->alt_login == 'on'){ 292 set_config('alt_login', 'off', 'auth/shibboleth'); 293 set_config('alternateloginurl', ''); 294 } 295 $config->alt_login = 'off'; 296 } 297 298 // Check values and return false if something is wrong 299 // Patch Anyware Technologies (14/05/07) 300 if (($config->convert_data != '')&&(!file_exists($config->convert_data) || !is_readable($config->convert_data))){ 301 return false; 302 } 303 304 // Check if there is at least one entry in the IdP list 305 if (isset($config->organization_selection) && empty($config->organization_selection) && isset($config->alt_login) && $config->alt_login == 'on'){ 306 return false; 307 } 308 309 return true; 310 } 311 312 /** 313 * Cleans and returns first of potential many values (multi-valued attributes) 314 * 315 * @param string $string Possibly multi-valued attribute from Shibboleth 316 */ 317 function get_first_string($string) { 318 $list = explode( ';', $string); 319 $clean_string = rtrim($list[0]); 320 321 return $clean_string; 322 } 323 } 324 325 326 /** 327 * Sets the standard SAML domain cookie that is also used to preselect 328 * the right entry on the local wayf 329 * 330 * @param IdP identifiere 331 */ 332 function set_saml_cookie($selectedIDP) { 333 if (isset($_COOKIE['_saml_idp'])) 334 { 335 $IDPArray = generate_cookie_array($_COOKIE['_saml_idp']); 336 } 337 else 338 { 339 $IDPArray = array(); 340 } 341 $IDPArray = appendCookieValue($selectedIDP, $IDPArray); 342 setcookie ('_saml_idp', generate_cookie_value($IDPArray), time() + (100*24*3600)); 343 } 344 345 /** 346 * Prints the option elements for the select element of the drop down list 347 * 348 */ 349 function print_idp_list(){ 350 $config = get_config('auth/shibboleth'); 351 352 $IdPs = get_idp_list($config->organization_selection); 353 if (isset($_COOKIE['_saml_idp'])){ 354 $idp_cookie = generate_cookie_array($_COOKIE['_saml_idp']); 355 do { 356 $selectedIdP = array_pop($idp_cookie); 357 } while (!isset($IdPs[$selectedIdP]) && count($idp_cookie) > 0); 358 359 } else { 360 $selectedIdP = '-'; 361 } 362 363 foreach($IdPs as $IdP => $data){ 364 if ($IdP == $selectedIdP){ 365 echo '<option value="'.$IdP.'" selected="selected">'.$data[0].'</option>'; 366 } else { 367 echo '<option value="'.$IdP.'">'.$data[0].'</option>'; 368 } 369 } 370 } 371 372 373 /** 374 * Generate array of IdPs from Moodle Shibboleth settings 375 * 376 * @param string Text containing tuble/triple of IdP entityId, name and (optionally) session initiator 377 * @return array Identifier of IdPs and their name/session initiator 378 */ 379 380 function get_idp_list($organization_selection) { 381 $idp_list = array(); 382 383 $idp_raw_list = explode("\n", $organization_selection); 384 385 foreach ($idp_raw_list as $idp_line){ 386 $idp_data = explode(',', $idp_line); 387 if (isset($idp_data[2])) 388 { 389 $idp_list[trim($idp_data[0])] = array(trim($idp_data[1]),trim($idp_data[2])); 390 } 391 elseif(isset($idp_data[1])) 392 { 393 $idp_list[trim($idp_data[0])] = array(trim($idp_data[1])); 394 } 395 } 396 397 return $idp_list; 398 } 399 400 /** 401 * Generates an array of IDPs using the cookie value 402 * 403 * @param string Value of SAML domain cookie 404 * @return array Identifiers of IdPs 405 */ 406 function generate_cookie_array($value) { 407 408 // Decodes and splits cookie value 409 $CookieArray = explode(' ', $value); 410 $CookieArray = array_map('base64_decode', $CookieArray); 411 412 return $CookieArray; 413 } 414 415 /** 416 * Generate the value that is stored in the cookie using the list of IDPs 417 * 418 * @param array IdP identifiers 419 * @return string SAML domain cookie value 420 */ 421 function generate_cookie_value($CookieArray) { 422 423 // Merges cookie content and encodes it 424 $CookieArray = array_map('base64_encode', $CookieArray); 425 $value = implode(' ', $CookieArray); 426 return $value; 427 } 428 429 /** 430 * Append a value to the array of IDPs 431 * 432 * @param string IdP identifier 433 * @param array IdP identifiers 434 * @return array IdP identifiers with appended IdP 435 */ 436 function appendCookieValue($value, $CookieArray) { 437 438 array_push($CookieArray, $value); 439 $CookieArray = array_reverse($CookieArray); 440 $CookieArray = array_unique($CookieArray); 441 $CookieArray = array_reverse($CookieArray); 442 443 return $CookieArray; 444 } 445 446 447
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:29:05 2014 | Cross-referenced by PHPXref 0.7.1 |