first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
+334
View File
@@ -0,0 +1,334 @@
Shibboleth Authentication for Moodle
-------------------------------------------------------------------------------
Requirements:
- Shibboleth Service Provider 1.3 or newer. Recommended is 2.1 or newer.
See documentation for your Shibboleth federation on how to set up Shibboleth.
Changes:
- 11. 2004: Created by Markus Hagman
- 05. 2005: Modifications to login process by Martin Dougiamas
- 05. 2005: Various extensions and fixes by Lukas Haemmerle
- 06. 2005: Adaptions to new field locks and plugin config structures by Martin
Langhoff and Lukas Haemmerle
- 10. 2005: Added better error messages and moved text to language directories
- 02. 2006: Simplified authentication so that authorization works properly
Added instructions for IIS
- 11. 2006: User capabilities are now loaded properly as of Moodle 1.7+
- 03. 2007: Adapted authentication method to Moodle 1.8
- 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
- 12. 2008: Shibboleth 2.x and Single Logout support added
- 1. 2008: Added logout hook and moved Shibboleth config strings to utf8 auth
language files.
- 3. 2009: Added various improvements and bug fixes reported by Ina Mller from
university Tuebingen and Peter Ellis of University of Washington
- 4. 2009: Added another requirement for logout regarding the call back script
- 6. 2009: Changed handler URL when integrated Discovery Service is used
- 10. 2009: Fixed HTML entity preservation in Shibboleth settings
Moodle Configuration with Dual login
-------------------------------------------------------------------------------
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:
--
<Directory /path/to/moodle/auth/shibboleth/index.php>
AuthType shibboleth
ShibRequireSession On
require valid-user
</Directory>
--
To restrict access to Moodle, replace the access rule 'require valid-user'
with something that fits your needs, e.g. 'require affiliation student'.
For IIS you have protect the auth/shibboleth directory directly in the
RequestMap of the Shibboleth configuration file (shibboleth.xml or
shibboleth2.xml).
--
<Path name="moodle" requireSession="false" >
<Path name="auth/shibboleth/index.php" requireSession="true" >
<AccessControl>
...
</AccessControl>
</Path>
</Path>
--
Also see:
https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPRequestMapper and
https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPAccessControl
2. As Moodle admin, go to the 'Administrations >> Users >> Authentication' 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
Shibboleth attributes that you want to map onto the corresponding Moodle
variable (e.g. 'Shib-Person-surname' for the person's last name, refer
the Shibboleth documentation or the documentation of your Shibboleth
federation for information on which attributes are available).
Especially the 'Username' field is of great importance because
this attribute is used for the Moodle authentication of Shibboleth users.
#############################################################################
Shibboleth Attributes needed by Moodle:
For Moodle to work properly Shibboleth should at least provide the attribute
that is used as username in Moodle. It has to be unique for all Shibboleth
Be aware that Moodle converts the username to lowercase. So, the overall
behaviour of the username will be case-insensitive.
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.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.
4.b If you want to use the Moodle integrated 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' (only works for Shibboleth 1.3.x) will be used. For
Shibboleth 2.x you have to add '/Shibboleth.sso/DS' as a SessionInitiator.
Also see https://wiki.shibboleth.net/confluence/display/SHIB/SessionInitiator
and https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPSessionInitiator
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.
If you were using the integrated WAYF alread with Shibboleth 1.3, it could
be that the integrated WAYF is not working anymore after you updated Moodle.
The reason is that the implicitly set default SessionInitiator changed in
Moodle as well as in Shibboleth. For Shibboleth 1.3 one therefore has to
add /Shibboleth.sso as third parameter whereas this is /Shibboleth.sso/DS
for Shibboleth 2.x.
5. Save the changes for the 'Shibboleth settings'.
Important Note: If you went for 4.b (integrated WAYF service), saving the
settings will overwrite the Moodle Alternate Login URL
using the Moodle web root URL.
6. If you want to use Shibboleth in addition to another authentication method
not using the integrated WAYF service from 4.b, change the 'Instructions' in
'Administrations >> Users >> Manage authentication' to contain a link to the
moodle/auth/shibboleth/index.php file which is protected by
Shibboleth (see step 1.) and causes the Shibboleth login procedure to start.
You can also use HTML code in that field, e.g. to include an image as a
Shibboleth login button.
Note: As of now you cannot use dual login together with the integrated
WAYF service provided by Moodle (4.b).
7. Save the authentication changes.
How the Shibboleth authentication works
--------------------------------------------------------------------------------
To get Shibboleth authenticated in Moodle a user basically must access the
Shibboleth-protected page /auth/shibboleth/index.php. If Shibboleth is the only
authentication method (see 4.a), this happens automatically when a user selects
his home organization in the Moodle WAYF service or if the alternate login URL
is configured to be the protected /auth/shibboleth/index.php
Otherwise, the user has to click on the link on the dual login page you
provided in step 5.b.
Moodle basically checks whether the Shibboleth attribute that you mapped
as the username is present. This attribute should only be present if a user is
Shibboleth authenticated.
If the user's Moodle account has not existed yet, it gets automatically created.
To prevent that every Shibboleth user can access your Moodle site you have to
adapt the 'require valid-user' line in your webserver's config (see step 1) to
allow only specific users. If you defined some authorization rules in step 1,
these are checked by Shibboleth itself. Only users who met these rules
actually can access /auth/shibboleth/index.php and get logged in.
You can use Shibboleth AND another authentication method (it was tested with
manual login). So, if there are a few users that don't have a Shibboleth
login, you could create manual accounts for them and they could use the manual
login. For other authentication methods you first have to configure them and
then set Shibboleth as your authentication method. Users can log in only via one
authentication method unless they have two accounts in Moodle.
Shibboleth dual login with custom login page
--------------------------------------------------------------------------------
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. Set this
web page then als alternate login page.
Consult the Moodle documentation for further instructions and requirements.
How to customize the way the Shibboleth user data is used in Moodle
--------------------------------------------------------------------------------
Among the Shibboleth settings in Moodle there is a field that should contain a
path to a php file that can be used as data manipulation hook.
You can use this if you want to further process the way your Shibboleth
attributes are used in Moodle. Due to security reasons this file cannot be
located within the current site data directory ($CFG->dataroot).
Example 1: Your Shibboleth federation uses an attribute that specifies the
user's preferred language, but the content of this attribute is not
compatible with the Moodle data representation, e.g. the Shibboleth
attribute contains 'German' but Moodle needs a two letter value like
'de'.
Example 2: The country, city and street are provided in one Shibboleth attribute
and you want these values to be used in the Moodle user profile. So
You have to parse the corresponding attribute to fill the user fields.
If you want to use this hook you have to be a skilled PHP programmer. It is
strongly recommended that you take a look at the file
moodle/auth/shibboleth/auth.php, especially the function 'get_userinfo'
where this file is included.
The context of the file is the same as within this login function. So you
can directly edit the object $result.
Example file:
--
<?php
// Set the zip code and the adress
if ($_SERVER[$this->config->field_map_address] != '')
{
// $address contains something like 'SWITCH$Limmatquai 138$CH-8021 Zurich'
// We want to split this up to get:
// institution, street, zipcode, city and country
$address = $_SERVER[$this->config->field_map_address];
list($institution, $street, $zip_city) = explode('$', $address);
preg_match('/ (.+)/', $zip_city, $regs);
$city = $regs[1];
preg_match('/(.+)-/',$zip_city, $regs);
$country = $regs[1];
$result["address"] = $street;
$result["city"] = $city;
$result["country"] = $country;
$result["department"] = $institution;
$result["description"] = "I am a Shibboleth user";
}
?>
--
How to upgrade your Service Provider to 2.x
-------------------------------------------------------------------------------
In case your upgrade your Service Provider 1.3.x to 2.x, be aware of the fact
that in version 2.0 the default behaviour regarding attribute propagation
changed.
While the Service Provider 1.3.x published the Shibboleth attributes to the
web server environment as HTTP Request headers, the Service Provider 2.x
publishes attributes as environment variables, which increases the security for
some platforms.
However, this change has the effect that the attribute names change.
E.g. while the surname attribute was published as 'HTTP_SHIB_PERSON_SURNAME'
with 1.3.x, this attribute will be available in $_SERVER['Shib-Person-surname']
or depending on your /etc/shibboleth/attribute-map.xml file just as
$_SERVER['sn'].
Because Moodle needs to know what Shibboleth attributes it shall map onto which
Moodle user profile field, one has to make sure the mapping is updated as well
after the Service Provider upgrade.
********************************************************************************
Because you risk locking yourself out of Moodle it is strongly
recommended to use the following approach when upgrading the Service Provider:
1. Enable manual authentication before the upgrade.
2. Make sure that you have at least one manual account with administration
privileges working before upgrading your Service Provider to 2.x.
3. After the SP upgrade, use this account to log into Moodle and adapt the
attribute mapping in 'Site Administration -> Users -> Shibboleth' to reflect
the changed attribute names.
You find the attribute names in the file /etc/shibboleth/attribute-map.xml
listed as the 'id' value of an attribute definition.
4. If you are using the integrated WAYF, you may have to set the third parameter
of each entry to '/Shibboleth.sso/DS'
5. Test the login with a Shibboleth account
6. If all is working, disable manual authentication again
********************************************************************************
How to add logout support
--------------------------------------------------------------------------------
In order make Moodle support Shibboleth logout, one has to make the Shibboleth
Service Provider (SP) aware of the Moodle logout capability. Only then the SP
can trigger Moodle's front or back channel logout handler.
To make the SP aware of the Moodle logout, you have to add the following to the
Shibboleth main configuration file shibboleth2.xml (usually in /etc/shibboleth/)
just before the <MetadataProvider> element.
--
<Notify
Channel="back"
Location="https://#YOUR_MOODLE_HOSTNAME#/moodle/auth/shibboleth/logout.php" />
--
Then restart the Shibboleth daemon and check the log file for errors. If there
were no errors, you can test the logout feature by accessing Moodle,
authenticating via Shibboleth and the access the URL:
#YOUR_MOODLE_HOSTNAME#/Shibboleth.sso/Logout (assuming you have a standard
Shibboleth installation). If everything worked well, you should see a Shibboleth
page saying that you were successfully logged out and if you go back to Moodle
you also should be logged out from Moodle.
Requirements:
- PHP needs the Soap Extension, which maybe must installed manually:
More information is available here http://ch.php.net/soap
- Logout only works with Shibboleth Service Provider 2.1 or higher
- /moodle/auth/shibboleth/logout.php *must not* be protected by Shibboleth!
In case all of Moodle is protected with Shibboleth, you have to add something
like this to your Apache configuration after all the other require rules
--
<Directory /path/to/moodle/auth/shibboleth/logout.php>
AuthType shibboleth
ShibRequireSession Off
require shibboleth
</Directory>
--
When using IIS, the same can be achieved by something like:
--
<Path name="auth/shibboleth/logout.php" requireSession="false" >
--
in the shibboleth2.xml RequestMap.
Limitations:
Single Logout is only supported when SAML2 is used at the SP and the IdP.
As of October 2009, the Shibboleth Identity Provider 2.1.4 does not yet support
Single Logout (SLO). Therefore, the single logout feature cannot be used yet
in a Shibboleth only setup but there may be other SAML2 products that could
be used as Identity Provider, e.g. SimpleSAML PHP.
One of the reasons why SLO isn't supported yet is because there aren't many
applications yet that were adapted to support front and back channel
logout. Hopefully, the Moodle logout helps to motivate the developers to
implement SLO. On the other hand, the easiest and safest way to log out
still is to tell users to quit their web browsers :)
Also see https://wiki.shibboleth.net/confluence/display/SHIB2/SLOIssues and
https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPLogoutInitiator for some
background information on this topic.
--------------------------------------------------------------------------------
In case of problems and questions with Shibboleth authentication, contact
Lukas Haemmerle <lukas.haemmerle@switch.ch> or Markus Hagman <hagman@hytti.uku.fi>
+413
View File
@@ -0,0 +1,413 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Authentication Plugin: Shibboleth Authentication
* Authentication using Shibboleth.
*
* Distributed under GPL (c)Markus Hagman 2004-2006
*
* @package auth_shibboleth
* @author Martin Dougiamas
* @author Lukas Haemmerle
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
*/
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir.'/authlib.php');
/**
* Shibboleth authentication plugin.
*/
class auth_plugin_shibboleth extends auth_plugin_base {
/**
* Constructor.
*/
public function __construct() {
$this->authtype = 'shibboleth';
$this->config = get_config('auth_shibboleth');
}
/**
* Old syntax of class constructor. Deprecated in PHP7.
*
* @deprecated since Moodle 3.1
*/
public function auth_plugin_shibboleth() {
debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
self::__construct();
}
/**
* Returns true if the username and password work and false if they are
* wrong or don't exist.
*
* @param string $username The username (with system magic quotes)
* @param string $password The password (with system magic quotes)
* @return bool Authentication success or failure.
*/
function user_login($username, $password) {
global $SESSION;
// If we are in the shibboleth directory then we trust the server var
if (!empty($_SERVER[$this->config->user_attribute])) {
// Associate Shibboleth session with user for SLO preparation
$sessionkey = '';
if (isset($_SERVER['Shib-Session-ID'])){
// This is only available for Shibboleth 2.x SPs
$sessionkey = $_SERVER['Shib-Session-ID'];
} else {
// Try to find out using the user's cookie
foreach ($_COOKIE as $name => $value){
if (preg_match('/_shibsession_/i', $name)){
$sessionkey = $value;
}
}
}
// Set shibboleth session ID for logout
$SESSION->shibboleth_session_id = $sessionkey;
return (strtolower($_SERVER[$this->config->user_attribute]) == strtolower($username));
} else {
// If we are not, the user has used the manual login and the login name is
// unknown, so we return false.
return false;
}
}
/**
* Returns the user information for 'external' users. In this case the
* attributes provided by Shibboleth
*
* @return array $result Associative array of user data
*/
function get_userinfo($username) {
// reads user information from shibboleth attributes and return it in array()
global $CFG;
// Check whether we have got all the essential attributes
if ( empty($_SERVER[$this->config->user_attribute]) ) {
throw new \moodle_exception( '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]."')");
}
$attrmap = $this->get_attributes();
$result = array();
$search_attribs = array();
foreach ($attrmap as $key=>$value) {
// Check if attribute is present
if (!isset($_SERVER[$value])){
$result[$key] = '';
continue;
}
// Make usename lowercase
if ($key == 'username'){
$result[$key] = strtolower($this->get_first_string($_SERVER[$value]));
} else {
$result[$key] = $this->get_first_string($_SERVER[$value]);
}
}
// Provide an API to modify the information to fit the Moodle internal
// data representation
if (
$this->config->convert_data
&& $this->config->convert_data != ''
&& is_readable($this->config->convert_data)
) {
// Include a custom file outside the Moodle dir to
// modify the variable $moodleattributes
include($this->config->convert_data);
}
return $result;
}
/**
* Returns array containg attribute mappings between Moodle and Shibboleth.
*
* @return array
*/
function get_attributes() {
$configarray = (array) $this->config;
$moodleattributes = array();
$userfields = array_merge($this->userfields, $this->get_custom_user_profile_fields());
foreach ($userfields as $field) {
if (isset($configarray["field_map_$field"])) {
$moodleattributes[$field] = $configarray["field_map_$field"];
}
}
$moodleattributes['username'] = $configarray["user_attribute"];
return $moodleattributes;
}
function prevent_local_passwords() {
return true;
}
/**
* Returns true if this authentication plugin is 'internal'.
*
* @return bool
*/
function is_internal() {
return false;
}
/**
* Whether shibboleth users can change their password or not.
*
* Shibboleth auth requires password to be changed on shibboleth server directly.
* So it is required to have password change url set.
*
* @return bool true if there's a password url or false otherwise.
*/
function can_change_password() {
if (!empty($this->config->changepasswordurl)) {
return true;
} else {
return false;
}
}
/**
* Get password change url.
*
* @return moodle_url|null Returns URL to change password or null otherwise.
*/
function change_password_url() {
if (!empty($this->config->changepasswordurl)) {
return new moodle_url($this->config->changepasswordurl);
} else {
return null;
}
}
/**
* Hook for login page
*
*/
function loginpage_hook() {
global $SESSION, $CFG;
// Prevent username from being shown on login page after logout
$CFG->nolastloggedin = true;
return;
}
/**
* Hook for logout page
*
*/
function logoutpage_hook() {
global $SESSION, $redirect;
// Only do this if logout handler is defined, and if the user is actually logged in via Shibboleth
$logouthandlervalid = isset($this->config->logout_handler) && !empty($this->config->logout_handler);
if (isset($SESSION->shibboleth_session_id) && $logouthandlervalid ) {
// Check if there is an alternative logout return url defined
if (isset($this->config->logout_return_url) && !empty($this->config->logout_return_url)) {
// Set temp_redirect to alternative return url
$temp_redirect = $this->config->logout_return_url;
} else {
// Backup old redirect url
$temp_redirect = $redirect;
}
// Overwrite redirect in order to send user to Shibboleth logout page and let him return back
$redirecturl = new moodle_url($this->config->logout_handler, array('return' => $temp_redirect));
$redirect = $redirecturl->out();
}
}
/**
* Cleans and returns first of potential many values (multi-valued attributes)
*
* @param string $string Possibly multi-valued attribute from Shibboleth
*/
function get_first_string($string) {
$list = explode( ';', $string);
$clean_string = rtrim($list[0]);
return $clean_string;
}
/**
* Test if settings are correct, print info to output.
*/
public function test_settings() {
global $OUTPUT;
if (!isset($this->config->user_attribute) || empty($this->config->user_attribute)) {
echo $OUTPUT->notification(get_string("shib_not_set_up_error", "auth_shibboleth",
(new moodle_url('/auth/shibboleth/README.txt'))->out()), 'notifyproblem');
return;
}
if ($this->config->convert_data and $this->config->convert_data != '' and !is_readable($this->config->convert_data)) {
echo $OUTPUT->notification(get_string("auth_shib_convert_data_warning", "auth_shibboleth"), 'notifyproblem');
return;
}
if (isset($this->config->organization_selection) && empty($this->config->organization_selection) &&
isset($this->config->alt_login) && $this->config->alt_login == 'on') {
echo $OUTPUT->notification(get_string("auth_shib_no_organizations_warning", "auth_shibboleth"), 'notifyproblem');
return;
}
}
/**
* Return a list of identity providers to display on the login page.
*
* @param string $wantsurl The requested URL.
* @return array List of arrays with keys url, iconurl and name.
*/
public function loginpage_idp_list($wantsurl) {
$config = get_config('auth_shibboleth');
$result = [];
// Before displaying the button check that Shibboleth is set-up correctly.
if (empty($config->user_attribute)) {
return $result;
}
$url = new moodle_url('/auth/shibboleth/index.php');
if ($config->auth_logo) {
$iconurl = moodle_url::make_pluginfile_url(
context_system::instance()->id,
'auth_shibboleth',
'logo',
null,
null,
$config->auth_logo);
} else {
$iconurl = null;
}
$result[] = ['url' => $url, 'iconurl' => $iconurl, 'name' => $config->login_name];
return $result;
}
}
/**
* Sets the standard SAML domain cookie that is also used to preselect
* the right entry on the local way
*
* @param string $selectedIDP IDP identifier
*/
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));
}
/**
* 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 = explode("\n", $organization_selection);
foreach ($idp_raw_list as $idp_line){
$idp_data = explode(',', $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 = explode(' ', $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;
}
@@ -0,0 +1,75 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Special setting for auth_shibboleth convert_data.
*
* @package auth_shibboleth
* @copyright 2020 Mihail Geshoski
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Admin settings class for the convert_data option.
*
* @package auth_shibboleth
* @copyright 2020 Mihail Geshoski
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class auth_shibboleth_admin_setting_convert_data extends admin_setting_configfile {
/**
* Constructor.
*
* @param string $name
* @param string $visiblename
* @param string $description
* @param mixed $defaultdirectory
*/
public function __construct($name, $visiblename, $description, $defaultdirectory) {
parent::__construct($name, $visiblename, $description, $defaultdirectory);
}
/**
* Validate the file path (location).
*
* This method ensures that the file defined as a data modification API exists and is not located in the site
* data directory ($CFG->dataroot). We should prohibit using files from the site data directory as this introduces
* security vulnerabilities.
*
* @param string $filepath The path to the file.
* @return mixed bool true for success or string:error on failure.
*/
public function validate($filepath) {
global $CFG;
if (empty($filepath)) {
return true;
}
// Fail if the file does not exist or it is not readable by the webserver process.
if (!is_readable($filepath)) {
return get_string('auth_shib_convert_data_warning', 'auth_shibboleth');
}
// Fail if the absolute file path matches the currently defined dataroot path.
if (preg_match('/' . preg_quote($CFG->dataroot, '/') . '/', realpath($filepath))) {
return get_string('auth_shib_convert_data_filepath_warning', 'auth_shibboleth');
}
return true;
}
}
@@ -0,0 +1,81 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Special setting for auth_shibboleth WAYF.
*
* @package auth_shibboleth
* @copyright 2017 Stephen Bourget
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Special setting for auth_shibboleth WAYF.
*
* @package auth_shibboleth
* @copyright 2017 Stephen Bourget
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class auth_shibboleth_admin_setting_special_idp_configtextarea extends admin_setting_configtextarea {
/**
* Calls parent::__construct with specific arguments.
*/
public function __construct() {
$default = $orgdefault = "urn:mace:organization1:providerID, Example Organization 1
https://another.idp-id.com/shibboleth, Other Example Organization, /Shibboleth.sso/DS/SWITCHaai
urn:mace:organization2:providerID, Example Organization 2, /Shibboleth.sso/WAYF/SWITCHaai";
parent::__construct('auth_shibboleth/organization_selection',
get_string('auth_shib_idp_list', 'auth_shibboleth'),
get_string('auth_shib_idp_list_description', 'auth_shibboleth'), $default, PARAM_RAW, '60', '8');
}
/**
* We need to overwrite the global "alternate login url" setting if wayf is enabled.
*
* @param string $data Form data.
* @return string Empty when no errors.
*/
public function write_setting($data) {
global $CFG;
$login = get_config('auth_shibboleth', 'alt_login');
if (isset($data) && !empty($data) && isset($login) && $login == 'on') {
// Need to use the get_idp_list() function here.
require_once($CFG->dirroot.'/auth/shibboleth/auth.php');
$idplist = get_idp_list($data);
if (count($idplist) < 1) {
return false;
}
$data = '';
foreach ($idplist as $idp => $value) {
$data .= $idp.', '.$value[0];
if (isset($value[1])) {
// Value[1] is optional.
$data .= ', '.$value[1] . "\n";
} else {
$data .= "\n";
}
}
}
return parent::write_setting($data);
}
}
@@ -0,0 +1,75 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Special settings for auth_shibboleth WAYF.
*
* @package auth_shibboleth
* @copyright 2017 Stephen Bourget
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Special settings for auth_shibboleth WAYF.
*
* @package auth_shibboleth
* @copyright 2017 Stephen Bourget
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class auth_shibboleth_admin_setting_special_wayf_select extends admin_setting_configselect {
/**
* Calls parent::__construct with specific arguments.
*/
public function __construct() {
$yesno = array();
$yesno['off'] = new lang_string('no');
$yesno['on'] = new lang_string('yes');
parent::__construct('auth_shibboleth/alt_login',
new lang_string('auth_shib_integrated_wayf', 'auth_shibboleth'),
new lang_string('auth_shib_integrated_wayf_description', 'auth_shibboleth'),
'off',
$yesno);
}
/**
* We need to overwrite the global "alternate login url" setting if wayf is enabled.
*
* @param string $data Form data.
* @return string Empty when no errors.
*/
public function write_setting($data) {
global $CFG;
// Overwrite alternative login URL if integrated WAYF is used.
if (isset($data) && $data == 'on') {
set_config('alt_login', $data, 'auth_shibboleth');
set_config('alternateloginurl', $CFG->wwwroot.'/auth/shibboleth/login.php');
} else {
// Check if integrated WAYF was enabled and is now turned off.
// If it was and only then, reset the Moodle alternate URL.
$oldsetting = get_config('auth_shibboleth', 'alt_login');
if (isset($oldsetting) and $oldsetting == 'on') {
set_config('alt_login', 'off', 'auth_shibboleth');
set_config('alternateloginurl', '');
}
$data = 'off';
}
return parent::write_setting($data);
}
}
+133
View File
@@ -0,0 +1,133 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Contains a helper class for the Shibboleth authentication plugin.
*
* @package auth_shibboleth
* @copyright 2018 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace auth_shibboleth;
defined('MOODLE_INTERNAL') || die();
/**
* The helper class for the Shibboleth authentication plugin.
*
* @package auth_shibboleth
* @copyright 2018 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class helper {
/**
* Delete session of user using file sessions.
*
* @param string $spsessionid SP-provided Shibboleth Session ID
* @return \SoapFault or void if everything was fine
*/
public static function logout_file_session($spsessionid) {
global $CFG;
if (!empty($CFG->session_file_save_path)) {
$dir = $CFG->session_file_save_path;
} else {
$dir = $CFG->dataroot . '/sessions';
}
if (is_dir($dir)) {
if ($dh = opendir($dir)) {
// Read all session files.
while (($file = readdir($dh)) !== false) {
// Check if it is a file.
if (is_file($dir.'/'.$file)) {
// Read session file data.
$data = file($dir.'/'.$file);
if (isset($data[0])) {
$usersession = self::unserializesession($data[0]);
// Check if we have found session that shall be deleted.
if (isset($usersession['SESSION']) && isset($usersession['SESSION']->shibboleth_session_id)) {
// If there is a match, delete file.
if ($usersession['SESSION']->shibboleth_session_id == $spsessionid) {
// Delete session file.
if (!unlink($dir.'/'.$file)) {
return new SoapFault('LogoutError', 'Could not delete Moodle session file.');
}
}
}
}
}
}
closedir($dh);
}
}
}
/**
* Delete session of user using DB sessions.
*
* @param string $spsessionid SP-provided Shibboleth Session ID
*/
public static function logout_db_session($spsessionid) {
global $CFG, $DB;
$sessions = $DB->get_records_sql(
'SELECT userid, sessdata FROM {sessions} WHERE timemodified > ?',
array(time() - $CFG->sessiontimeout)
);
foreach ($sessions as $session) {
// Get user session from DB.
$usersession = self::unserializesession(base64_decode($session->sessdata));
if (isset($usersession['SESSION']) && isset($usersession['SESSION']->shibboleth_session_id)) {
// If there is a match, kill the session.
if ($usersession['SESSION']->shibboleth_session_id == trim($spsessionid)) {
// Delete this user's sessions.
\core\session\manager::kill_user_sessions($session->userid);
}
}
}
}
/**
* Unserialize a session string.
*
* @param string $serializedstring
* @return array
*/
private static function unserializesession($serializedstring) {
$variables = array();
$index = 0;
// Find next delimiter after current index. It's key being the characters between those points.
while ($delimiterpos = strpos($serializedstring, '|', $index)) {
$key = substr($serializedstring, $index, $delimiterpos - $index);
// Start unserializing immediately after the delimiter. PHP will read as much valid data as possible.
$value = unserialize(substr($serializedstring, $delimiterpos + 1),
['allowed_classes' => ['stdClass']]);
$variables[$key] = $value;
// Advance index beyond the length of the previously captured serialized value.
$index = $delimiterpos + 1 + strlen(serialize($value));
}
return $variables;
}
}
@@ -0,0 +1,41 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Privacy Subsystem implementation for auth_shibboleth.
*
* @package auth_shibboleth
* @copyright 2018 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace auth_shibboleth\privacy;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy Subsystem for auth_shibboleth implementing null_provider.
*
* @copyright 2018 Carlos Escobedo <carlos@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements \core_privacy\local\metadata\null_provider {
/**
* Get the language string identifier with the component's language
* file to explain why this plugin stores no data.
*
* @return string
*/
public static function get_reason(): string {
return 'privacy:metadata';
}
}
+6
View File
@@ -0,0 +1,6 @@
<?php
function xmldb_auth_shibboleth_install() {
global $CFG, $DB;
}
+44
View File
@@ -0,0 +1,44 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Shibboleth authentication plugin upgrade code
*
* @package auth_shibboleth
* @copyright 2017 Stephen Bourget
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Function to upgrade auth_shibboleth.
* @param int $oldversion the version we are upgrading from
* @return bool result
*/
function xmldb_auth_shibboleth_upgrade($oldversion) {
// Automatically generated Moodle v4.1.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.2.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.3.0 release upgrade line.
// Put any upgrade step following this.
// Automatically generated Moodle v4.4.0 release upgrade line.
// Put any upgrade step following this.
return true;
}
+103
View File
@@ -0,0 +1,103 @@
<?php
// Designed to be redirected from moodle/login/index.php
require('../../config.php');
$context = context_system::instance();
$PAGE->set_url('/auth/shibboleth/index.php');
$PAGE->set_context($context);
// Support for WAYFless URLs.
$target = optional_param('target', '', PARAM_LOCALURL);
if (!empty($target) && empty($SESSION->wantsurl)) {
$SESSION->wantsurl = $target;
}
if (isloggedin() && !isguestuser()) { // Nothing to do
if (isset($SESSION->wantsurl) and (strpos($SESSION->wantsurl, $CFG->wwwroot) === 0)) {
$urltogo = $SESSION->wantsurl; /// Because it's an address in this site
unset($SESSION->wantsurl);
} else {
$urltogo = $CFG->wwwroot.'/'; /// Go to the standard home page
unset($SESSION->wantsurl); /// Just in case
}
redirect($urltogo);
}
$pluginconfig = get_config('auth_shibboleth');
$shibbolethauth = get_auth_plugin('shibboleth');
// Check whether Shibboleth is configured properly
$readmeurl = (new moodle_url('/auth/shibboleth/README.txt'))->out();
if (empty($pluginconfig->user_attribute)) {
throw new \moodle_exception('shib_not_set_up_error', 'auth_shibboleth', '', $readmeurl);
}
/// If we can find the Shibboleth attribute, save it in session and return to main login page
if (!empty($_SERVER[$pluginconfig->user_attribute])) { // Shibboleth auto-login
$frm = new stdClass();
$frm->username = strtolower($_SERVER[$pluginconfig->user_attribute]);
// The password is never actually used, but needs to be passed to the functions 'user_login' and
// 'authenticate_user_login'. Shibboleth returns true for the function 'prevent_local_password', which is
// used when setting the password in 'update_internal_user_password'. When 'prevent_local_password'
// returns true, the password is set to 'not cached' (AUTH_PASSWORD_NOT_CACHED) in the Moodle DB. However,
// rather than setting the password to a hard-coded value, we will generate one each time, in case there are
// changes to the Shibboleth plugin and it is actually used.
$frm->password = generate_password(8);
/// Check if the user has actually submitted login data to us
$reason = null;
if ($shibbolethauth->user_login($frm->username, $frm->password)
&& $user = authenticate_user_login($frm->username, $frm->password, false, $reason, false)) {
complete_user_login($user);
if (user_not_fully_set_up($USER, true)) {
$urltogo = $CFG->wwwroot.'/user/edit.php?id='.$USER->id.'&amp;course='.SITEID;
// We don't delete $SESSION->wantsurl yet, so we get there later
} else if (isset($SESSION->wantsurl) and (strpos($SESSION->wantsurl, $CFG->wwwroot) === 0)) {
$urltogo = $SESSION->wantsurl; /// Because it's an address in this site
unset($SESSION->wantsurl);
} else {
$urltogo = $CFG->wwwroot.'/'; /// Go to the standard home page
unset($SESSION->wantsurl); /// Just in case
}
/// Go to my-moodle page instead of homepage if defaulthomepage enabled
if (!has_capability('moodle/site:config',
context_system::instance()) and !empty($CFG->defaulthomepage) and !isguestuser()) {
if ($urltogo == $CFG->wwwroot or $urltogo == $CFG->wwwroot.'/' or $urltogo == $CFG->wwwroot.'/index.php') {
if ($CFG->defaulthomepage == HOMEPAGE_MY && !empty($CFG->enabledashboard)) {
$urltogo = $CFG->wwwroot.'/my/';
} else if ($CFG->defaulthomepage == HOMEPAGE_MYCOURSES) {
$urltogo = $CFG->wwwroot.'/my/courses.php';
}
}
}
redirect($urltogo);
exit;
}
else {
// The Shibboleth user couldn't be mapped to a valid Moodle user
throw new \moodle_exception('shib_invalid_account_error', 'auth_shibboleth');
}
}
// If we can find any (user independent) Shibboleth attributes but no user
// attributes we probably didn't receive any user attributes
elseif (!empty($_SERVER['HTTP_SHIB_APPLICATION_ID']) || !empty($_SERVER['Shib-Application-ID'])) {
throw new \moodle_exception('shib_no_attributes_error', 'auth_shibboleth' , '',
'\''.$pluginconfig->user_attribute.'\', \''.$pluginconfig->field_map_firstname.'\', \''.
$pluginconfig->field_map_lastname.'\' and \''.$pluginconfig->field_map_email.'\'');
} else {
throw new \moodle_exception('shib_not_set_up_error', 'auth_shibboleth', '', $readmeurl);
}
@@ -0,0 +1,63 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Strings for component 'auth_shibboleth', language 'en'.
*
* @package auth_shibboleth
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['auth_shib_auth_method'] = 'Authentication method name';
$string['auth_shib_auth_method_description'] = '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. <tt>SWITCHaai Login</tt> or <tt>InCommon Login</tt> or similar.';
$string['auth_shib_auth_logo'] = 'Authentication method logo';
$string['auth_shib_auth_logo_description'] = 'Provide a logo for the Shibboleth authentication method that is familiar to your users. This could be the logo of your Shibboleth federation, e.g. <tt>SWITCHaai Login</tt> or <tt>InCommon Login</tt> or similar.';
$string['auth_shib_contact_administrator'] = 'In case you are not associated with the given organizations and you need access to a course on this server, please contact the <a href="mailto:{$a}">Moodle Administrator</a>.';
$string['auth_shibbolethdescription'] = 'Using this method users are created and authenticated using Shibboleth. For set-up details, see the <a href="{$a}">Shibboleth README</a>.';
$string['auth_shibboleth_errormsg'] = 'Please select the organization you are member of!';
$string['auth_shibboleth_login'] = 'Shibboleth login';
$string['auth_shibboleth_login_long'] = 'Login to Moodle via Shibboleth';
$string['auth_shibboleth_manual_login'] = 'Manual login';
$string['auth_shibboleth_select_member'] = 'I\'m a member of ...';
$string['auth_shibboleth_select_organization'] = 'For authentication via Shibboleth, please select your organisation from the drop-down menu:';
$string['auth_shib_convert_data'] = 'Data modification API';
$string['auth_shib_convert_data_description'] = 'You can use this API to further modify the data provided by Shibboleth. Read the <a href="{$a}">README</a> for further instructions.';
$string['auth_shib_convert_data_warning'] = 'The file does not exist or is not readable by the webserver process!';
$string['auth_shib_convert_data_filepath_warning'] = 'You cannot use a file that is located within the current site data directory ($CFG->dataroot) as the data modification API.';
$string['auth_shib_changepasswordurl'] = 'Password-change URL';
$string['auth_shib_idp_list'] = 'Identity providers';
$string['auth_shib_idp_list_description'] = 'Provide a list of Identity Provider entityIDs to let the user choose from on the login page.<br />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 drop-down list.<br />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.';
$string['auth_shib_instructions'] = 'Use the <a href="{$a}">Shibboleth login</a> to get access via Shibboleth, if your institution supports it. Otherwise, use the normal login form shown here.';
$string['auth_shib_instructions_help'] = 'Here you should provide custom instructions for your users to explain Shibboleth. It will be shown on the login page in the instructions section. The instructions must include a link to "<b>{$a}</b>" that users click when they want to log in.';
$string['auth_shib_instructions_key'] = 'Login instructions';
$string['auth_shib_integrated_wayf'] = 'Moodle WAYF service';
$string['auth_shib_integrated_wayf_description'] = 'If you enable 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.';
$string['auth_shib_logout_return_url'] = 'Alternative logout return URL';
$string['auth_shib_logout_return_url_description'] = 'Provide the URL that Shibboleth users shall be redirected to after logging out.<br />If left empty, users will be redirected to the location that moodle will redirect users to';
$string['auth_shib_logout_url'] = 'Shibboleth Service Provider logout handler URL';
$string['auth_shib_logout_url_description'] = 'Provide the URL to the Shibboleth Service Provider logout handler. This typically is <tt>/Shibboleth.sso/Logout</tt>';
$string['auth_shib_no_organizations_warning'] = 'If you want to use the integrated WAYF service, you must provide a coma-separated list of Identity Provider entityIDs, their names and optionally a session initiator.';
$string['auth_shib_only'] = 'Shibboleth only';
$string['auth_shib_only_description'] = 'Check this option if a Shibboleth authentication shall be enforced';
$string['auth_shib_username_description'] = 'Name of the webserver Shibboleth environment variable that shall be used as Moodle username';
$string['shib_invalid_account_error'] = 'You seem to be Shibboleth authenticated but Moodle has no valid account for your username. Your account may not exist or it may have been suspended.';
$string['shib_no_attributes_error'] = 'You seem to be Shibboleth authenticated but Moodle didn\'t receive any user attributes. Please check that your Identity Provider releases the necessary attributes ({$a}) to the Service Provider Moodle is running on or inform the webmaster of this server.';
$string['shib_not_all_attributes_error'] = 'Moodle needs certain Shibboleth attributes which are not present in your case. The attributes are: {$a}<br />Please contact the webmaster of this server or your Identity Provider.';
$string['shib_not_set_up_error'] = 'Shibboleth authentication doesn\'t seem to be set up correctly because no Shibboleth environment variables are present for this page. Please consult the <a href="{$a}">README</a> for further instructions on how to set up Shibboleth authentication or contact the webmaster of this Moodle installation.';
$string['pluginname'] = 'Shibboleth';
$string['privacy:metadata'] = 'The Shibboleth authentication plugin does not store any personal data.';
+64
View File
@@ -0,0 +1,64 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file contains the hooks for the Shibboleth authentication module.
*
* @package auth_shibboleth
* @copyright 2018 Fabrice Ménard
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die;
/**
* Serves the logo file settings.
*
* @param stdClass $course course object
* @param stdClass $cm course module object
* @param stdClass $context context object
* @param string $filearea file area
* @param array $args extra arguments
* @param bool $forcedownload whether or not force download
* @param array $options additional options affecting the file serving
* @return bool false if file not found, does not return if found - justsend the file
*/
function auth_shibboleth_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
if ($context->contextlevel != CONTEXT_SYSTEM) {
return false;
}
if ($filearea !== 'logo' ) {
return false;
}
$itemid = 0;
$filename = array_pop($args);
if (!$args) {
$filepath = '/';
} else {
$filepath = '/'.implode('/', $args).'/';
}
$fs = get_file_storage();
$file = $fs->get_file($context->id, 'auth_shibboleth', $filearea, $itemid, $filepath, $filename);
if (!$file) {
return false;
}
send_stored_file($file, null, 0, $forcedownload, $options);
}
+125
View File
@@ -0,0 +1,125 @@
<?php
require_once("../../config.php");
require_once($CFG->dirroot."/auth/shibboleth/auth.php");
$idp = optional_param('idp', null, PARAM_RAW);
// Check for timed out sessions.
if (!empty($SESSION->has_timed_out)) {
$session_has_timed_out = true;
$SESSION->has_timed_out = false;
} else {
$session_has_timed_out = false;
}
// Define variables used in page.
$isvalid = true;
$site = get_site();
$loginsite = get_string("loginsite");
$loginurl = (!empty($CFG->alternateloginurl)) ? $CFG->alternateloginurl : '';
$config = get_config('auth_shibboleth');
if (!empty($CFG->registerauth) or is_enabled_auth('none') or !empty($config->auth_instructions)) {
$showinstructions = true;
} else {
$showinstructions = false;
}
$idplist = get_idp_list($config->organization_selection);
if (isset($idp)) {
if (isset($idplist[$idp])) {
set_saml_cookie($idp);
$targeturl = new moodle_url('/auth/shibboleth/index.php');
$idpinfo = $idplist[$idp];
// Redirect to SessionInitiator with entityID as argument.
if (isset($idpinfo[1]) && !empty($idpinfo[1])) {
$sso = $idpinfo[1];
} else {
$sso = '/Shibboleth.sso';
}
// For Shibboleth 1.x Service Providers.
header('Location: ' . $sso . '?providerId=' . urlencode($idp) . '&target=' . urlencode($targeturl->out()));
} else {
$isvalid = false;
}
}
$loginsite = get_string("loginsite");
$PAGE->set_url('/auth/shibboleth/login.php');
$PAGE->set_context(context_system::instance());
$PAGE->navbar->add($loginsite);
$PAGE->set_title($loginsite);
$PAGE->set_heading($site->fullname);
$PAGE->set_pagelayout('login');
echo $OUTPUT->header();
if (isloggedin() and !isguestuser()) {
// Prevent logging when already logged in, we do not want them to relogin by accident because sesskey would be changed.
echo $OUTPUT->box_start();
$params = array('sesskey' => sesskey(), 'loginpage' => 1);
$logout = new single_button(new moodle_url('/login/logout.php', $params), get_string('logout'), 'post');
$continue = new single_button(new moodle_url('/'), get_string('cancel'), 'get');
echo $OUTPUT->confirm(get_string('alreadyloggedin', 'error', fullname($USER)), $logout, $continue);
echo $OUTPUT->box_end();
} else {
// Print login page.
$selectedidp = '-';
if (isset($_COOKIE['_saml_idp'])) {
$idpcookie = generate_cookie_array($_COOKIE['_saml_idp']);
do {
$selectedidp = array_pop($idpcookie);
} while (!isset($idplist[$selectedidp]) && count($idpcookie) > 0);
}
$idps = [];
foreach ($idplist as $value => $data) {
$name = reset($data);
$selected = $value === $selectedidp;
$idps[] = (object)[
'name' => $name,
'value' => $value,
'selected' => $selected
];
}
// Whether the user can sign up.
$cansignup = !empty($CFG->registerauth);
// Default instructions.
$instructions = format_text($config->auth_instructions);
if (is_enabled_auth('none')) {
$instructions = get_string('loginstepsnone');
} else if ($cansignup) {
if ($CFG->registerauth === 'email' && empty($instructions)) {
$instructions = get_string('loginsteps');
}
}
// Build the template context data.
$templatedata = (object)[
'adminemail' => get_admin()->email,
'cansignup' => $cansignup,
'guestlogin' => $CFG->guestloginbutton,
'guestloginurl' => new moodle_url('/login/index.php'),
'idps' => $idps,
'instructions' => $instructions,
'loginname' => $config->login_name ?? null,
'logintoken' => \core\session\manager::get_login_token(),
'loginurl' => new moodle_url('/auth/shibboleth/login.php'),
'showinstructions' => $showinstructions,
'signupurl' => new moodle_url('/login/signup.php'),
'isvalid' => $isvalid
];
// Render the login form.
echo $OUTPUT->render_from_template('auth_shibboleth/login_form', $templatedata);
}
echo $OUTPUT->footer();
+140
View File
@@ -0,0 +1,140 @@
<?php
// Implements logout for Shibboleth authenticated users according to:
// - https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPLogoutInitiator
// - https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPNotify
require_once("../../config.php");
require_once($CFG->dirroot."/auth/shibboleth/auth.php");
$action = optional_param('action', '', PARAM_ALPHA);
$redirect = optional_param('return', '', PARAM_URL);
// Find out whether host supports https
$protocol = 'http://';
if (is_https()) {
$protocol = 'https://';
}
// If the shibboleth plugin is not enable, throw an exception.
if (!is_enabled_auth('shibboleth')) {
throw new moodle_exception(get_string('pluginnotenabled', 'auth', 'shibboleth'));
}
// Front channel logout.
$inputstream = file_get_contents("php://input");
if ($action == 'logout' && !empty($redirect)) {
if (isloggedin($USER) && $USER->auth == 'shibboleth') {
// Logout user from application.
require_logout();
}
// Finally, send user to the return URL.
redirect($redirect);
} else if (!empty($inputstream)) {
// Back channel logout.
// Set SOAP header.
$server = new SoapServer($protocol.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].'/LogoutNotification.wsdl');
$server->addFunction("LogoutNotification");
$server->handle();
} else {
// Return WSDL.
header('Content-Type: text/xml');
echo <<<WSDL
<?xml version ="1.0" encoding ="UTF-8" ?>
<definitions name="LogoutNotification"
targetNamespace="urn:mace:shibboleth:2.0:sp:notify"
xmlns:notify="urn:mace:shibboleth:2.0:sp:notify"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<!--
This page either has to be called with the GET arguments 'action' and 'return' via
a redirect from the Shibboleth Service Provider logout handler (front-channel
logout) or via a SOAP request by a Shibboleth Service Provider (back-channel
logout).
Because neither of these two variants seems to be the case, the WSDL file for
the web service is returned.
For more information see:
- https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPLogoutInitiator
- https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPNotify
-->
<types>
<schema targetNamespace="urn:mace:shibboleth:2.0:sp:notify"
xmlns="http://www.w3.org/2000/10/XMLSchema"
xmlns:notify="urn:mace:shibboleth:2.0:sp:notify">
<simpleType name="string">
<restriction base="string">
<minLength value="1"/>
</restriction>
</simpleType>
<element name="OK" type="notify:OKType"/>
<complexType name="OKType">
<sequence/>
</complexType>
</schema>
</types>
<message name="getLogoutNotificationRequest">
<part name="SessionID" type="notify:string" />
</message>
<message name="getLogoutNotificationResponse" >
<part name="OK"/>
</message>
<portType name="LogoutNotificationPortType">
<operation name="LogoutNotification">
<input message="getLogoutNotificationRequest"/>
<output message="getLogoutNotificationResponse"/>
</operation>
</portType>
<binding name="LogoutNotificationBinding" type="notify:LogoutNotificationPortType">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="LogoutNotification">
<soap:operation soapAction="urn:xmethods-logout-notification#LogoutNotification"/>
</operation>
</binding>
<service name="LogoutNotificationService">
<port name="LogoutNotificationPort" binding="notify:LogoutNotificationBinding">
<soap:address location="{$protocol}{$_SERVER['HTTP_HOST']}{$_SERVER['PHP_SELF']}"/>
</port>
</service>
</definitions>
WSDL;
exit;
}
/******************************************************************************/
/**
* Handles SOAP Back-channel logout notification
*
* @param string $spsessionid SP-provided Shibboleth Session ID
* @return SoapFault or void if everything was fine
*/
function LogoutNotification($spsessionid) {
$sessionclass = \core\session\manager::get_handler_class();
switch ($sessionclass) {
case '\core\session\file':
return \auth_shibboleth\helper::logout_file_session($spsessionid);
case '\core\session\database':
return \auth_shibboleth\helper::logout_db_session($spsessionid);
default:
throw new moodle_exception("Shibboleth logout not implemented for '$sessionclass'");
}
// If no SoapFault was thrown, the function will return OK as the SP assumes.
}
+89
View File
@@ -0,0 +1,89 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Admin settings and defaults.
*
* @package auth_shibboleth
* @copyright 2017 Stephen Bourget
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die;
if ($ADMIN->fulltree) {
// We use a couple of custom admin settings since we need to massage the data before it is inserted into the DB.
require_once($CFG->dirroot.'/auth/shibboleth/classes/admin_setting_special_wayf_select.php');
require_once($CFG->dirroot.'/auth/shibboleth/classes/admin_setting_special_idp_configtextarea.php');
require_once($CFG->dirroot.'/auth/shibboleth/classes/admin_setting_special_convert_data_configfile.php');
// Introductory explanation.
$readmeurl = (new moodle_url('/auth/shibboleth/README.txt'))->out();
$settings->add(new admin_setting_heading('auth_shibboleth/pluginname', '',
new lang_string('auth_shibbolethdescription', 'auth_shibboleth', $readmeurl)));
// Username.
$settings->add(new admin_setting_configtext('auth_shibboleth/user_attribute', get_string('username'),
get_string('auth_shib_username_description', 'auth_shibboleth'), '', PARAM_RAW));
// Convert Data configuration file.
$settings->add(new auth_shibboleth_admin_setting_convert_data('auth_shibboleth/convert_data',
get_string('auth_shib_convert_data', 'auth_shibboleth'),
get_string('auth_shib_convert_data_description', 'auth_shibboleth', $readmeurl), ''));
// WAYF.
$settings->add(new auth_shibboleth_admin_setting_special_wayf_select());
// Organization_selection.
$settings->add(new auth_shibboleth_admin_setting_special_idp_configtextarea());
// Logout handler.
$settings->add(new admin_setting_configtext('auth_shibboleth/logout_handler',
get_string('auth_shib_logout_url', 'auth_shibboleth'),
get_string('auth_shib_logout_url_description', 'auth_shibboleth'), '', PARAM_URL));
// Logout return URL.
$settings->add(new admin_setting_configtext('auth_shibboleth/logout_return_url',
get_string('auth_shib_logout_return_url', 'auth_shibboleth'),
get_string('auth_shib_logout_return_url_description', 'auth_shibboleth'), '', PARAM_URL));
// Authentication method name.
$settings->add(new admin_setting_configtext('auth_shibboleth/login_name',
get_string('auth_shib_auth_method', 'auth_shibboleth'),
get_string('auth_shib_auth_method_description', 'auth_shibboleth'), 'Shibboleth Login', PARAM_RAW_TRIMMED));
// Authentication method logo.
$settings->add(new admin_setting_configstoredfile('auth_shibboleth/auth_logo',
get_string('auth_shib_auth_logo', 'auth_shibboleth'),
get_string('auth_shib_auth_logo_description', 'auth_shibboleth'), 'logo', 0, ['accepted_types' => ['image']]));
// Login directions.
$settings->add(new admin_setting_configtextarea('auth_shibboleth/auth_instructions',
get_string('auth_shib_instructions_key', 'auth_shibboleth'),
get_string('auth_shib_instructions_help', 'auth_shibboleth', $CFG->wwwroot.'/auth/shibboleth/index.php'),
get_string('auth_shib_instructions', 'auth_shibboleth', $CFG->wwwroot.'/auth/shibboleth/index.php'), PARAM_RAW_TRIMMED));
// Password change URL.
$settings->add(new admin_setting_configtext('auth_shibboleth/changepasswordurl',
get_string('auth_shib_changepasswordurl', 'auth_shibboleth'),
get_string('changepasswordhelp', 'auth'), '', PARAM_URL));
// Display locking / mapping of profile fields.
$authplugin = get_auth_plugin('shibboleth');
display_auth_lock_options($settings, $authplugin->authtype, $authplugin->userfields,
'', true, false, $authplugin->get_custom_user_profile_fields());
}
@@ -0,0 +1,129 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template auth_shibboleth/login_form
Template for the Shibboleth authentication plugin's login form.
Classes required for JS:
* none
Data attributes required for JS:
* none
Context variables required for this template:
* adminemail String The Administrator's email address.
* cansignup Boolean Whether a new user can sign up for an account.
* guestlogin Boolean Whether to show the guest login section.
* guestloginurl String The URL for guest login.
* idps Array The list of identity providers for the Shibboleth authentication plugin in value-name pairs per IDP.
* instructions String Signup instructions.
* isvalid Boolean Whether form validation passes.
* loginname String The custom login name.
* logintoken String The login token.
* loginurl String The login URL.
* showinstructions Boolean Whether to show additional login instructions.
* signupurl String The signup URL.
Example context (json):
{
"loginurl": "#",
"guestloginurl": "#",
"guestlogin": true,
"idps": [
{ "value": 1, "name": "IDP 1" },
{ "value": 2, "name": "IDP 2", "selected": true },
{ "value": 3, "name": "IDP 3" }
],
"showinstructions": true,
"logintoken": "abcde",
"adminemail": "admin@example.com",
"loginname": "Shib auth",
"cansignup": true,
"signupurl": "#",
"instructions": "Sign up here",
"isvalid": false
}
}}
<div class="my-1 my-sm-5"></div>
<div class="container">
<div class="card">
<h2 class="card-header">
{{#loginname}}{{.}}{{/loginname}}
{{^loginname}}{{#str}}auth_shibboleth_login_long, auth_shibboleth{{/str}}{{/loginname}}
</h2>
<div class="card-body">
<div class="row justify-content-center ml-1 mr-1 mb-1">
<div class="col-md-5">
<form action="{{loginurl}}" method="post" id="login">
<div class="mb-3">
<label for="idp">{{#str}}auth_shibboleth_select_organization, auth_shibboleth{{/str}}</label>
<select id="idp" name="idp" class="form-control input-block-level {{^isvalid}}is-invalid{{/isvalid}}">
<option value="-">{{#str}}auth_shibboleth_select_member, auth_shibboleth{{/str}}</option>
{{#idps}}
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
{{/idps}}
</select>
<div class="invalid-feedback text-danger mb-1" {{#isvalid}}hidden{{/isvalid}}>
{{#str}}auth_shibboleth_errormsg, auth_shibboleth{{/str}}
</div>
</div>
<button type="submit" class="btn btn-primary btn-block mb-1" accesskey="s">
{{#str}}select, moodle{{/str}}
</button>
<p class="form-text text-muted mt-1 mb-1">
{{#str}}auth_shib_contact_administrator, auth_shibboleth, {{adminemail}}{{/str}}
</p>
</form>
</div>
{{#guestlogin}}
<div class="col-md-5">
<p>
{{#str}}someallowguest, moodle{{/str}}
</p>
<form action="{{guestloginurl}}" method="post" id="guestlogin">
<div class="guestform">
<input type="hidden" name="logintoken" value="{{logintoken}}">
<input type="hidden" name="username" value="guest">
<input type="hidden" name="password" value="guest">
<button type="submit" class="btn btn-secondary btn-block">
{{#str}}loginguest, moodle{{/str}}
</button>
</div>
</form>
</div>
{{/guestlogin}}
</div>
</div>
</div>
{{#showinstructions}}
<div class="card mt-1">
<div class="card-body ml-1 mr-1 mb-1">
<h2 class="card-title">{{#str}}firsttime, moodle{{/str}}</h2>
<p>
{{{instructions}}}
</p>
{{#cansignup}}
<form action="{{signupurl}}" method="get" id="signup">
<button type="submit" class="btn btn-secondary">{{#str}}startsignup, moodle{{/str}}</button>
</form>
{{/cansignup}}
</div>
</div>
{{/showinstructions}}
</div>
+17
View File
@@ -0,0 +1,17 @@
This files describes API changes in /auth/shibboleth/*,
information provided here is intended especially for developers.
=== 3.11 ===
* The 'Data modification API' (convert_data) setting can no longer be configured to use files located within the
current site data directory ($CFG->dataroot), as it exposes the site to security risks.
=== 3.5.2 ===
* Moved the public function unserializesession in auth/shibboleth/logout.php to auth/shibboleth/classes/helper.php and
made it private. This function should not have been used outside of this file.
=== 3.3 ===
* The config.html file was migrated to use the admin settings API.
The identifier for configuration data stored in config_plugins table was converted from 'auth/shibboleth' to 'auth_shibboleth'.
+30
View File
@@ -0,0 +1,30 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Version information
*
* @package auth_shibboleth
* @author Martin Dougiamas
* @author Lukas Haemmerle
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2024042200; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2024041600; // Requires this Moodle version.
$plugin->component = 'auth_shibboleth'; // Full name of the plugin (used for diagnostics)