- 07. 2007: Fixed a but that caused problems with uppercase usernames
- 10. 2007: Removed the requirement for email address, surname and given name
attributes on request of Markus Hagman
+- 11. 2007: Integrated WAYF Service in Moodle
Moodle Configuration with Dual login
-------------------------------------------------------------------------------
-1. Protect the directory moodle/auth/shibboleth/ with Shibboleth.
+1. Protect the directory moodle/auth/shibboleth/index.php with Shibboleth.
The page index.php in that directory actually logs in a Shibboleth user.
For Apache you have to define a rule like the following in the Apache config:
--
-<Location ~ "/auth/shibboleth">
+<Location ~ "/auth/shibboleth/index.php">
AuthType shibboleth
ShibRequireSession On
require valid-user
Options' and click on the the 'Shibboleth' settings.
3. Fill in the fields of the form. The fields 'Username', 'First name',
- 'Surname', etc should contain the name of the environment variables of the
+ 'Surname', etc. should contain the name of the environment variables of the
Shibboleth attributes that you want to map onto the corresponding Moodle
variable (e.g. 'HTTP_SHIB_PERSON_SURNAME' for the person's last name, refer
the Shibboleth documentation or the documentation of your Shibboleth
#############################################################################
Shibboleth Attributes needed by Moodle:
- For Moodle to work properly Shibboleth should at least provide the attributes
- that are used as username, firstname, lastname and email in Moodle.
- The attribute used for the username has to be unique for all Shibboleth user.
- All attributes must obey a certain length, otherwise Moodle cuts off the
- ends. Consult the Moodle documentation for further information on the maximum
- lengths for each field in the user profile.
+ For Moodle to work properly Shibboleth should at least provide the attribute
+ that is used as usernam in Moodle. It has to be unique for all Shibboleth
+ users.
+ All attributes used for moodle must obey a certain length, otherwise Moodle
+ cuts off the ends. Consult the Moodle documentation for further information
+ on the maximum lengths for each field in the user profile.
#############################################################################
4. Save the changes for the 'Shibboleth settings'.
-5.a If you want Shibboleth as your only authentication method, set the
- 'Alternate Login URL' in the 'Common settings' in
- 'Administrations >> Users >> Authentication Options' to the the URL of the
- file 'moodle/auth/shibboleth/index.php'. This will enforce Shibboleth login.
+5.a If you want Shibboleth as your only authentication method with an external
+ Where Are You From (WAYF) Service , set the 'Alternate Login URL' in the
+ 'Common settings' in 'Administrations >> Users >> Authentication Options'
+ to the the URL of the file 'moodle/auth/shibboleth/index.php'.
+ This will enforce Shibboleth login.
+
+5.b If you want to use the Moodle internal WAYF service, you have to activate it
+ in the Moodle Shibboleth authentication settings by checking the
+ 'Moodle WAYF Service' checkbox and providing a list of entity IDs in the
+ 'Identity Providers' textarea together with a name and an optional
+ SessionInitiator URL, which usually is an absolute or relative URL pointing
+ to the same host. If no SessionInitiator URL is given, the default one
+ '/Shibboleth.sso' will be used.
+ Also see https://spaces.internet2.edu/display/SHIB/SessionInitiator
+
+ Important Note: If you upgraded from a previous version of Moodle and now
+ want to use the integrated WAYF, you have to make sure that
+ in step 1 only the index.php script in
+ moodle/auth/shibboleth/ is protected but *not* the other
+ scripts and especially not the login.php script.
6.b If you want to use another authentication method together with Shibboleth,
in parallel, change the 'Instructions' in the 'Common settings' of the
Shibboleth dual login with custom login page
--------------------------------------------------------------------------------
-Of course you can create a dual login page that better fits your needs. For this
-to work, you have to set up the two authentication methods (e.g. 'Manual' and
-'Shibboleth') and specify an alternate login link to your own dual login page.
-On that page you basically need a link to the Shibboleth-protected page
-('/auth/shibboleth/index.php') for the Shibboleth login and a
+You can create a dual login page that better fits your needs. For this
+to work, you have to set up the two authentication methods (e.g. 'Manual
+Accounts' and 'Shibboleth') and specify an alternate login link to your own dual
+login page. On that page you basically need a link to the Shibboleth-protected
+page ('/auth/shibboleth/index.php') for the Shibboleth login and a
form that sends 'username' and 'password' to moodle/login/index.php.
Consult the Moodle documentation for further instructions and requirements.
* 2006-10-27 Upstream 1.7 changes merged in, added above credits from lib.php :-)
* 2007-03-09 Fixed authentication but may need some other changes
* 2007-10-03 Removed requirement for email address, surname and given name on request of Markus Hagman
+ * 2008-01-21 Added WAYF functionality
+
*/
if (!defined('MOODLE_INTERNAL')) {
return $result;
}
- /*
+ /**
* Returns array containg attribute mappings between Moodle and Shibboleth.
+ *
+ * @return array
*/
function get_attributes() {
$configarray = (array) $this->config;
return false;
}
+ /**
+ * Hook for login page
+ *
+ */
function loginpage_hook() {
global $SESSION, $CFG;
if (!isset ($config->convert_data)) {
$config->convert_data = '';
}
+
if (!isset($config->changepasswordurl)) {
$config->changepasswordurl = '';
}
+
+ if (!isset($config->login_name)) {
+ $config->login_name = 'Shibboleth Login';
+ }
+
+ // Clean idp list
+ if (isset($config->organization_selection) && !empty($config->organization_selection) && isset($config->alt_login) && $config->alt_login == 'on') {
+ $idp_list = get_idp_list($config->organization_selection);
+ if (count($idp_list) < 1){
+ return false;
+ }
+ $config->organization_selection = '';
+ foreach ($idp_list as $idp => $value){
+ $config->organization_selection .= $idp.', '.$value[0].', '.$value[1]."\n";
+ }
+ }
+
// save settings
set_config('user_attribute', $config->user_attribute, 'auth/shibboleth');
+
+ if (isset($config->organization_selection) && !empty($config->organization_selection)) {
+ set_config('organization_selection', $config->organization_selection, 'auth/shibboleth');
+ }
+ set_config('login_name', $config->login_name, 'auth/shibboleth');
set_config('convert_data', $config->convert_data, 'auth/shibboleth');
set_config('auth_instructions', $config->auth_instructions, 'auth/shibboleth');
set_config('changepasswordurl', $config->changepasswordurl, 'auth/shibboleth');
-
+
+ if (isset($config->alt_login) && $config->alt_login == 'on'){
+ set_config('alt_login', $config->alt_login, 'auth/shibboleth');
+ set_config('alternateloginurl', $CFG->wwwroot.'/auth/shibboleth/login.php');
+ } else {
+ set_config('alt_login', 'off', 'auth/shibboleth');
+ set_config('alternateloginurl', '');
+ $config->alt_login = 'off';
+ }
+
// Check values and return false if something is wrong
// Patch Anyware Technologies (14/05/07)
if (($config->convert_data != '')&&(!file_exists($config->convert_data) || !is_readable($config->convert_data))){
return false;
}
+
+ // Check if there is at least one entry in the IdP list
+ if (isset($config->organization_selection) && empty($config->organization_selection) && isset($config->alt_login) && $config->alt_login == 'on'){
+ return false;
+ }
return true;
}
}
}
+
+ /**
+ * Sets the standard SAML domain cookie that is also used to preselect
+ * the right entry on the local wayf
+ *
+ * @param IdP identifiere
+ */
+ function set_saml_cookie($selectedIDP) {
+ if (isset($_COOKIE['_saml_idp']))
+ {
+ $IDPArray = generate_cookie_array($_COOKIE['_saml_idp']);
+ }
+ else
+ {
+ $IDPArray = array();
+ }
+ $IDPArray = appendCookieValue($selectedIDP, $IDPArray);
+ setcookie ('_saml_idp', generate_cookie_value($IDPArray), time() + (100*24*3600));
+ }
+
+ /**
+ * Prints the option elements for the select element of the drop down list
+ *
+ */
+ function print_idp_list(){
+ $config = get_config('auth/shibboleth');
+
+ $IdPs = get_idp_list($config->organization_selection);
+ if (isset($_COOKIE['_saml_idp'])){
+ $idp_cookie = generate_cookie_array($_COOKIE['_saml_idp']);
+ do {
+ $selectedIdP = array_pop($idp_cookie);
+ } while (!isset($IdPs[$selectedIdP]) && count($idp_cookie) > 0);
+
+ } else {
+ $selectedIdP = '-';
+ }
+
+ foreach($IdPs as $IdP => $data){
+ if ($IdP == $selectedIdP){
+ echo '<option value="'.$IdP.'" selected="selected">'.$data[0].'</option>';
+ } else {
+ echo '<option value="'.$IdP.'">'.$data[0].'</option>';
+ }
+ }
+ }
+
+
+ /**
+ * Generate array of IdPs from Moodle Shibboleth settings
+ *
+ * @param string Text containing tuble/triple of IdP entityId, name and (optionally) session initiator
+ * @return array Identifier of IdPs and their name/session initiator
+ */
+
+ function get_idp_list($organization_selection) {
+ $idp_list = array();
+
+ $idp_raw_list = split("\n", $organization_selection);
+
+ foreach ($idp_raw_list as $idp_line){
+ $idp_data = split(',', $idp_line);
+ if (isset($idp_data[2]))
+ {
+ $idp_list[trim($idp_data[0])] = array(trim($idp_data[1]),trim($idp_data[2]));
+ }
+ elseif(isset($idp_data[1]))
+ {
+ $idp_list[trim($idp_data[0])] = array(trim($idp_data[1]));
+ }
+ }
+
+ return $idp_list;
+ }
+
+ /**
+ * Generates an array of IDPs using the cookie value
+ *
+ * @param string Value of SAML domain cookie
+ * @return array Identifiers of IdPs
+ */
+ function generate_cookie_array($value) {
+
+ // Decodes and splits cookie value
+ $CookieArray = split(' ', $value);
+ $CookieArray = array_map('base64_decode', $CookieArray);
+
+ return $CookieArray;
+ }
+
+ /**
+ * Generate the value that is stored in the cookie using the list of IDPs
+ *
+ * @param array IdP identifiers
+ * @return string SAML domain cookie value
+ */
+ function generate_cookie_value($CookieArray) {
+
+ // Merges cookie content and encodes it
+ $CookieArray = array_map('base64_encode', $CookieArray);
+ $value = implode(' ', $CookieArray);
+ return $value;
+ }
+
+ /**
+ * Append a value to the array of IDPs
+ *
+ * @param string IdP identifier
+ * @param array IdP identifiers
+ * @return array IdP identifiers with appended IdP
+ */
+ function appendCookieValue($value, $CookieArray) {
+
+ array_push($CookieArray, $value);
+ $CookieArray = array_reverse($CookieArray);
+ $CookieArray = array_unique($CookieArray);
+ $CookieArray = array_reverse($CookieArray);
+
+ return $CookieArray;
+ }
+
+
?>
<td><?php print_string("auth_shib_username_description", "auth") ?></td>
</tr>
-<!--
-This is kind of obsolete because the login instructions are now centralized
-On the other hand it would be great for Shibboleth to have seperate login
-instructions
--->
-<!--
<tr valign="top">
- <td align="right"><?php print_string("instructions", "auth") ?>:</td>
- <td>
- <textarea name="auth_instructions" cols="30" rows="10" wrap="virtual"><?php p($config->auth_instructions) ?></textarea>
- </td>
+ <td align="right"><?php print_string("auth_shib_convert_data", "auth") ?>:</td>
<td>
+ <input name="convert_data" type="text" size="30" value="<?php echo $config->convert_data?>" />
<?php
-
- print_string("auth_shib_instructions_help", "auth", htmlspecialchars($CFG->wwwroot.'/auth/shibboleth/index.php'));
- helpbutton("text", get_string("helptext"));
+
+ if ($config->convert_data and $config->convert_data != '' and !is_readable($config->convert_data)) {
+ echo '<br/><font color="red">';
+ print_string("auth_shib_convert_data_warning", "auth");
+ echo '</font>';
+ }
?>
</td>
+ <td><?php print_string("auth_shib_convert_data_description", "auth"); echo $config->alt_login ?></td>
</tr>
--->
<tr valign="top">
- <td align="right"><?php print_string("auth_shib_convert_data", "auth") ?>:</td>
+ <td align="right">Moodle WAYF Service:</td>
<td>
- <input name="convert_data" type="text" size="30" value="<?php echo $config->convert_data?>" />
- <?php
+ <input name="alt_login" type="checkbox" <?php
+ if ( isset($config->alt_login) and $config->alt_login == 'on' ){
+ echo 'checked="checked"';
+ }
+ ?> />
+ </td>
+ <td>If you check this, Moodle will use its own WAYF service instead of the one configured for Shibboleth. Moodle will display a drop-down list on this alternative login page where the user has to select his Identity Provider.</td>
+</tr>
- if ($config->convert_data and $config->convert_data != '' and !is_readable($config->convert_data)) {
+<tr valign="top">
+ <td align="right">Identity Providers:</td>
+ <td>
+ <textarea name="organization_selection" rows="10" cols="30" style="overflow: auto;" wrap="off"
+><?php
+ if (!isset($config->organization_selection)){
+ echo 'urn:mace:organization1:providerID, Example Organization 1
+https://another.idp-id.com/shibboleth, Other Example Organization
+urn:mace:organization2:providerID, Example Organization 2, /Shibboleth.sso/WAYF/SWITCHaai';
+ } else {
+ echo $config->organization_selection;
+ }
+ ?>
+</textarea>
+ <?
+ if (isset($config->organization_selection) && empty($config->organization_selection) && isset($config->alt_login) && $config->alt_login == 'on') {
echo '<br/><font color="red">';
- print_string("auth_shib_convert_data_warning", "auth");
+ print_string("auth_shib_no_organizations_warning", "auth");
echo '</font>';
}
-
- ?>
+ ?>
</td>
- <td><?php print_string("auth_shib_convert_data_description", "auth") ?></td>
+ <td>Provide a list of Identity Provider entityIDs to let the user choose from on the login page.
+On each line there must be a comma-separated tuple for entityID of the IdP (see the Shibboleth metadata file) and Name of IdP as it shall be displayed in the drow-down list.
+As an optional third parameter you can add the location of a Shibboleth session initiator that shall be used in case your Moodle installation is part of a multi federation setup.</td>
</tr>
+<tr valign="top">
+ <td align="right">Authentication Method Name:</td>
+ <td>
+ <input name="login_name" type="text" size="30" value="<?php
+ if ( isset($config->login_name) and !empty($config->login_name)){
+ echo $config->login_name;
+ } else {
+ echo 'Shibboleth Login';
+ }
+ ?>" />
+ </td>
+ <td>Provide a name for the Shibboleth authentication method that is familiar to your users. This could be the name of your Shibboleth federation, e.g. "SWITCHaai Login" or "InCommon Login" and so on.</td>
+</tr>
<tr valign="top">
<td align="right"><?php print_string('auth_shib_changepasswordurl', 'auth') ?>: </td>
<td><?php print_string('changepasswordhelp', 'auth') ?></td>
</tr>
+
+
<?php
print_auth_lock_options('shibboleth', $user_fields, '<!-- empty help -->', true, false);