Actualización
This commit is contained in:
73
main/auth/cas/cas_var.inc.php
Normal file
73
main/auth/cas/cas_var.inc.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
/* This file contains all the configuration variable for the cas module
|
||||
* In the future, these will be in the database
|
||||
*/
|
||||
|
||||
if (api_is_cas_activated()) {
|
||||
require_once __DIR__.'/../../../vendor/apereo/phpcas/source/CAS.php';
|
||||
|
||||
// Get the $cas array from app/config/auth.conf.php
|
||||
global $cas;
|
||||
|
||||
if (is_array($cas) && array_key_exists('debug', $cas) && !empty($cas['debug'])) {
|
||||
phpCAS::setDebug($cas['debug']);
|
||||
}
|
||||
|
||||
if (is_array($cas) && array_key_exists('verbose', $cas) && $cas['verbose']) {
|
||||
phpCAS::setVerbose(true);
|
||||
}
|
||||
|
||||
if (!phpCAS::isInitialized()) {
|
||||
switch (api_get_setting('cas_protocol')) {
|
||||
case 'CAS1':
|
||||
$version = CAS_VERSION_1_0;
|
||||
break;
|
||||
case 'CAS3':
|
||||
$version = CAS_VERSION_3_0;
|
||||
break;
|
||||
case 'SAML':
|
||||
$version = SAML_VERSION_1_1;
|
||||
break;
|
||||
case 'CAS2':
|
||||
default:
|
||||
$version = CAS_VERSION_2_0;
|
||||
}
|
||||
$port = api_get_setting('cas_port');
|
||||
if (is_null($port)) {
|
||||
$port = 443;
|
||||
} else {
|
||||
$port = intval($port) ?: 443;
|
||||
}
|
||||
$uri = api_get_setting('cas_server_uri') ?: '';
|
||||
$hostname = api_get_setting('cas_server') ?: 'localhost';
|
||||
$serviceBaseUrl = '';
|
||||
|
||||
if (is_array($cas)) {
|
||||
if (array_key_exists('service_base_url', $cas)) {
|
||||
$serviceBaseUrl = $cas['service_base_url'];
|
||||
}
|
||||
}
|
||||
|
||||
phpCAS::client($version, $hostname, $port, $uri, $serviceBaseUrl);
|
||||
|
||||
if (is_array($cas) && array_key_exists('noCasServerValidation', $cas) && $cas['noCasServerValidation']) {
|
||||
phpCAS::setNoCasServerValidation();
|
||||
}
|
||||
|
||||
if (is_array($cas)) {
|
||||
if (array_key_exists('fixedServiceURL', $cas)) {
|
||||
$fixedServiceURL = $cas['fixedServiceURL'];
|
||||
if (is_string($fixedServiceURL)) {
|
||||
phpCAS::setFixedServiceURL($fixedServiceURL);
|
||||
} elseif (is_bool($fixedServiceURL) && $fixedServiceURL) {
|
||||
phpCAS::setFixedServiceURL(api_get_configuration_value('root_web'));
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($cas['saml_validate_url'])) {
|
||||
phpCAS::setServerSamlValidateURL($cas['saml_validate_url']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
51
main/auth/conditional_login/complete_phone_number.php
Normal file
51
main/auth/conditional_login/complete_phone_number.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
require_once __DIR__.'/../../inc/global.inc.php';
|
||||
$url = api_get_path(WEB_PATH).'main/auth/conditional_login/complete_phone_number.php';
|
||||
|
||||
if (!isset($_SESSION['conditional_login']['uid'])) {
|
||||
exit("Not Authorised");
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html lang="fr" xml:lang="fr" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
|
||||
</head>
|
||||
<body>
|
||||
<form id="data_completion" name="data_completion" method="post" action="<?php echo $url; ?>">
|
||||
Téléphone : <input type="text" name="phone_number" />
|
||||
<input type="submit" name="submit" value="Submit" />
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
if (isset($_POST['submit'])) {
|
||||
$u = api_get_user_info($_SESSION['conditional_login']['uid']);
|
||||
$u['phone'] = $_POST['phone_number'];
|
||||
$password = null; // we don't want to change the password
|
||||
$updated = UserManager::update_user(
|
||||
$u['user_id'],
|
||||
$u['firstname'],
|
||||
$u['lastname'],
|
||||
$u['username'],
|
||||
$password,
|
||||
$u['auth_source'],
|
||||
$u['email'],
|
||||
$u['status'],
|
||||
$u['official_code'],
|
||||
$u['phone'],
|
||||
$u['picture_uri'],
|
||||
$u['expiration_date'],
|
||||
$u['active'],
|
||||
$u['creator_id'],
|
||||
$u['hr_dept_id'],
|
||||
$u['extra'],
|
||||
$u['language'],
|
||||
''
|
||||
);
|
||||
if ($updated) {
|
||||
ConditionalLogin::login();
|
||||
}
|
||||
}
|
||||
81
main/auth/conditional_login/conditional_login.php
Normal file
81
main/auth/conditional_login/conditional_login.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
use ChamiloSession as Session;
|
||||
|
||||
/*
|
||||
This script is included by local.inc.php to redirect users to some url if some conditions are satisfied.
|
||||
* Please populate the $login_conditions array with a conditional function and an url.
|
||||
* If the conditional function returns true the user will be redirected to URL at login.
|
||||
* This array must be filled for this module to work.
|
||||
* This is an example asking the user to enter his phone number if it is empty.
|
||||
* Note you can enter more than one condition in the array. They will be checked in the array order.
|
||||
*/
|
||||
/**
|
||||
* Please implements the functions of the $login_conditions array.
|
||||
* Each of these function will take a user array
|
||||
* (user_id, username, password (crypted), auth_source, active, expiration_date).
|
||||
*/
|
||||
$login_conditions = [];
|
||||
|
||||
$conditionalLoginHook = HookConditionalLogin::create();
|
||||
|
||||
if (!empty($conditionalLoginHook)) {
|
||||
foreach ($conditionalLoginHook->notifyConditionalLogin() as $condition) {
|
||||
$login_conditions[] = $condition;
|
||||
}
|
||||
}
|
||||
|
||||
// "Terms and conditions" condition
|
||||
array_push(
|
||||
$login_conditions,
|
||||
[
|
||||
'conditional_function' => 'check_platform_legal_conditions',
|
||||
'url' => api_get_path(WEB_CODE_PATH).'auth/inscription.php',
|
||||
]
|
||||
);
|
||||
|
||||
//array_push($login_conditions, array(
|
||||
// 'conditional_function' => 'dc_check_phone_number',
|
||||
// 'url' => api_get_path(WEB_PATH).'main/auth/conditional_login/complete_phone_number.php'
|
||||
//));
|
||||
|
||||
function dc_check_phone_number($user)
|
||||
{
|
||||
$uInfo = api_get_user_info($user['user_id']);
|
||||
if (empty($uInfo['phone'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the user accepted or not the legal conditions.
|
||||
*
|
||||
* @param array $user
|
||||
*
|
||||
* @return bool true if user pass, false otherwise
|
||||
*/
|
||||
function check_platform_legal_conditions($user)
|
||||
{
|
||||
if (api_get_setting('allow_terms_conditions') === 'true' &&
|
||||
api_get_setting('load_term_conditions_section') === 'login'
|
||||
) {
|
||||
$termAndConditionStatus = api_check_term_condition($user['user_id']);
|
||||
|
||||
// @todo not sure why we need the login password and update_term_status
|
||||
if ($termAndConditionStatus === false) {
|
||||
Session::write('term_and_condition', ['user_id' => $user['user_id']]);
|
||||
|
||||
return false;
|
||||
} else {
|
||||
Session::erase('term_and_condition');
|
||||
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// No validation user can pass
|
||||
return true;
|
||||
}
|
||||
}
|
||||
242
main/auth/courses.php
Normal file
242
main/auth/courses.php
Normal file
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
use Chamilo\CoreBundle\Entity\SequenceResource;
|
||||
|
||||
// Delete the globals['_cid'], we don't need it here.
|
||||
$cidReset = true;
|
||||
|
||||
require_once __DIR__.'/../inc/global.inc.php';
|
||||
|
||||
// Section for the tabs.
|
||||
$this_section = SECTION_CATALOG;
|
||||
|
||||
if ('true' !== api_get_setting('course_catalog_published')) {
|
||||
// Access rights: anonymous users can't do anything useful here.
|
||||
api_block_anonymous_users();
|
||||
}
|
||||
|
||||
$userCanViewPage = CoursesAndSessionsCatalog::userCanView();
|
||||
|
||||
$defaultAction = CoursesAndSessionsCatalog::is(CATALOG_SESSIONS) ? 'display_sessions' : 'display_courses';
|
||||
$action = isset($_REQUEST['action']) ? Security::remove_XSS($_REQUEST['action']) : $defaultAction;
|
||||
$categoryCode = isset($_REQUEST['category_code']) ? Security::remove_XSS($_REQUEST['category_code']) : '';
|
||||
$searchTerm = isset($_REQUEST['search_term']) ? Security::remove_XSS($_REQUEST['search_term']) : '';
|
||||
|
||||
$nameTools = CourseCategory::getCourseCatalogNameTools($action);
|
||||
if (empty($nameTools)) {
|
||||
$nameTools = get_lang('CourseManagement');
|
||||
} else {
|
||||
if (!in_array(
|
||||
$action,
|
||||
['display_random_courses', 'display_courses', 'subscribe']
|
||||
)) {
|
||||
$interbreadcrumb[] = [
|
||||
'url' => api_get_path(WEB_CODE_PATH).'auth/courses.php',
|
||||
'name' => get_lang('CourseManagement'),
|
||||
];
|
||||
}
|
||||
$interbreadcrumb[] = ['url' => '#', 'name' => $nameTools];
|
||||
}
|
||||
|
||||
switch ($action) {
|
||||
case 'unsubscribe':
|
||||
// We are unsubscribing from a course (=Unsubscribe from course).
|
||||
$ctok = Security::get_existing_token();
|
||||
|
||||
if (!empty($_GET['sec_token']) && $ctok == $_GET['sec_token']) {
|
||||
$auth = new Auth();
|
||||
$result = $auth->remove_user_from_course($_GET['course_code']);
|
||||
if ($result) {
|
||||
Display::addFlash(
|
||||
Display::return_message(get_lang('YouAreNowUnsubscribed'), 'success')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$currentUrl = api_get_path(WEB_CODE_PATH).'auth/courses.php?category_code='.$categoryCode.'&search_term='.$searchTerm;
|
||||
|
||||
header('Location: '.$currentUrl);
|
||||
exit;
|
||||
case 'subscribe_course':
|
||||
$courseCodeToSubscribe = isset($_GET['course_code']) ? Security::remove_XSS($_GET['course_code']) : '';
|
||||
if (api_is_anonymous()) {
|
||||
header('Location: '.api_get_path(WEB_CODE_PATH).'auth/inscription.php?c='.$courseCodeToSubscribe);
|
||||
exit;
|
||||
}
|
||||
if (Security::check_token('get')) {
|
||||
$courseInfo = api_get_course_info($courseCodeToSubscribe);
|
||||
if (!empty($courseInfo)) {
|
||||
CourseManager::autoSubscribeToCourse($courseCodeToSubscribe);
|
||||
$redirectionTarget = CoursesAndSessionsCatalog::generateRedirectUrlAfterSubscription(
|
||||
$courseInfo['course_public_url']
|
||||
);
|
||||
|
||||
header("Location: $redirectionTarget");
|
||||
exit;
|
||||
}
|
||||
}
|
||||
Display::addFlash(
|
||||
Display::return_message(get_lang('NoResults'), 'warning')
|
||||
);
|
||||
CoursesAndSessionsCatalog::displayCoursesList('search_course', $searchTerm, $categoryCode);
|
||||
|
||||
exit;
|
||||
|
||||
break;
|
||||
case 'subscribe_course_validation':
|
||||
$toolTitle = get_lang('Subscribe');
|
||||
$courseCodeToSubscribe = isset($_GET['course_code']) ? Security::remove_XSS($_GET['course_code']) : '';
|
||||
$courseInfo = api_get_course_info($courseCodeToSubscribe);
|
||||
if (empty($courseInfo)) {
|
||||
header('Location: '.api_get_self());
|
||||
exit;
|
||||
}
|
||||
$message = get_lang('CourseRequiresPassword').' ';
|
||||
$message .= $courseInfo['title'].' ('.$courseInfo['visual_code'].') ';
|
||||
|
||||
$action = api_get_self().'?action=subscribe_course_validation&sec_token='.
|
||||
Security::getTokenFromSession().'&course_code='.$courseInfo['code'];
|
||||
$form = new FormValidator(
|
||||
'subscribe_user_with_password',
|
||||
'post',
|
||||
$action
|
||||
);
|
||||
$form->addHeader($message);
|
||||
$form->addElement('hidden', 'sec_token', Security::getTokenFromSession());
|
||||
$form->addElement('hidden', 'subscribe_user_with_password', $courseInfo['code']);
|
||||
$form->addElement('text', 'course_registration_code');
|
||||
$form->addButtonSave(get_lang('SubmitRegistrationCode'));
|
||||
$content = $form->returnForm();
|
||||
|
||||
if ($form->validate()) {
|
||||
if (sha1($_POST['course_registration_code']) === $courseInfo['registration_code']) {
|
||||
CourseManager::autoSubscribeToCourse($_POST['subscribe_user_with_password']);
|
||||
|
||||
$redirectionTarget = CoursesAndSessionsCatalog::generateRedirectUrlAfterSubscription(
|
||||
$courseInfo['course_public_url']
|
||||
);
|
||||
|
||||
header("Location: $redirectionTarget");
|
||||
} else {
|
||||
Display::addFlash(Display::return_message(get_lang('CourseRegistrationCodeIncorrect'), 'warning'));
|
||||
header('Location: '.$action);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
$template = new Template($toolTitle, true, true, false, false, false);
|
||||
$template->assign('content', $content);
|
||||
$template->display_one_col_template();
|
||||
break;
|
||||
case 'subscribe':
|
||||
if (!$userCanViewPage) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
header('Location: '.api_get_self());
|
||||
exit;
|
||||
case 'display_random_courses':
|
||||
case 'display_courses':
|
||||
case 'search_course':
|
||||
if (!$userCanViewPage) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
CoursesAndSessionsCatalog::displayCoursesList($action, $searchTerm, $categoryCode);
|
||||
exit;
|
||||
case 'display_sessions':
|
||||
if (!$userCanViewPage) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
CoursesAndSessionsCatalog::sessionList();
|
||||
exit;
|
||||
case 'subscribe_to_session':
|
||||
if (!$userCanViewPage) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$userId = api_get_user_id();
|
||||
$confirmed = isset($_GET['confirm']);
|
||||
$sessionId = (int) $_GET['session_id'];
|
||||
|
||||
if (empty($userId)) {
|
||||
api_not_allowed();
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!$confirmed) {
|
||||
$template = new Template(null, false, false, false, false, false);
|
||||
$template->assign('session_id', $sessionId);
|
||||
$layout = $template->get_template('auth/confirm_session_subscription.tpl');
|
||||
echo $template->fetch($layout);
|
||||
exit;
|
||||
}
|
||||
|
||||
$registrationAllowed = api_get_setting('catalog_allow_session_auto_subscription');
|
||||
if ('true' === $registrationAllowed) {
|
||||
$entityManager = Database::getManager();
|
||||
$repository = $entityManager->getRepository('ChamiloCoreBundle:SequenceResource');
|
||||
$sequences = $repository->getRequirements(
|
||||
$sessionId,
|
||||
SequenceResource::SESSION_TYPE
|
||||
);
|
||||
|
||||
if (count($sequences) > 0) {
|
||||
$requirementsData = $repository->checkRequirementsForUser(
|
||||
$sequences,
|
||||
SequenceResource::SESSION_TYPE,
|
||||
$userId,
|
||||
$sessionId
|
||||
);
|
||||
|
||||
$continueWithSubscription = $repository->checkSequenceAreCompleted($requirementsData);
|
||||
|
||||
if (!$continueWithSubscription) {
|
||||
header('Location: '.api_get_path(WEB_CODE_PATH).'auth/courses.php');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
SessionManager::subscribeUsersToSession(
|
||||
$sessionId,
|
||||
[$userId],
|
||||
SESSION_VISIBLE_READ_ONLY,
|
||||
false
|
||||
);
|
||||
|
||||
$coursesList = SessionManager::get_course_list_by_session_id($sessionId);
|
||||
$count = count($coursesList);
|
||||
$url = '';
|
||||
|
||||
if ($count <= 0) {
|
||||
// no course in session -> return to catalog
|
||||
$url = api_get_path(WEB_CODE_PATH).'auth/courses.php';
|
||||
} elseif (1 == $count) {
|
||||
// only one course, so redirect directly to this course
|
||||
foreach ($coursesList as $course) {
|
||||
$url = api_get_path(WEB_COURSE_PATH).$course['directory'].'/index.php?id_session='.$sessionId;
|
||||
}
|
||||
} else {
|
||||
$url = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$sessionId;
|
||||
}
|
||||
header('Location: '.$url);
|
||||
exit;
|
||||
}
|
||||
break;
|
||||
case 'search_tag':
|
||||
if (!$userCanViewPage) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
CoursesAndSessionsCatalog::sessionsListByCoursesTag();
|
||||
exit;
|
||||
case 'search_session_title':
|
||||
if (!$userCanViewPage) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
CoursesAndSessionsCatalog::sessionsListByName();
|
||||
exit;
|
||||
}
|
||||
220
main/auth/external_login/facebook.inc.php
Normal file
220
main/auth/external_login/facebook.inc.php
Normal file
@@ -0,0 +1,220 @@
|
||||
<?php
|
||||
/**
|
||||
* Licence: GPL
|
||||
* Please contact CBlue regarding any licences issues.
|
||||
* Author: noel@cblue.be
|
||||
* Copyright: CBlue SPRL, 20XX.
|
||||
*
|
||||
* External login module : FACEBOOK
|
||||
*
|
||||
* This files provides the facebookConnect() and facebook_get_url functions
|
||||
* Please edit the facebook.conf.php file to adapt it to your fb application parameter
|
||||
*/
|
||||
require_once __DIR__.'/../../inc/global.inc.php';
|
||||
require_once __DIR__.'/facebook.init.php';
|
||||
require_once __DIR__.'/functions.inc.php';
|
||||
|
||||
/**
|
||||
* This function connect to facebook and retrieves the user info
|
||||
* If user does not exist in chamilo, it creates it and logs in
|
||||
* If user already exists, it updates his info.
|
||||
*/
|
||||
function facebookConnect()
|
||||
{
|
||||
$fb = new \Facebook\Facebook([
|
||||
'app_id' => $GLOBALS['facebook_config']['appId'],
|
||||
'app_secret' => $GLOBALS['facebook_config']['secret'],
|
||||
'default_graph_version' => 'v2.2',
|
||||
]);
|
||||
|
||||
$helper = $fb->getRedirectLoginHelper();
|
||||
|
||||
try {
|
||||
$accessToken = $helper->getAccessToken();
|
||||
} catch (Facebook\Exceptions\FacebookResponseException $e) {
|
||||
Display::addFlash(
|
||||
Display::return_message('Facebook Graph returned an error: '.$e->getMessage(), 'error')
|
||||
);
|
||||
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit;
|
||||
} catch (Facebook\Exceptions\FacebookSDKException $e) {
|
||||
Display::addFlash(
|
||||
Display::return_message('Facebook SDK returned an error: '.$e->getMessage(), 'error')
|
||||
);
|
||||
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!isset($accessToken)) {
|
||||
if (!$helper->getError()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($_GET['loginFailed'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$error = implode('<br>', [
|
||||
'Error: '.$helper->getError(),
|
||||
'Error Code: '.$helper->getErrorCode(),
|
||||
'Error Reason: '.$helper->getErrorReason(),
|
||||
'Error Description: '.$helper->getErrorDescription(),
|
||||
]);
|
||||
|
||||
Display::addFlash(
|
||||
Display::return_message($error, 'error', false)
|
||||
);
|
||||
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit;
|
||||
}
|
||||
|
||||
$oAuth2Client = $fb->getOAuth2Client();
|
||||
$tokenMetadata = $oAuth2Client->debugToken($accessToken);
|
||||
$tokenMetadata->validateAppId($GLOBALS['facebook_config']['appId']);
|
||||
$tokenMetadata->validateExpiration();
|
||||
|
||||
if (!$accessToken->isLongLived()) {
|
||||
try {
|
||||
$accessToken = $oAuth2Client->getLongLivedAccessToken($accessToken);
|
||||
} catch (Facebook\Exceptions\FacebookSDKException $e) {
|
||||
Display::addFlash(
|
||||
Display::return_message('Error getting long-lived access token: '.$e->getMessage(), 'error')
|
||||
);
|
||||
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$response = $fb->get('/me?fields=id,first_name,last_name,locale,email', $accessToken->getValue());
|
||||
} catch (Facebook\Exceptions\FacebookResponseException $e) {
|
||||
Display::addFlash(
|
||||
Display::return_message('Graph returned an error: '.$e->getMessage(), 'error')
|
||||
);
|
||||
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit;
|
||||
} catch (Facebook\Exceptions\FacebookSDKException $e) {
|
||||
Display::addFlash(
|
||||
Display::return_message('Facebook SDK returned an error: '.$e->getMessage(), 'error')
|
||||
);
|
||||
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit;
|
||||
}
|
||||
|
||||
$user = $response->getGraphUser();
|
||||
$language = facebookPluginGetLanguage($user['locale']);
|
||||
|
||||
if (!$language) {
|
||||
$language = 'en_US';
|
||||
}
|
||||
|
||||
$u = [
|
||||
'firstname' => $user->getFirstName(),
|
||||
'lastname' => $user->getLastName(),
|
||||
'status' => STUDENT,
|
||||
'email' => $user->getEmail(),
|
||||
'username' => changeToValidChamiloLogin($user->getEmail()),
|
||||
'language' => $language,
|
||||
'password' => 'facebook',
|
||||
'auth_source' => 'facebook',
|
||||
'extra' => [],
|
||||
];
|
||||
$chamiloUinfo = api_get_user_info_from_email($user->getEmail());
|
||||
|
||||
$_user['uidReset'] = true;
|
||||
$_user['language'] = $language;
|
||||
|
||||
if ($chamiloUinfo === false) {
|
||||
// We have to create the user
|
||||
$chamilo_uid = external_add_user($u);
|
||||
|
||||
if ($chamilo_uid === false) {
|
||||
Display::addFlash(
|
||||
Display::return_message(get_lang('UserNotRegistered'), 'error')
|
||||
);
|
||||
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit;
|
||||
}
|
||||
|
||||
$_user['user_id'] = $chamilo_uid;
|
||||
$_SESSION['_user'] = $_user;
|
||||
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit();
|
||||
}
|
||||
|
||||
// User already exists, update info and login
|
||||
$chamilo_uid = $chamiloUinfo['user_id'];
|
||||
$u['user_id'] = $chamilo_uid;
|
||||
external_update_user($u);
|
||||
$_user['user_id'] = $chamilo_uid;
|
||||
$_SESSION['_user'] = $_user;
|
||||
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get facebook login url for the platform.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function facebookGetLoginUrl()
|
||||
{
|
||||
$fb = new \Facebook\Facebook([
|
||||
'app_id' => $GLOBALS['facebook_config']['appId'],
|
||||
'app_secret' => $GLOBALS['facebook_config']['secret'],
|
||||
'default_graph_version' => 'v2.2',
|
||||
]);
|
||||
|
||||
$helper = $fb->getRedirectLoginHelper();
|
||||
$loginUrl = $helper->getLoginUrl(api_get_path(WEB_PATH).'?action=fbconnect', [
|
||||
'email',
|
||||
]);
|
||||
|
||||
return $loginUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a valid Chamilo login
|
||||
* Chamilo login only use characters lettres, des chiffres et les signes _ . -.
|
||||
*
|
||||
* @param $in_txt
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function changeToValidChamiloLogin($in_txt)
|
||||
{
|
||||
return preg_replace("/[^a-zA-Z1-9_\-.]/", "_", $in_txt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user language.
|
||||
*
|
||||
* @param string $language
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function facebookPluginGetLanguage($language = 'en_US')
|
||||
{
|
||||
$language = substr($language, 0, 2);
|
||||
$sqlResult = Database::query(
|
||||
"SELECT english_name FROM ".
|
||||
Database::get_main_table(TABLE_MAIN_LANGUAGE).
|
||||
" WHERE available = 1 AND isocode = '$language'"
|
||||
);
|
||||
if (Database::num_rows($sqlResult)) {
|
||||
$result = Database::fetch_array($sqlResult);
|
||||
|
||||
return $result['english_name'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
24
main/auth/external_login/facebook.init.php
Normal file
24
main/auth/external_login/facebook.init.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Licence: GPL
|
||||
* Please contact CBlue regarding any licences issues.
|
||||
* Author: noel@cblue.be
|
||||
* Copyright: CBlue SPRL, 20XX.
|
||||
*
|
||||
* External login module : FACEBOOK
|
||||
*
|
||||
* Configuration file
|
||||
* Please edit this file to match with your FACEBOOK settings
|
||||
* */
|
||||
/**
|
||||
* Facebook application setting.
|
||||
* */
|
||||
|
||||
//Loads the portal facebook settings
|
||||
/**
|
||||
* Facebook application setting
|
||||
* Loads the portal facebook settings
|
||||
* See facebook section of the auth.conf.php file.
|
||||
*/
|
||||
require __DIR__.'/../../../app/config/auth.conf.php';
|
||||
225
main/auth/external_login/functions.inc.php
Normal file
225
main/auth/external_login/functions.inc.php
Normal file
@@ -0,0 +1,225 @@
|
||||
<?php
|
||||
|
||||
//TODO : Please implements this function for this module to work.
|
||||
|
||||
/**
|
||||
* Gets user info from external source.
|
||||
*
|
||||
* @param string login
|
||||
* @param string password
|
||||
*
|
||||
* @return user array with at least the following fields:
|
||||
* firstname
|
||||
* lastname
|
||||
* status
|
||||
* email
|
||||
* login
|
||||
* password
|
||||
* or false if no data
|
||||
* */
|
||||
function external_get_user_info($login, $password)
|
||||
{
|
||||
//Those are the mandatory fields for user creation.
|
||||
//See external_add_user function for all the fields you can have.
|
||||
$table = USERINFO_TABLE;
|
||||
$sql = "SELECT * from $table where username='".Database::escape_string($login)."'";
|
||||
$result = Database::query($sql);
|
||||
|
||||
if (Database::num_rows($result) == 0) { //false password
|
||||
return false;
|
||||
}
|
||||
$user_info = Database::fetch_assoc($result);
|
||||
// User status
|
||||
$admin = false;
|
||||
switch ($user_info['status']) {
|
||||
case 'admin':
|
||||
$status = COURSEMANAGER;
|
||||
$admin = true;
|
||||
break;
|
||||
case 'teacher':
|
||||
$status = COURSEMANAGER;
|
||||
break;
|
||||
case 'user':
|
||||
$status = STUDENT;
|
||||
break;
|
||||
default:
|
||||
$status = STUDENT;
|
||||
}
|
||||
|
||||
// Language
|
||||
switch ($user_info['language']) {
|
||||
case 'FR':
|
||||
$language = 'french';
|
||||
break;
|
||||
case 'EN':
|
||||
$language = 'english';
|
||||
break;
|
||||
default:
|
||||
$language = 'english';
|
||||
break;
|
||||
}
|
||||
//Can Send Message ?
|
||||
$can_send_message = ($user_info['can_send_message'] == 1) ? 'yes' : 'no';
|
||||
|
||||
$u = [
|
||||
'firstname' => $user_info['firstname'],
|
||||
'lastname' => $user_info['lastname'],
|
||||
'status' => $status,
|
||||
'admin' => $admin,
|
||||
'email' => $user_info['email'],
|
||||
'username' => $user_info['username'],
|
||||
'language' => $language,
|
||||
'password' => DEFAULT_PASSWORD,
|
||||
'courses' => $user_info['courses'],
|
||||
'profile_link' => $user_info['profile_link'],
|
||||
'worldwide_bu' => $user_info['worlwide_bu'],
|
||||
'manager' => $user_info['manager'],
|
||||
'extra' => [
|
||||
'position_title' => $user_info['position_title'],
|
||||
'country' => $user_info['country'],
|
||||
'job_family' => $user_info['job_family'],
|
||||
'country_bu' => $user_info['country_bu'],
|
||||
'worldwide_bu' => $user_info['worldwide_bu'],
|
||||
'profile_link' => $user_info['profile_link'],
|
||||
'can_send_message' => $can_send_message,
|
||||
'update_type' => 'external_logininfo', ],
|
||||
];
|
||||
|
||||
return $u; //Please return false if user does not exist
|
||||
//return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array with all user info.
|
||||
*
|
||||
* @param associative array with at least thes fields setted :
|
||||
firstname, lastname, status, email, login, password
|
||||
* @return mixed new user id - if the new user creation succeeds, false otherwise
|
||||
* */
|
||||
function external_add_user($u)
|
||||
{
|
||||
//Setting default
|
||||
if (empty($u['password'])) {
|
||||
$u['password'] = null;
|
||||
}
|
||||
if (empty($u['status'])) {
|
||||
$u['status'] = 5;
|
||||
}
|
||||
if (!isset($u['email'])) {
|
||||
$u['email'] = '';
|
||||
}
|
||||
if (!isset($u['official_code'])) {
|
||||
$u['official_code'] = '';
|
||||
}
|
||||
if (!isset($u['language'])) {
|
||||
$u['language'] = '';
|
||||
}
|
||||
if (!isset($u['phone'])) {
|
||||
$u['phone'] = '';
|
||||
}
|
||||
if (!isset($u['picture_uri'])) {
|
||||
$u['picture_uri'] = '';
|
||||
}
|
||||
if (!isset($u['auth_source'])) {
|
||||
$u['auth_source'] = PLATFORM_AUTH_SOURCE;
|
||||
}
|
||||
if (!isset($u['expiration_date'])) {
|
||||
$u['expiration_date'] = '';
|
||||
}
|
||||
if (!isset($u['active'])) {
|
||||
$u['active'] = 1;
|
||||
}
|
||||
if (!isset($u['hr_dept_id'])) {
|
||||
$u['hr_dept_id'] = 0;
|
||||
} //id of responsible HR
|
||||
if (!isset($u['extra'])) {
|
||||
$u['extra'] = null;
|
||||
}
|
||||
if (!isset($u['encrypt_method'])) {
|
||||
$u['encrypt_method'] = '';
|
||||
}
|
||||
|
||||
$chamilo_uid = UserManager::create_user(
|
||||
$u['firstname'],
|
||||
$u['lastname'],
|
||||
$u['status'],
|
||||
$u['email'],
|
||||
$u['username'],
|
||||
$u['password'],
|
||||
$u['official_code'],
|
||||
$u['language'],
|
||||
$u['phone'],
|
||||
$u['picture_uri'],
|
||||
$u['auth_source'],
|
||||
$u['expiration_date'],
|
||||
$u['active'],
|
||||
$u['hr_dept_id'],
|
||||
$u['extra'],
|
||||
$u['encrypt_method']
|
||||
);
|
||||
|
||||
return $chamilo_uid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the user in chamilo database. It upgrade only info that is present in the
|
||||
* new_user array.
|
||||
*
|
||||
* @param $new_user associative array with the value to upgrade
|
||||
* WARNING user_id key is MANDATORY
|
||||
* Possible keys are :
|
||||
* - firstname
|
||||
* - lastname
|
||||
* - username
|
||||
* - auth_source
|
||||
* - email
|
||||
* - status
|
||||
* - official_code
|
||||
* - phone
|
||||
* - picture_uri
|
||||
* - expiration_date
|
||||
* - active
|
||||
* - creator_id
|
||||
* - hr_dept_id
|
||||
* - extra : array of custom fields
|
||||
* - language
|
||||
* - courses : string of all courses code separated by '|'
|
||||
* - admin : boolean
|
||||
*
|
||||
* @return bool|null
|
||||
*
|
||||
* @author ndiechburg <noel@cblue.be>
|
||||
* */
|
||||
function external_update_user($new_user)
|
||||
{
|
||||
$old_user = api_get_user_info($new_user['user_id']);
|
||||
$u = array_merge($old_user, $new_user);
|
||||
UserManager::update_user(
|
||||
$u['user_id'],
|
||||
$u['firstname'],
|
||||
$u['lastname'],
|
||||
$u['username'],
|
||||
null,
|
||||
$u['auth_source'],
|
||||
$u['email'],
|
||||
$u['status'],
|
||||
$u['official_code'],
|
||||
$u['phone'],
|
||||
$u['picture_uri'],
|
||||
$u['expiration_date'],
|
||||
$u['active'],
|
||||
$u['creator_id'],
|
||||
$u['hr_dept_id'],
|
||||
$u['extra'],
|
||||
$u['language'],
|
||||
''
|
||||
);
|
||||
if (isset($u['courses']) && !empty($u['courses'])) {
|
||||
$autoSubscribe = explode('|', $u['courses']);
|
||||
foreach ($autoSubscribe as $code) {
|
||||
if (CourseManager::course_exists($code)) {
|
||||
CourseManager::subscribeUser($u['user_id'], $code, STUDENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
522
main/auth/external_login/ldap.inc.php
Normal file
522
main/auth/external_login/ldap.inc.php
Normal file
@@ -0,0 +1,522 @@
|
||||
<?php
|
||||
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
/**
|
||||
* This files is included by newUser.ldap.php and login.ldap.php
|
||||
* It implements the functions nedded by both files.
|
||||
* */
|
||||
require_once __DIR__.'/../../inc/global.inc.php';
|
||||
|
||||
$debug = false;
|
||||
|
||||
/**
|
||||
* Returns a transcoded and trimmed string.
|
||||
*
|
||||
* @param string
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @author ndiechburg <noel@cblue.be>
|
||||
* */
|
||||
function extldap_purify_string($string)
|
||||
{
|
||||
global $extldap_config;
|
||||
if (isset($extldap_config['encoding'])) {
|
||||
return trim(api_to_system_encoding($string, $extldap_config['encoding']));
|
||||
} else {
|
||||
return trim($string);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes a connection to the LDAP server and sets the protocol version.
|
||||
*
|
||||
* @return resource|bool ldap link identifier or false
|
||||
*
|
||||
* @author ndiechburg <noel@cblue.be>
|
||||
* */
|
||||
function extldap_connect()
|
||||
{
|
||||
global $extldap_config, $debug;
|
||||
|
||||
if (!is_array($extldap_config['host'])) {
|
||||
$extldap_config['host'] = [$extldap_config['host']];
|
||||
}
|
||||
|
||||
foreach ($extldap_config['host'] as $host) {
|
||||
//Trying to connect
|
||||
if (isset($extldap_config['port'])) {
|
||||
$ds = ldap_connect($host, $extldap_config['port']);
|
||||
} else {
|
||||
$ds = ldap_connect($host);
|
||||
}
|
||||
if (!$ds) {
|
||||
$port = isset($extldap_config['port']) ? $extldap_config['port'] : 389;
|
||||
if ($debug) {
|
||||
error_log(
|
||||
'EXTLDAP ERROR : cannot connect to '.$extldap_config['host'].':'.$port
|
||||
);
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$ds) {
|
||||
if ($debug) {
|
||||
error_log('EXTLDAP ERROR : no valid server found');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// Setting protocol version
|
||||
if (isset($extldap_config['protocol_version'])) {
|
||||
if (!ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, $extldap_config['protocol_version'])) {
|
||||
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Setting protocol version
|
||||
if (isset($extldap_config['referrals'])) {
|
||||
if (!ldap_set_option($ds, LDAP_OPT_REFERRALS, $extldap_config['referrals'])) {
|
||||
ldap_set_option($ds, LDAP_OPT_REFERRALS, $extldap_config['referrals']);
|
||||
}
|
||||
}
|
||||
|
||||
return $ds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate user on external ldap server and return user ldap entry if that succeeds.
|
||||
*
|
||||
* @param string $password
|
||||
*
|
||||
* @return mixed false if user cannot authenticate on ldap, user ldap entry if tha succeeds
|
||||
*
|
||||
* @author ndiechburg <noel@cblue.be>
|
||||
* Modified by hubert.borderiou@grenet.fr
|
||||
* Add possibility to get user info from LDAP without check password (if CAS auth and LDAP profil update)
|
||||
*
|
||||
* */
|
||||
function extldap_authenticate($username, $password, $in_auth_with_no_password = false)
|
||||
{
|
||||
global $extldap_config, $debug;
|
||||
|
||||
if (empty($username) || empty($password)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$ds = extldap_connect();
|
||||
if (!$ds) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Connection as admin to search dn of user
|
||||
|
||||
if (api_get_configuration_value('ldap_encrypt_admin_password')) {
|
||||
$ldap_pass = api_decrypt_ldap_password($extldap_config['admin_password']);
|
||||
} else {
|
||||
$ldap_pass = $extldap_config['admin_password'];
|
||||
}
|
||||
$ldapbind = @ldap_bind($ds, $extldap_config['admin_dn'], $ldap_pass);
|
||||
if ($ldapbind === false) {
|
||||
if ($debug) {
|
||||
error_log(
|
||||
'EXTLDAP ERROR : cannot connect with admin login/password'
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
$user_search = extldap_get_user_search_string($username);
|
||||
// Search distinguish name of user
|
||||
$sr = ldap_search($ds, $extldap_config['base_dn'], $user_search);
|
||||
if (!$sr) {
|
||||
if ($debug) {
|
||||
error_log(
|
||||
'EXTLDAP ERROR : ldap_search('.$ds.', '.$extldap_config['base_dn'].", $user_search) failed"
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$entries_count = ldap_count_entries($ds, $sr);
|
||||
|
||||
if ($entries_count > 1) {
|
||||
if ($debug) {
|
||||
error_log(
|
||||
'EXTLDAP ERROR : more than one entry for that user ( ldap_search(ds, '.$extldap_config['base_dn'].", $user_search) )"
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
if ($entries_count < 1) {
|
||||
if ($debug) {
|
||||
error_log(
|
||||
'EXTLDAP ERROR : No entry for that user ( ldap_search(ds, '.$extldap_config['base_dn'].", $user_search) )"
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
$users = ldap_get_entries($ds, $sr);
|
||||
$user = $users[0];
|
||||
|
||||
// If we just want to have user info from LDAP and not to check password
|
||||
if ($in_auth_with_no_password) {
|
||||
return $user;
|
||||
}
|
||||
|
||||
// now we try to autenthicate the user in the ldap
|
||||
$ubind = @ldap_bind($ds, $user['dn'], $password);
|
||||
if ($ubind !== false) {
|
||||
return $user;
|
||||
} else {
|
||||
if ($debug) {
|
||||
error_log('EXTLDAP : Wrong password for '.$user['dn']);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array with userinfo compatible with chamilo using $extldap_user_correspondance
|
||||
* configuration array declared in ldap.conf.php file.
|
||||
*
|
||||
* @param array ldap user
|
||||
* @param array correspondance array (if not set use extldap_user_correspondance declared in auth.conf.php
|
||||
*
|
||||
* @return array userinfo array
|
||||
*
|
||||
* @author ndiechburg <noel@cblue.be>
|
||||
* */
|
||||
function extldap_get_chamilo_user($ldap_user, $cor = null)
|
||||
{
|
||||
global $extldap_user_correspondance, $debug;
|
||||
if (is_null($cor)) {
|
||||
$cor = $extldap_user_correspondance;
|
||||
}
|
||||
|
||||
$chamilo_user = [];
|
||||
foreach ($cor as $chamilo_field => $ldap_field) {
|
||||
if (is_array($ldap_field)) {
|
||||
$chamilo_user[$chamilo_field] = extldap_get_chamilo_user($ldap_user, $ldap_field);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch ($ldap_field) {
|
||||
case 'func':
|
||||
$func = "extldap_get_$chamilo_field";
|
||||
if (function_exists($func)) {
|
||||
$chamilo_user[$chamilo_field] = extldap_purify_string($func($ldap_user));
|
||||
} else {
|
||||
if ($debug) {
|
||||
error_log(
|
||||
"EXTLDAP WARNING : You forgot to declare $func"
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//if string begins with "!", then this is a constant
|
||||
if ($ldap_field[0] === '!') {
|
||||
$chamilo_user[$chamilo_field] = trim($ldap_field, "!\t\n\r\0");
|
||||
break;
|
||||
}
|
||||
if (!array_key_exists($ldap_field, $ldap_user)) {
|
||||
$lowerCaseFieldName = strtolower($ldap_field);
|
||||
if (array_key_exists($lowerCaseFieldName, $ldap_user)) {
|
||||
$ldap_field = $lowerCaseFieldName;
|
||||
}
|
||||
}
|
||||
if (isset($ldap_user[$ldap_field][0])) {
|
||||
$chamilo_user[$chamilo_field] = extldap_purify_string($ldap_user[$ldap_field][0]);
|
||||
} else {
|
||||
if ($debug) {
|
||||
error_log(
|
||||
'EXTLDAP WARNING : '.$ldap_field.'[0] field is not set in ldap array'
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $chamilo_user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Please declare here all the function you use in extldap_user_correspondance
|
||||
* All these functions must have an $ldap_user parameter. This parameter is the
|
||||
* array returned by the ldap for the user.
|
||||
* */
|
||||
function extldap_get_status($ldap_user)
|
||||
{
|
||||
return STUDENT;
|
||||
}
|
||||
|
||||
function extldap_get_admin($ldap_user)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the string used to search a user in ldap.
|
||||
*
|
||||
* @param string username
|
||||
*
|
||||
* @return string the serach string
|
||||
*
|
||||
* @author ndiechburg <noel@cblue.be>
|
||||
* */
|
||||
function extldap_get_user_search_string($username)
|
||||
{
|
||||
global $extldap_config;
|
||||
// init
|
||||
$filter = '('.$extldap_config['user_search'].')';
|
||||
// replacing %username% by the actual username
|
||||
$filter = str_replace('%username%', $username, $filter);
|
||||
// append a global filter if needed
|
||||
if (isset($extldap_config['filter']) && $extldap_config['filter'] != "") {
|
||||
$filter = '(&'.$filter.'('.$extldap_config['filter'].'))';
|
||||
}
|
||||
|
||||
return $filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports all LDAP users into Chamilo.
|
||||
*
|
||||
* @return false|null false on error, true otherwise
|
||||
*/
|
||||
function extldap_import_all_users()
|
||||
{
|
||||
global $extldap_config, $debug;
|
||||
//echo "Connecting...\n";
|
||||
$ds = extldap_connect();
|
||||
if (!$ds) {
|
||||
return false;
|
||||
}
|
||||
//echo "Binding...\n";
|
||||
$ldapbind = false;
|
||||
//Connection as admin to search dn of user
|
||||
if (api_get_configuration_value('ldap_encrypt_admin_password')) {
|
||||
$ldap_pass = api_decrypt_ldap_password($extldap_config['admin_password']);
|
||||
} else {
|
||||
$ldap_pass = $extldap_config['admin_password'];
|
||||
}
|
||||
$ldapbind = @ldap_bind($ds, $extldap_config['admin_dn'], $ldap_pass);
|
||||
if ($ldapbind === false) {
|
||||
if ($debug) {
|
||||
error_log(
|
||||
'EXTLDAP ERROR : cannot connect with admin login/password'
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
//browse ASCII values from a to z to avoid 1000 results limit of LDAP
|
||||
$count = 0;
|
||||
$alphanum = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
||||
for ($a = 97; $a <= 122; $a++) {
|
||||
$alphanum[] = chr($a);
|
||||
}
|
||||
foreach ($alphanum as $char1) {
|
||||
foreach ($alphanum as $char2) {
|
||||
$user_search = $extldap_config['user_search_import_all_users'];
|
||||
//Search distinguish name of user
|
||||
$sr = ldap_search($ds, $extldap_config['base_dn'], $user_search);
|
||||
if (!$sr) {
|
||||
if ($debug) {
|
||||
error_log(
|
||||
'EXTLDAP ERROR : ldap_search('.$ds.', '.$extldap_config['base_dn'].", $user_search) failed"
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
//echo "Getting entries\n";
|
||||
$users = ldap_get_entries($ds, $sr);
|
||||
//echo "Entries: ".$users['count']."\n";
|
||||
for ($key = 0; $key < $users['count']; $key++) {
|
||||
$user_id = extldap_add_user_by_array($users[$key], true);
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
//echo "Found $count users in total\n";
|
||||
@ldap_close($ds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert users from an array of user fields.
|
||||
*/
|
||||
function extldap_add_user_by_array($data, $update_if_exists = true)
|
||||
{
|
||||
global $extldap_user_correspondance;
|
||||
|
||||
$lastname = api_convert_encoding($data[$extldap_user_correspondance['lastname']][0], api_get_system_encoding(), 'UTF-8');
|
||||
$firstname = api_convert_encoding($data[$extldap_user_correspondance['firstname']][0], api_get_system_encoding(), 'UTF-8');
|
||||
$email = $data[$extldap_user_correspondance['email']][0];
|
||||
$username = $data[$extldap_user_correspondance['username']][0];
|
||||
|
||||
// TODO the password, if encrypted at the source, will be encrypted twice, which makes it useless. Try to fix that.
|
||||
$passwordKey = isset($extldap_user_correspondance['password']) ? $extldap_user_correspondance['password'] : 'userPassword';
|
||||
$password = $data[$passwordKey][0];
|
||||
|
||||
// To ease management, we add the step-year (etape-annee) code
|
||||
//$official_code = $etape."-".$annee;
|
||||
$official_code = api_convert_encoding($data[$extldap_user_correspondance['official_code']][0], api_get_system_encoding(), 'UTF-8');
|
||||
$auth_source = 'ldap';
|
||||
|
||||
// No expiration date for students (recover from LDAP's shadow expiry)
|
||||
$expiration_date = '';
|
||||
$active = 1;
|
||||
$status = 5;
|
||||
$phone = '';
|
||||
$picture_uri = '';
|
||||
// Adding user
|
||||
$user_id = 0;
|
||||
if (UserManager::is_username_available($username)) {
|
||||
//echo "$username\n";
|
||||
$user_id = UserManager::create_user(
|
||||
$firstname,
|
||||
$lastname,
|
||||
$status,
|
||||
$email,
|
||||
$username,
|
||||
$password,
|
||||
$official_code,
|
||||
api_get_setting('platformLanguage'),
|
||||
$phone,
|
||||
$picture_uri,
|
||||
$auth_source,
|
||||
$expiration_date,
|
||||
$active
|
||||
);
|
||||
} else {
|
||||
if ($update_if_exists) {
|
||||
$user = api_get_user_info($username);
|
||||
$user_id = $user['user_id'];
|
||||
//echo "$username\n";
|
||||
UserManager::update_user(
|
||||
$user_id,
|
||||
$firstname,
|
||||
$lastname,
|
||||
$username,
|
||||
null,
|
||||
null,
|
||||
$email,
|
||||
$status,
|
||||
$official_code,
|
||||
$phone,
|
||||
$picture_uri,
|
||||
$expiration_date,
|
||||
$active
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $user_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get one user's single attribute value.
|
||||
* User is identified by filter.
|
||||
* $extldap_config['filter'] is also applied in complement, if defined.
|
||||
*
|
||||
* @param $filter string LDAP entry filter, such as '(uid=10000)'
|
||||
* @param $attribute string name of the LDAP attribute to read the value from
|
||||
*
|
||||
* @throws Exception if more than one entries matched or on internal error
|
||||
*
|
||||
* @return string|bool the single matching user entry's single attribute value or false if not found
|
||||
*/
|
||||
function extldapGetUserAttributeValue($filter, $attribute)
|
||||
{
|
||||
global $extldap_config;
|
||||
|
||||
if (array_key_exists('filter', $extldap_config) && !empty($extldap_config['filter'])) {
|
||||
$filter = '(&'.$filter.'('.$extldap_config['filter'].'))';
|
||||
}
|
||||
|
||||
$ldap = extldap_connect();
|
||||
if (false === $ldap) {
|
||||
throw new Exception(get_lang('LDAPConnectFailed'));
|
||||
}
|
||||
|
||||
if (api_get_configuration_value('ldap_encrypt_admin_password')) {
|
||||
$ldap_pass = api_decrypt_ldap_password($extldap_config['admin_password']);
|
||||
} else {
|
||||
$ldap_pass = $extldap_config['admin_password'];
|
||||
}
|
||||
if (false === ldap_bind($ldap, $extldap_config['admin_dn'], $ldap_pass)) {
|
||||
throw new Exception(get_lang('LDAPBindFailed'));
|
||||
}
|
||||
|
||||
$searchResult = ldap_search($ldap, $extldap_config['base_dn'], $filter, [$attribute]);
|
||||
if (false === $searchResult) {
|
||||
throw new Exception(get_lang('LDAPSearchFailed'));
|
||||
}
|
||||
|
||||
switch (ldap_count_entries($ldap, $searchResult)) {
|
||||
case 0:
|
||||
return false;
|
||||
case 1:
|
||||
$entry = ldap_first_entry($ldap, $searchResult);
|
||||
if (false === $entry) {
|
||||
throw new Exception(get_lang('LDAPFirstEntryFailed'));
|
||||
}
|
||||
$values = ldap_get_values($ldap, $entry, $attribute);
|
||||
if (false == $values) {
|
||||
throw new Exception(get_lang('LDAPGetValuesFailed'));
|
||||
}
|
||||
if ($values['count'] == 1) {
|
||||
return $values[0];
|
||||
}
|
||||
throw new Exception(get_lang('MoreThanOneAttributeValueFound'));
|
||||
default:
|
||||
throw new Exception(get_lang('MoreThanOneUserMatched'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the username from the CAS-supplied user identifier.
|
||||
*
|
||||
* searches in attribute $extldap_user_correspondance['extra']['cas_user'] or 'uid' by default
|
||||
* reads value from attribute $extldap_user_correspondance['username'] or 'uid' by default
|
||||
*
|
||||
* @param $casUser string code returned from the CAS server to identify the user
|
||||
*
|
||||
* @throws Exception on error
|
||||
*
|
||||
* @return string|bool user login name, false if not found
|
||||
*/
|
||||
function extldapCasUserLogin($casUser)
|
||||
{
|
||||
global $extldap_user_correspondance;
|
||||
|
||||
// which LDAP attribute is the cas user identifier stored in ?
|
||||
$attributeToFilterOn = 'uid';
|
||||
if (is_array($extldap_user_correspondance) && array_key_exists('extra', $extldap_user_correspondance)) {
|
||||
$extra = $extldap_user_correspondance['extra'];
|
||||
if (is_array($extra) && array_key_exists('cas_user', $extra) && !empty($extra['cas_user'])) {
|
||||
$attributeToFilterOn = $extra['cas_user'];
|
||||
}
|
||||
}
|
||||
|
||||
// which LDAP attribute is the username ?
|
||||
$attributeToRead = 'uid';
|
||||
if (is_array($extldap_user_correspondance)
|
||||
&& array_key_exists('username', $extldap_user_correspondance)
|
||||
&& !empty($extldap_user_correspondance['username'])
|
||||
) {
|
||||
$attributeToRead = $extldap_user_correspondance['username'];
|
||||
}
|
||||
|
||||
// return the value
|
||||
return extldapGetUserAttributeValue("($attributeToFilterOn=$casUser)", $attributeToRead);
|
||||
}
|
||||
22
main/auth/external_login/ldap_import_all_users.php
Normal file
22
main/auth/external_login/ldap_import_all_users.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
/**
|
||||
* This script executes the importation of all users in the LDAP repository
|
||||
* into Chamilo.
|
||||
*
|
||||
* @package chamilo.auth.ldap
|
||||
*/
|
||||
/**
|
||||
* Init.
|
||||
*/
|
||||
if (PHP_SAPI != 'cli') {
|
||||
exit('For security reasons, this script can only be launched from cron or from the command line');
|
||||
}
|
||||
|
||||
require __DIR__.'/../../inc/global.inc.php';
|
||||
require __DIR__.'/ldap.inc.php';
|
||||
require __DIR__.'/../../../app/config/auth.conf.php';
|
||||
/**
|
||||
* Code execution.
|
||||
*/
|
||||
extldap_import_all_users();
|
||||
55
main/auth/external_login/login.azure.php
Normal file
55
main/auth/external_login/login.azure.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
require_once __DIR__.'/functions.inc.php';
|
||||
|
||||
/** @var array $uData */
|
||||
if ($uData['auth_source'] === 'azure') {
|
||||
$plugin = AzureActiveDirectory::create();
|
||||
|
||||
if ('true' !== $plugin->get(AzureActiveDirectory::SETTING_ENABLE)) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$uidField = new ExtraFieldValue('user');
|
||||
$uidValue = $uidField->get_values_by_handler_and_field_variable(
|
||||
$uData['user_id'],
|
||||
AzureActiveDirectory::EXTRA_FIELD_AZURE_UID
|
||||
);
|
||||
|
||||
if (empty($uidValue) || empty($uidValue['value'])) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$azureIdField = new ExtraFieldValue('user');
|
||||
$azureIdValue = $azureIdField->get_values_by_handler_and_field_variable(
|
||||
$uData['user_id'],
|
||||
AzureActiveDirectory::EXTRA_FIELD_AZURE_ID
|
||||
);
|
||||
|
||||
if (empty($azureIdValue) || empty($azureIdValue['value'])) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$organsationEmailField = new ExtraFieldValue('user');
|
||||
$organsationEmailValue = $organsationEmailField->get_values_by_handler_and_field_variable(
|
||||
$uData['user_id'],
|
||||
AzureActiveDirectory::EXTRA_FIELD_ORGANISATION_EMAIL
|
||||
);
|
||||
|
||||
if (empty($organsationEmailValue) || empty($organsationEmailValue['value'])) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$provider = $plugin->getProvider();
|
||||
|
||||
$authUrl = $provider->getAuthorizationUrl(['login_hint' => $organsationEmailValue['value']]);
|
||||
|
||||
ChamiloSession::write('oauth2state', $provider->getState());
|
||||
|
||||
// Redirect to Azure login.
|
||||
header('Location: '.$authUrl);
|
||||
// Avoid execution from here in local.inc.php script.
|
||||
exit;
|
||||
}
|
||||
85
main/auth/external_login/login.ldap.php
Normal file
85
main/auth/external_login/login.ldap.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
use ChamiloSession as Session;
|
||||
|
||||
/**
|
||||
* This file is included in main/inc/local.inc.php at user login if the user have 'extldap' in
|
||||
* his auth_source field instead of platform.
|
||||
*
|
||||
* Variables that can be used :
|
||||
* - $login : string containing the username posted by the user
|
||||
* - $password : string containing the password posted by the user
|
||||
* - $uData : associative array with those keys :
|
||||
* -username
|
||||
* -password
|
||||
* -auth_source
|
||||
* -active
|
||||
* -expiration_date
|
||||
*
|
||||
* If login succeeds, we have 2 choices :
|
||||
* 1. - set $loginFailed to false,
|
||||
* - set $_SESSION['_user']['user_id'] with the Chamilo user_id
|
||||
* - set $uidReset to true
|
||||
* - upgrade user info in chamilo database if needed
|
||||
* - let the script local.inc.php continue
|
||||
*
|
||||
* 2. - set $_SESSION['_user']['user_id'] with the Chamilo user_id
|
||||
* - set $_SESSION['_user']['uidReset'] to true
|
||||
* - upgrade user info in chamilo database if needed
|
||||
* - redirect to any page and let local.inc.php do the magic
|
||||
*
|
||||
* If login fails we have to redirect to index.php with the right message
|
||||
* Possible messages are :
|
||||
* - index.php?loginFailed=1&error=access_url_inactive
|
||||
* - index.php?loginFailed=1&error=account_expired
|
||||
* - index.php?loginFailed=1&error=account_inactive
|
||||
* - index.php?loginFailed=1&error=user_password_incorrect
|
||||
* - index.php?loginFailed=1&error=unrecognize_sso_origin');
|
||||
*/
|
||||
require_once __DIR__.'/ldap.inc.php';
|
||||
require_once __DIR__.'/functions.inc.php';
|
||||
|
||||
$debug = false;
|
||||
if ($debug) {
|
||||
error_log('Entering login.ldap.php');
|
||||
}
|
||||
$ldap_user = extldap_authenticate($login, $password);
|
||||
if ($ldap_user !== false) {
|
||||
if ($debug) {
|
||||
error_log('extldap_authenticate works');
|
||||
}
|
||||
$chamilo_user = extldap_get_chamilo_user($ldap_user);
|
||||
//userid is not on the ldap, we have to use $uData variable from local.inc.php
|
||||
$chamilo_user['user_id'] = $uData['user_id'];
|
||||
if ($debug) {
|
||||
error_log("chamilo_user found user_id: {$uData['user_id']}");
|
||||
}
|
||||
|
||||
//Update user info
|
||||
if (isset($extldap_config['update_userinfo']) && $extldap_config['update_userinfo']) {
|
||||
external_update_user($chamilo_user);
|
||||
if ($debug) {
|
||||
error_log("Calling external_update_user");
|
||||
}
|
||||
}
|
||||
|
||||
$loginFailed = false;
|
||||
$_user['user_id'] = $chamilo_user['user_id'];
|
||||
$_user['status'] = (isset($chamilo_user['status']) ? $chamilo_user['status'] : 5);
|
||||
$_user['uidReset'] = true;
|
||||
Session::write('_user', $_user);
|
||||
$uidReset = true;
|
||||
$logging_in = true;
|
||||
Event::eventLogin($_user['user_id']);
|
||||
} else {
|
||||
if ($debug) {
|
||||
error_log('extldap_authenticate error');
|
||||
}
|
||||
$loginFailed = true;
|
||||
$uidReset = false;
|
||||
if (isset($_user) && isset($_user['user_id'])) {
|
||||
unset($_user['user_id']);
|
||||
}
|
||||
}
|
||||
39
main/auth/external_login/login.oauth2.php
Normal file
39
main/auth/external_login/login.oauth2.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
require_once __DIR__.'/functions.inc.php';
|
||||
|
||||
/** @var array $uData */
|
||||
if ('oauth2' === $uData['auth_source']) {
|
||||
$plugin = OAuth2::create();
|
||||
|
||||
if ('true' !== $plugin->get(OAuth2::SETTING_ENABLE)) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$oauth2IdField = new ExtraFieldValue('user');
|
||||
$oauth2IdValue = $oauth2IdField->get_values_by_handler_and_field_variable(
|
||||
$uData['user_id'],
|
||||
OAuth2::EXTRA_FIELD_OAUTH2_ID
|
||||
);
|
||||
|
||||
if (empty($oauth2IdValue) || empty($oauth2IdValue['value'])) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$provider = $plugin->getProvider();
|
||||
|
||||
// Redirect to OAuth2 login.
|
||||
$authUrl = $provider->getAuthorizationUrl();
|
||||
|
||||
ChamiloSession::write('oauth2state', $provider->getState());
|
||||
|
||||
if (OAuth2::isFirstLoginAfterAuthSource($uData['user_id'])) {
|
||||
ChamiloSession::write('aouth2_authorization_url', $authUrl);
|
||||
$authUrl = api_get_path(WEB_PLUGIN_PATH).'oauth2/redirect_info.php';
|
||||
}
|
||||
|
||||
header('Location: '.$authUrl);
|
||||
// Avoid execution from here in local.inc.php script.
|
||||
exit;
|
||||
}
|
||||
107
main/auth/external_login/login.ws.php
Normal file
107
main/auth/external_login/login.ws.php
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
use ChamiloSession as Session;
|
||||
|
||||
// External login module : WS (for Web Services)
|
||||
/**
|
||||
* This file is included in main/inc/local.inc.php at user login if the user
|
||||
* have 'ws' in his auth_source field instead of 'platform'.
|
||||
*/
|
||||
|
||||
// Configure the web service URL here. e.g. http://174.1.1.19:8020/login.asmx?WSDL
|
||||
$wsUrl = '';
|
||||
|
||||
// include common authentication functions
|
||||
require_once __DIR__.'/functions.inc.php';
|
||||
// call the login checker (defined below)
|
||||
$isValid = loginWSAuthenticate($login, $password, $wsUrl);
|
||||
|
||||
// if the authentication was successful, proceed
|
||||
if ($isValid === 1) {
|
||||
//error_log('WS authentication worked');
|
||||
$chamiloUser = api_get_user_info_from_username($login);
|
||||
$loginFailed = false;
|
||||
$_user['user_id'] = $chamiloUser['user_id'];
|
||||
$_user['status'] = (isset($chamiloUser['status']) ? $chamiloUser['status'] : 5);
|
||||
$_user['uidReset'] = true;
|
||||
Session::write('_user', $_user);
|
||||
$uidReset = true;
|
||||
$logging_in = true;
|
||||
Event::eventLogin($_user['user_id']);
|
||||
} else {
|
||||
//error_log('WS authentication error - user not approved by external WS');
|
||||
$loginFailed = true;
|
||||
$uidReset = false;
|
||||
if (isset($_user) && isset($_user['user_id'])) {
|
||||
unset($_user['user_id']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a user has the right to enter on the platform or not.
|
||||
*
|
||||
* @param string The username, as provided in form
|
||||
* @param string The cleartext password, as provided in form
|
||||
* @param string The WS URL, as provided at the beginning of this script
|
||||
*/
|
||||
function loginWSAuthenticate($username, $password, $wsUrl)
|
||||
{
|
||||
// check params
|
||||
if (empty($username) || empty($password) || empty($wsUrl)) {
|
||||
return false;
|
||||
}
|
||||
// Create new SOAP client instance
|
||||
$client = new SoapClient($wsUrl);
|
||||
if (!$client) {
|
||||
return false;
|
||||
}
|
||||
// Include phpseclib methods, because of a bug with AES/CFB in mcrypt
|
||||
include_once api_get_path(LIBRARY_PATH).'phpseclib/Crypt/AES.php';
|
||||
// Define all elements necessary to the encryption
|
||||
$key = '-+*%$({[]})$%*+-';
|
||||
// Complete password con PKCS7-specific padding
|
||||
$blockSize = 16;
|
||||
$padding = $blockSize - (strlen($password) % $blockSize);
|
||||
$password .= str_repeat(chr($padding), $padding);
|
||||
$cipher = new Crypt_AES(CRYPT_AES_MODE_CFB);
|
||||
$cipher->setKeyLength(128);
|
||||
$cipher->setKey($key);
|
||||
$cipher->setIV($key);
|
||||
|
||||
$cipheredPass = $cipher->encrypt($password);
|
||||
// Mcrypt call left for documentation purposes - broken, see https://bugs.php.net/bug.php?id=51146
|
||||
//$cipheredPass = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $password, MCRYPT_MODE_CFB, $key);
|
||||
|
||||
// Following lines present for debug purposes only
|
||||
/*
|
||||
$arr = preg_split('//', $cipheredPass, -1, PREG_SPLIT_NO_EMPTY);
|
||||
foreach ($arr as $char) {
|
||||
error_log(ord($char));
|
||||
}
|
||||
*/
|
||||
// Change to base64 to avoid communication alteration
|
||||
$passCrypted = base64_encode($cipheredPass);
|
||||
// The call to the webservice will change depending on your definition
|
||||
try {
|
||||
$response = $client->validateUser(
|
||||
[
|
||||
'user' => $username,
|
||||
'pass' => $passCrypted,
|
||||
'system' => 'chamilo',
|
||||
]
|
||||
);
|
||||
} catch (SoapFault $fault) {
|
||||
error_log('Caught something');
|
||||
if ($fault->faultstring != 'Could not connect to host') {
|
||||
error_log('Not a connection problem');
|
||||
throw $fault;
|
||||
} else {
|
||||
error_log('Could not connect to WS host');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $response->validateUserResult;
|
||||
}
|
||||
71
main/auth/external_login/newUser.ldap.php
Normal file
71
main/auth/external_login/newUser.ldap.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
// External login module : LDAP
|
||||
/**
|
||||
* This file is included by main/inc/local.inc.php when extldap is activated, a user try to login
|
||||
* and chamilo does not find his user
|
||||
* Variables that can be used :
|
||||
* - $login : string containing the username posted by the user
|
||||
* - $password : string containing the password posted by the user.
|
||||
*
|
||||
* Please configure the exldap module in main/auth/external_login/ldap.conf.php
|
||||
*
|
||||
* If login succeeds, we have to add the user in the chamilo database and then
|
||||
* we have 2 choices :
|
||||
* 1. - set $loginFailed to false,
|
||||
* - set $_SESSION['_user']['user_id'] with the dokeos user_id
|
||||
* - set $uidReset to true
|
||||
* - let the script local.inc.php continue
|
||||
*
|
||||
* 2. - set $_SESSION['_user']['user_id'] with the dokeos user_id
|
||||
* - set $_SESSION['_user']['uidReset'] to true
|
||||
* - upgrade user info in dokeos database if needeed
|
||||
* - redirect to any page and let local.inc.php do the magic
|
||||
*
|
||||
* If login fails we have also 2 choices :
|
||||
* 1. - unset $_user['user_id']
|
||||
* - set $loginFailed=true
|
||||
* - set $uidReset = false
|
||||
* User wil then have the user password incorrect message
|
||||
*
|
||||
* 2. We redirect the user to index.php with appropriate message :
|
||||
* Possible messages are :
|
||||
* - index.php?loginFailed=1&error=access_url_inactive
|
||||
* - index.php?loginFailed=1&error=account_expired
|
||||
* - index.php?loginFailed=1&error=account_inactive
|
||||
* - index.php?loginFailed=1&error=user_password_incorrect
|
||||
* - index.php?loginFailed=1&error=unrecognize_sso_origin');
|
||||
* */
|
||||
use ChamiloSession as Session;
|
||||
|
||||
require_once __DIR__.'/ldap.inc.php';
|
||||
require_once __DIR__.'/functions.inc.php';
|
||||
|
||||
$ldap_user = extldap_authenticate($login, $password);
|
||||
if ($ldap_user !== false) {
|
||||
$chamilo_user = extldap_get_chamilo_user($ldap_user);
|
||||
//username is not on the ldap, we have to use $login variable
|
||||
$chamilo_user['username'] = $login;
|
||||
$chamilo_uid = external_add_user($chamilo_user);
|
||||
$chamiloUser = api_get_user_entity($chamilo_uid);
|
||||
|
||||
if ($chamiloUser) {
|
||||
$loginFailed = false;
|
||||
$_user['user_id'] = $chamiloUser->getId();
|
||||
$_user['status'] = $chamiloUser->getStatus();
|
||||
$_user['uidReset'] = true;
|
||||
Session::write('_user', $_user);
|
||||
$uidReset = true;
|
||||
// Is user admin?
|
||||
if ($chamilo_user['admin'] === true) {
|
||||
$is_platformAdmin = true;
|
||||
Database::query("INSERT INTO admin values ('{$chamiloUser->getId()}')");
|
||||
}
|
||||
Event::eventLogin($chamiloUser->getId());
|
||||
|
||||
MessageManager::sendNotificationOfNewRegisteredUser($chamiloUser);
|
||||
}
|
||||
} else {
|
||||
$loginFailed = true;
|
||||
$uidReset = false;
|
||||
}
|
||||
54
main/auth/external_login/newUser.php
Normal file
54
main/auth/external_login/newUser.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/*
|
||||
Template to automatically create a new user with information from anywhere.
|
||||
This file is loaded by main/inc/local.inc.php
|
||||
To use it please add this line to main/inc/conf/configuration.php :
|
||||
$extAuthSource["external_logininfo"]["newUser"] = $_configuration['root_sys']."main/auth/external_logininfo/newUser.php";
|
||||
|
||||
You also have to implements the external_get_user_info function in functions.inc.php
|
||||
*/
|
||||
|
||||
use ChamiloSession as Session;
|
||||
|
||||
require_once __DIR__.'/functions.inc.php';
|
||||
|
||||
//MAIN CODE
|
||||
//$login and $password variables are setted in main/inc/local.inc.php
|
||||
|
||||
if ($password != DEFAULT_PASSWORD) {
|
||||
$user = false;
|
||||
} else {
|
||||
$user = external_get_user_info($login, $password);
|
||||
}
|
||||
|
||||
if ($user !== false && ($chamilo_uid = external_add_user($user)) !== false) {
|
||||
//log in the user
|
||||
$loginFailed = false;
|
||||
$_user['user_id'] = $chamilo_uid;
|
||||
$_user['uidReset'] = true;
|
||||
Session::write('_user', $_user);
|
||||
$uidReset = true;
|
||||
|
||||
//Autosubscribe to courses
|
||||
if (!empty($user['courses'])) {
|
||||
$autoSubscribe = explode('|', $user['courses']);
|
||||
foreach ($autoSubscribe as $code) {
|
||||
if (CourseManager::course_exists($code)) {
|
||||
CourseManager::subscribeUser($_user['user_id'], $code);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Is User Admin ?
|
||||
if ($user['admin']) {
|
||||
$is_platformAdmin = true;
|
||||
Database::query("INSERT INTO admin values ('$chamilo_uid')");
|
||||
}
|
||||
// Can user create course
|
||||
$is_allowedCreateCourse = (bool) (($user['status'] == COURSEMANAGER) or (api_get_setting('drhCourseManagerRights') and $user['status'] == SESSIONADMIN));
|
||||
|
||||
Event::eventLogin($chamilo_uid);
|
||||
} else {
|
||||
$loginFailed = true;
|
||||
unset($_user['user_id']);
|
||||
$uidReset = false;
|
||||
}
|
||||
41
main/auth/external_login/updateUser.php
Normal file
41
main/auth/external_login/updateUser.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
//Script loaded by local.inc.php providing update user information of type external_logininfo.
|
||||
/*
|
||||
This script must not exit.
|
||||
*/
|
||||
|
||||
use ChamiloSession as Session;
|
||||
|
||||
require_once __DIR__.'/functions.inc.php';
|
||||
|
||||
//MAIN CODE
|
||||
//$uData variable is set in local.inc.php
|
||||
$user = api_get_user_info($uData['user_id']);
|
||||
$new_user = external_get_user_info($login);
|
||||
$user['firstname'] = $new_user['firstname'];
|
||||
$user['lastname'] = $new_user['lastname'];
|
||||
$user['status'] = $new_user['status'];
|
||||
$user['admin'] = $new_user['admin'];
|
||||
$user['email'] = $new_user['email'];
|
||||
$user['username'] = $new_user['username'];
|
||||
$user['profile_link'] = $new_user['profile_link'];
|
||||
$user['worldwide_bu'] = $new_user['worldwide_bu'];
|
||||
$user['manager'] = $new_user['manager'];
|
||||
$user['country_bu'] = $new_user['country_bu'];
|
||||
$user['extra'] = $new_user['extra'];
|
||||
|
||||
if ($new_user !== false) { //User can login
|
||||
external_update_user($user);
|
||||
$loginFailed = false;
|
||||
$_user['user_id'] = $user['user_id'];
|
||||
$_user['uidReset'] = true;
|
||||
$uidReset = true;
|
||||
Session::write('_user', $_user);
|
||||
} else {
|
||||
//User cannot login
|
||||
$loginFailed = true;
|
||||
Session::erase('_uid');
|
||||
header('Location: '.api_get_path(WEB_PATH).'index.php?loginFailed=1&error=user_password_incorrect');
|
||||
exit;
|
||||
}
|
||||
76
main/auth/gotocourse.php
Normal file
76
main/auth/gotocourse.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
/**
|
||||
* Allow the user to login to a course after reaching a course URL
|
||||
* (e.g. http://chamilo.chamilo.org/courses/MYCOURSE/?id_session=0 )
|
||||
* See https://support.chamilo.org/issues/6768.
|
||||
*
|
||||
* Author : hubert.borderiou@grenet.fr
|
||||
*/
|
||||
require_once __DIR__.'/../inc/global.inc.php';
|
||||
$msg = null;
|
||||
if (isset($_GET['firstpage'])) {
|
||||
$firstpage = $_GET['firstpage'];
|
||||
|
||||
// if course is public, go to course without auth
|
||||
$tab_course_info = api_get_course_info($firstpage);
|
||||
|
||||
api_set_firstpage_parameter($firstpage);
|
||||
|
||||
$tpl = new Template(null, 1, 1);
|
||||
|
||||
$action = api_get_self().'?'.Security::remove_XSS($_SERVER['QUERY_STRING']);
|
||||
$action = str_replace('&', '&', $action);
|
||||
$form = new FormValidator('formLogin', 'post', $action, null, ['class' => 'form-stacked']);
|
||||
$params = [
|
||||
'placeholder' => get_lang('UserName'),
|
||||
];
|
||||
// Avoid showing the autocapitalize option if the browser doesn't
|
||||
// support it: this attribute is against the HTML5 standard
|
||||
if (api_browser_support('autocapitalize')) {
|
||||
$params['autocapitalize'] = 'none';
|
||||
}
|
||||
$form->addElement(
|
||||
'text',
|
||||
'login',
|
||||
null,
|
||||
$params
|
||||
);
|
||||
$params = [
|
||||
'placeholder' => get_lang('Password'),
|
||||
];
|
||||
if (api_browser_support('autocapitalize')) {
|
||||
$params['autocapitalize'] = 'none';
|
||||
}
|
||||
$form->addElement(
|
||||
'password',
|
||||
'password',
|
||||
null,
|
||||
$params
|
||||
);
|
||||
$form->addButtonNext(get_lang('LoginEnter'), 'submitAuth');
|
||||
// see same text in main_api.lib.php function api_not_allowed
|
||||
if (api_is_cas_activated()) {
|
||||
$msg .= Display::return_message(sprintf(get_lang('YouHaveAnInstitutionalAccount'), api_get_setting("Institution")), '', false);
|
||||
$msg .= Display::div(Template::displayCASLoginButton(), ['align' => 'center']);
|
||||
$msg .= Display::return_message(get_lang('YouDontHaveAnInstitutionAccount'));
|
||||
$msg .= "<p style='text-align:center'><a href='#' onclick='$(this).parent().next().toggle()'>".get_lang('LoginWithExternalAccount')."</a></p>";
|
||||
$msg .= "<div style='display:none;'>";
|
||||
}
|
||||
|
||||
$msg .= '<div class="well_login">';
|
||||
$msg .= $form->returnForm();
|
||||
$msg .= '</div>';
|
||||
if (api_is_cas_activated()) {
|
||||
$msg .= "</div>";
|
||||
}
|
||||
$msg .= '<hr/><p style="text-align:center"><a href="'.api_get_path(WEB_PATH).'">'.get_lang('ReturnToCourseHomepage').'</a></p>';
|
||||
|
||||
$tpl->assign('content', '<h4>'.get_lang('LoginToGoToThisCourse').'</h4>'.$msg);
|
||||
$tpl->display_one_col_template();
|
||||
} else {
|
||||
api_delete_firstpage_parameter();
|
||||
header('Location: '.api_get_path(WEB_PATH).'index.php');
|
||||
exit;
|
||||
}
|
||||
104
main/auth/hmac/login.php
Normal file
104
main/auth/hmac/login.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
use ChamiloSession as Session;
|
||||
|
||||
/**
|
||||
* This file contains the necessary elements to allow a Single Sign On
|
||||
* based on a validation of a hmac computed hash.
|
||||
*
|
||||
* To allow the SSO access /main/auth/hmac/login.php must receive as
|
||||
* query string parameters the following parameters:
|
||||
*
|
||||
* 'email': user email.
|
||||
*
|
||||
* 'time': time of the request, as HH:mm.
|
||||
*
|
||||
* 'system': System name, a control value.
|
||||
*
|
||||
* 'Token': a HMAC computed SHA256 algorithm based on the concatenation of
|
||||
* the 'time' and 'email' value.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* https://campus.chamilo/main/auth/hmac/login.php?email=user@domain.com&time=10:48&system=SystemName&Token=XYZ
|
||||
*
|
||||
* Also a settings.php file must be configured the set the following values:
|
||||
*
|
||||
* 'secret': secret key used to generate a HMAC computed hash to validate the
|
||||
* received 'Token' parameter on the query string.
|
||||
*
|
||||
* 'secret': secret key used to generate a HMAC computed hash to validate the 'Token' parameter on the query string.
|
||||
*
|
||||
* 'expiration_time': integer value, maximum time in minutes of the request lifetime.
|
||||
*/
|
||||
require_once '../../../main/inc/global.inc.php';
|
||||
|
||||
// Create a settings.dist.php
|
||||
if (file_exists('settings.php')) {
|
||||
require_once 'settings.php';
|
||||
} else {
|
||||
$message = '';
|
||||
if (api_is_platform_admin()) {
|
||||
$message = 'Create a settings.php';
|
||||
}
|
||||
api_not_allowed(true, $message);
|
||||
}
|
||||
|
||||
// Check if we have all the parameters from the query string
|
||||
if (isset($_GET['email']) && isset($_GET['time']) && isset($_GET['system']) && isset($_GET['Token'])) {
|
||||
$email = $_GET['email'];
|
||||
$time = $_GET['time'];
|
||||
$system = $_GET['system'];
|
||||
$token = $_GET['Token'];
|
||||
|
||||
// Generate the token
|
||||
$validToken = hash_hmac('sha256', $time.$email, $settingsInfo['secret'], false);
|
||||
|
||||
// Compare the received token & the valid token
|
||||
if ($token !== $validToken) {
|
||||
Display::addFlash(Display::return_message('Incorrect token', 'error'));
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit;
|
||||
}
|
||||
|
||||
// Check the system is correct
|
||||
if ($settingsInfo['system'] !== $system) {
|
||||
Display::addFlash(Display::return_message('Incorrect client', 'error'));
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit;
|
||||
}
|
||||
|
||||
// Check if the request expired with a diff between the query string parameter & the actual time
|
||||
if ($settingsInfo['expiration_time'] && $settingsInfo['expiration_time'] > 0) {
|
||||
$tokenTime = strtotime($time);
|
||||
$diff = abs($tokenTime - time()) / 60;
|
||||
if ($diff > $settingsInfo['expiration_time']) {
|
||||
Display::addFlash(Display::return_message('Token expired', 'error'));
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the user info
|
||||
$userInfo = api_get_user_info_from_email($email);
|
||||
|
||||
// Log-in user if exists or a show error message
|
||||
if (!empty($userInfo)) {
|
||||
Session::write('_user', $userInfo);
|
||||
Session::write('is_platformAdmin', false);
|
||||
Session::write('is_allowedCreateCourse', false);
|
||||
Event::eventLogin($userInfo['user_id']);
|
||||
Session::write('flash_messages', '');
|
||||
} else {
|
||||
Display::addFlash(Display::return_message(get_lang('UserNotFound'), 'error'));
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit;
|
||||
}
|
||||
|
||||
header('Location: '.api_get_path(WEB_PATH).'user_portal.php');
|
||||
exit;
|
||||
} else {
|
||||
Display::addFlash(Display::return_message('Invalid request', 'error'));
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit;
|
||||
}
|
||||
7
main/auth/hmac/settings.dist.php
Normal file
7
main/auth/hmac/settings.dist.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
$settingsInfo = [
|
||||
'secret' => '',
|
||||
'system' => '',
|
||||
'expiration_time' => 0,
|
||||
];
|
||||
48
main/auth/hrm_courses.php
Normal file
48
main/auth/hrm_courses.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
require_once __DIR__.'/../inc/global.inc.php';
|
||||
|
||||
api_block_anonymous_users();
|
||||
|
||||
$isHrm = api_is_drh();
|
||||
|
||||
if (!$isHrm) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$hrm = api_get_user_entity(api_get_user_id());
|
||||
$assignedUsers = UserManager::get_users_followed_by_drh($hrm->getId());
|
||||
$users = [];
|
||||
|
||||
$courseController = new IndexManager('');
|
||||
|
||||
foreach ($assignedUsers as $assignedUserId => $assignedUserInfo) {
|
||||
$assignedUser = api_get_user_entity($assignedUserId);
|
||||
|
||||
if (!$assignedUser) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$userInfo = [
|
||||
'username' => $assignedUser->getUsername(),
|
||||
'complete_name' => UserManager::formatUserFullName($assignedUser),
|
||||
'picture_url' => UserManager::getUserPicture($assignedUserId),
|
||||
'course_list' => $courseController->returnCoursesAndSessions($assignedUserId)['html'],
|
||||
];
|
||||
|
||||
$users[$assignedUser->getId()] = $userInfo;
|
||||
}
|
||||
|
||||
$toolName = get_lang('HrmAssignedUsersCourseList');
|
||||
|
||||
$view = new Template($toolName);
|
||||
$view->assign('users', $users);
|
||||
|
||||
$content = $view->fetch(
|
||||
$view->get_template('auth/hrm_courses.tpl')
|
||||
);
|
||||
|
||||
$view->assign('header', $toolName);
|
||||
$view->assign('content', $content);
|
||||
$view->display_one_col_template();
|
||||
7
main/auth/index.html
Normal file
7
main/auth/index.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; url=courses.php">
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
1103
main/auth/inscription.php
Normal file
1103
main/auth/inscription.php
Normal file
File diff suppressed because it is too large
Load Diff
230
main/auth/justification.php
Normal file
230
main/auth/justification.php
Normal file
@@ -0,0 +1,230 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
$cidReset = true;
|
||||
require_once __DIR__.'/../inc/global.inc.php';
|
||||
|
||||
api_block_anonymous_users(true);
|
||||
|
||||
$allowJustification = api_get_plugin_setting('justification', 'tool_enable') === 'true';
|
||||
|
||||
if (!$allowJustification) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$user_data = api_get_user_info(api_get_user_id());
|
||||
|
||||
$justification = '';
|
||||
$plugin = Justification::create();
|
||||
$fields = $plugin->getList();
|
||||
$formValidator = new FormValidator('justification');
|
||||
$formValidator->addHeader($plugin->get_lang('Justification'));
|
||||
foreach ($fields as $field) {
|
||||
$formValidator->addHtml('<a name="'.$field['code'].'"></a>');
|
||||
$formValidator->addFile($field['code'].'_file', [$field['name'], $field['comment']]);
|
||||
if ($field['date_manual_on']) {
|
||||
$formValidator->addDatePicker($field['code'].'_date', $plugin->get_lang('ValidityDate'));
|
||||
}
|
||||
$formValidator->addHtml('<hr>');
|
||||
}
|
||||
|
||||
$formValidator->addButtonSend(get_lang('Send'));
|
||||
if ($formValidator->validate() && isset($_FILES)) {
|
||||
foreach ($fields as $field) {
|
||||
$fieldId = $field['id'];
|
||||
|
||||
$days = $field['validity_duration'];
|
||||
if (isset($_FILES[$field['code'].'_file']) && !empty($_FILES[$field['code'].'_file']['tmp_name'])) {
|
||||
$file = $_FILES[$field['code'].'_file'];
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
$date = isset($_REQUEST[$field['code'].'_date']) ? $_REQUEST[$field['code'].'_date'].' 13:00:00' : api_get_local_time();
|
||||
|
||||
$startDate = api_get_utc_datetime($date, false, true);
|
||||
|
||||
$interval = new \DateInterval('P'.$days.'D');
|
||||
$startDate->add($interval);
|
||||
$finalDate = $startDate->format('Y-m-d');
|
||||
|
||||
$file['name'] = api_replace_dangerous_char($file['name']);
|
||||
$fileName = $file['name'];
|
||||
|
||||
$params = [
|
||||
'file_path' => $fileName,
|
||||
'user_id' => api_get_user_id(),
|
||||
'date_validity' => $finalDate,
|
||||
'justification_document_id' => $fieldId,
|
||||
];
|
||||
$id = Database::insert('justification_document_rel_users', $params);
|
||||
|
||||
if ($id) {
|
||||
api_upload_file('justification', $file, $id);
|
||||
Display::addFlash(Display::return_message($plugin->get_lang('JustificationSaved')));
|
||||
}
|
||||
}
|
||||
|
||||
header('Location: '.api_get_self());
|
||||
exit;
|
||||
}
|
||||
|
||||
$userJustifications = $plugin->getUserJustificationList(api_get_user_id());
|
||||
|
||||
if (!empty($userJustifications)) {
|
||||
if (count($fields) <= count($userJustifications) && $_REQUEST['a'] != 'notification_sent') {
|
||||
$formValidator->addHtml('<label class="col-sm-2 control-label"></label><a class="btn btn-primary" href="'.api_get_self().'?a=notify_justification" >'.$plugin->get_lang('SendNotificationToAllAdmins').'</a>');
|
||||
}
|
||||
}
|
||||
|
||||
$userJustificationList = '';
|
||||
$action = isset($_REQUEST['a']) ? $_REQUEST['a'] : '';
|
||||
|
||||
$justificationContent = '';
|
||||
switch ($action) {
|
||||
case 'notify_justification':
|
||||
$link = api_get_path(WEB_PATH).'plugin/justification/justification_by_user.php?user_id='.api_get_user_id();
|
||||
$notificationEmailSubject = $plugin->get_lang('JustificationsCompleted').': '.$userInfo['complete_name'];
|
||||
$notificationEmailContent = $notificationEmailSubject.' <br /><br />'.'<a href="'.$link.'">'.$link.'</a>';
|
||||
if (api_get_plugin_setting('justification', 'notification_to_creator_only') === 'true') {
|
||||
$sql = "select creator_id from user where user_id = ".api_get_user_id();
|
||||
$result = Database::query($sql);
|
||||
if (Database::num_rows($result) > 0) {
|
||||
$row = Database::fetch_array($result);
|
||||
$sendToAllAdmins = false;
|
||||
MessageManager::send_message_simple(
|
||||
$row['creator_id'],
|
||||
$notificationEmailSubject,
|
||||
$notificationEmailContent,
|
||||
api_get_user_id());
|
||||
}
|
||||
}
|
||||
if ($sendToAllAdmins) {
|
||||
// get_all_administrators
|
||||
$adminList = UserManager::get_all_administrators();
|
||||
foreach ($adminList as $adminId => $data) {
|
||||
MessageManager::send_message_simple(
|
||||
$adminId,
|
||||
$notificationEmailSubject,
|
||||
$notificationEmailContent,
|
||||
api_get_user_id());
|
||||
}
|
||||
}
|
||||
Display::addFlash(Display::return_message(get_lang('MessageSent')));
|
||||
header('Location: '.api_get_self().'?a=notification_sent');
|
||||
exit;
|
||||
break;
|
||||
case 'edit_justification':
|
||||
$justificationId = isset($_REQUEST['justification_id']) ? (int) $_REQUEST['justification_id'] : '';
|
||||
$userJustification = $plugin->getUserJustification($justificationId);
|
||||
$justification = $plugin->getJustification($userJustification['justification_document_id']);
|
||||
if ($justification['date_manual_on'] == 0) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
$formEdit = new FormValidator('edit', 'post', api_get_self().'?a=edit_justification&justification_id='.$justificationId);
|
||||
$formEdit->addHeader($justification['name']);
|
||||
$element = $formEdit->addDatePicker('date_validity', $plugin->get_lang('ValidityDate'));
|
||||
$element->setValue($userJustification['date_validity']);
|
||||
$formEdit->addButtonUpdate(get_lang('Update'));
|
||||
$formEdit->setDefaults($userJustification);
|
||||
$justificationContent = $formEdit->returnForm();
|
||||
if ($formEdit->validate()) {
|
||||
$values = $formEdit->getSubmitValues();
|
||||
$date = Database::escape_string($values['date_validity']);
|
||||
$sql = "UPDATE justification_document_rel_users SET date_validity = '$date'
|
||||
WHERE id = $justificationId AND user_id = ".$user_data['id'];
|
||||
Database::query($sql);
|
||||
Display::addFlash(Display::return_message(get_lang('Updated')));
|
||||
header('Location: '.api_get_self());
|
||||
exit;
|
||||
}
|
||||
break;
|
||||
case 'delete_justification':
|
||||
$justificationId = isset($_REQUEST['justification_id']) ? (int) $_REQUEST['justification_id'] : '';
|
||||
$userJustification = $plugin->getUserJustification($justificationId);
|
||||
if ($userJustification && $userJustification['user_id'] == api_get_user_id()) {
|
||||
api_remove_uploaded_file_by_id('justification', $justificationId, $userJustification['file_path']);
|
||||
$sql = "DELETE FROM justification_document_rel_users
|
||||
WHERE id = $justificationId AND user_id = ".$user_data['id'];
|
||||
Database::query($sql);
|
||||
Display::addFlash(Display::return_message(get_lang('Deleted')));
|
||||
}
|
||||
|
||||
header('Location: '.api_get_self());
|
||||
exit;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!empty($userJustifications)) {
|
||||
$userJustificationList .= Display::page_subheader3($plugin->get_lang('MyJustifications'));
|
||||
$table = new HTML_Table(['class' => 'table table-hover table-striped data_table']);
|
||||
$column = 0;
|
||||
$row = 0;
|
||||
$headers = [
|
||||
get_lang('Name'),
|
||||
get_lang('File'),
|
||||
$plugin->get_lang('ValidityDate'),
|
||||
get_lang('Actions'),
|
||||
];
|
||||
foreach ($headers as $header) {
|
||||
$table->setHeaderContents($row, $column, $header);
|
||||
$column++;
|
||||
}
|
||||
$row = 1;
|
||||
foreach ($userJustifications as $userJustification) {
|
||||
$justification = $plugin->getJustification($userJustification['justification_document_id']);
|
||||
$url = api_get_uploaded_web_url('justification', $userJustification['id'], $userJustification['file_path']);
|
||||
$link = Display::url($userJustification['file_path'], $url);
|
||||
$col = 0;
|
||||
$table->setCellContents($row, $col++, $justification['name']);
|
||||
$table->setCellContents($row, $col++, $link);
|
||||
$date = $userJustification['date_validity'];
|
||||
if ($userJustification['date_validity'] < api_get_local_time()) {
|
||||
$date = Display::label($userJustification['date_validity'], 'warning');
|
||||
}
|
||||
$table->setCellContents($row, $col++, $date);
|
||||
$actions = '';
|
||||
|
||||
if ($justification['date_manual_on'] == 1) {
|
||||
$actions .= Display::url(get_lang('Edit'), api_get_self().'?a=edit_justification&justification_id='.$userJustification['id'], ['class' => 'btn btn-primary']);
|
||||
}
|
||||
$actions .= ' '.Display::url(get_lang('Delete'), api_get_self().'?a=delete_justification&justification_id='.$userJustification['id'], ['class' => 'btn btn-danger']);
|
||||
$table->setCellContents($row, $col++, $actions);
|
||||
$code = $justification['code'];
|
||||
$htmlHeadXtra[] = '<script type="text/javascript" >$(function(){$("#file_'.$code.'_file label").css("color","green");});</script>';
|
||||
$row++;
|
||||
}
|
||||
|
||||
$userJustificationList .= $justificationContent.$table->toHtml();
|
||||
}
|
||||
|
||||
$htmlHeadXtra[] = '<script type="text/javascript" >
|
||||
$(function(){
|
||||
$("#justification label").each(function(){
|
||||
var colorG = $(this).css("color");
|
||||
var lgtxt = $(this).text().replace(/ /g,"").length;
|
||||
if (colorG!="green"&&colorG!="rgb(0, 128, 0)"&&lgtxt>3) {
|
||||
$(this).append("<img src=\"'.api_get_path(WEB_PATH).'main/img/icons/22/warning.png\" />");
|
||||
}
|
||||
});
|
||||
});</script>';
|
||||
|
||||
$tabs = SocialManager::getHomeProfileTabs('justification');
|
||||
$justification = $tabs.$formValidator->returnForm().$userJustificationList;
|
||||
|
||||
$tpl = new Template(get_lang('ModifyProfile'));
|
||||
|
||||
SocialManager::setSocialUserBlock($tpl, api_get_user_id(), 'home');
|
||||
$menu = SocialManager::show_social_menu(
|
||||
'home',
|
||||
null,
|
||||
api_get_user_id(),
|
||||
false,
|
||||
false
|
||||
);
|
||||
|
||||
$tpl->assign('social_menu_block', $menu);
|
||||
$tpl->assign('social_right_content', $justification);
|
||||
$social_layout = $tpl->get_template('social/edit_profile.tpl');
|
||||
|
||||
$tpl->display($social_layout);
|
||||
8
main/auth/key/index.php
Normal file
8
main/auth/key/index.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* Display nothing. This ensure Apache doesn't display the list of files and folders
|
||||
* when it is not propertly configured.
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
268
main/auth/key/key_auth.class.php
Normal file
268
main/auth/key/key_auth.class.php
Normal file
@@ -0,0 +1,268 @@
|
||||
<?php
|
||||
|
||||
use ChamiloSession as Session;
|
||||
|
||||
/**
|
||||
* Used to authenticate user with an access token. By default this method is disabled.
|
||||
* Method used primarily to make API calls: Rss, file upload.
|
||||
*
|
||||
* Access is granted only for the services that are enabled.
|
||||
*
|
||||
* To be secured this method must
|
||||
*
|
||||
* 1) be called through httpS to avoid sniffing (note that this is the case anyway with other methods such as cookies)
|
||||
* 2) the url/access token must be secured
|
||||
*
|
||||
* This authentication method is session less. This is to ensure that the navigator
|
||||
* do not receive an access cookie that will grant it access to other parts of the
|
||||
* application.
|
||||
*
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* Enable KeyAuth for a specific service. Add the following lines so that
|
||||
* the key authentication method is enabled for a specific service before
|
||||
* calling global.inc.php.
|
||||
*
|
||||
* include_once '.../main/inc/autoload.inc.php';
|
||||
* KeyAuth::enable_services('my_service');
|
||||
* include_once '.../main/inc/global.inc.php';
|
||||
*
|
||||
*
|
||||
* Enable url access for a short period of time:
|
||||
*
|
||||
* token = KeyAuth::create_temp_token();
|
||||
* url = '...?access_token=' . $token ;
|
||||
*
|
||||
* @see AccessToken
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info> for the Univesity of Geneva
|
||||
*/
|
||||
class KeyAuth
|
||||
{
|
||||
public const PARAM_ACCESS_TOKEN = 'access_token';
|
||||
|
||||
protected static $services = [];
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public static function create_temp_token($service = null, $duration = 60, $user_id = null)
|
||||
{
|
||||
return UserApiKeyManager::create_temp_token($service, $duration, $user_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns enabled services.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_services()
|
||||
{
|
||||
return self::$services;
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the service for which we are goint to check the API Key.
|
||||
* If empty it disables authentication.
|
||||
*
|
||||
* !! 10 chars max !!
|
||||
*
|
||||
* @param string $_
|
||||
*/
|
||||
public static function enable_services($_)
|
||||
{
|
||||
$args = func_get_args();
|
||||
$names = [];
|
||||
foreach ($args as $arg) {
|
||||
if (is_object($arg)) {
|
||||
$f = [$arg, 'get_service_name'];
|
||||
$name = call_user_func($f);
|
||||
} else {
|
||||
$name = $arg;
|
||||
}
|
||||
$name = substr($name, 0, 10);
|
||||
self::$services[$name] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
public static function disable_services($_)
|
||||
{
|
||||
$args = func_get_args();
|
||||
$names = [];
|
||||
foreach ($args as $name) {
|
||||
$name = substr($name, 0, 10);
|
||||
unset(self::$services[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
public static function is_service_enabled($service)
|
||||
{
|
||||
$services = self::get_services();
|
||||
foreach ($services as $s) {
|
||||
if ($s == $service) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function clear_services()
|
||||
{
|
||||
self::$services[$name] = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable key authentication for the default service - i.e. chamilo.
|
||||
*/
|
||||
public static function enable()
|
||||
{
|
||||
self::enable_services(UserApiKeyManager::default_service());
|
||||
}
|
||||
|
||||
public static function disable()
|
||||
{
|
||||
self::$services[$name] = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the key authentication method is enabled. False otherwise.
|
||||
* Default to false.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_enabled()
|
||||
{
|
||||
return !empty(self::$services);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return KeyAuth
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
static $result = null;
|
||||
if (empty($result)) {
|
||||
$result = new self();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if authentication accepts to run otherwise returns false.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function accept()
|
||||
{
|
||||
/**
|
||||
* Authentication method must be enabled.
|
||||
*/
|
||||
if (!self::is_enabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$token = $this->get_access_token();
|
||||
if ($token->is_empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$key = UserApiKeyManager::get_by_id($token->get_id());
|
||||
if (empty($key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The service corresponding to the key must be enabled.
|
||||
*/
|
||||
$service = $key['api_service'];
|
||||
if (!self::is_service_enabled($service)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* User associated with the key must be active.
|
||||
*/
|
||||
$user = api_get_user_info($token->get_user_id());
|
||||
if (empty($user)) {
|
||||
return false;
|
||||
}
|
||||
if (!$user['active']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Token must be valid.
|
||||
*/
|
||||
return $token->is_valid();
|
||||
}
|
||||
|
||||
/**
|
||||
* If accepted tear down session, log in user and returns true.
|
||||
* If not accepted do nothing and returns false.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function login()
|
||||
{
|
||||
if (!$this->accept()) {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* ! important this is to ensure we don't grant access for other parts.
|
||||
*/
|
||||
Session::destroy();
|
||||
|
||||
/**
|
||||
* We don't allow redirection since access is granted only for this call.
|
||||
*/
|
||||
global $no_redirection, $noredirection;
|
||||
$no_redirection = true;
|
||||
$noredirection = true;
|
||||
Session::write('noredirection', $noredirection);
|
||||
|
||||
$user_id = $this->get_user_id();
|
||||
$course_code = $this->get_course_code();
|
||||
$group_id = $this->get_group_id();
|
||||
|
||||
Login::init_user($user_id, true);
|
||||
Login::init_course($course_code, true);
|
||||
Login::init_group($group_id, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request access token.
|
||||
*
|
||||
* @return AccessToken
|
||||
*/
|
||||
public function get_access_token()
|
||||
{
|
||||
$string = Request::get(self::PARAM_ACCESS_TOKEN);
|
||||
|
||||
return AccessToken::parse($string);
|
||||
}
|
||||
|
||||
public function get_user_id()
|
||||
{
|
||||
return $this->get_access_token()->get_user_id();
|
||||
}
|
||||
|
||||
public function get_course_code()
|
||||
{
|
||||
return Request::get('cidReq', 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function get_group_id()
|
||||
{
|
||||
return Request::get('gidReq', 0);
|
||||
}
|
||||
}
|
||||
745
main/auth/ldap/authldap.php
Normal file
745
main/auth/ldap/authldap.php
Normal file
@@ -0,0 +1,745 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
/**
|
||||
* LDAP module functions.
|
||||
*
|
||||
* If the application uses LDAP, these functions are used
|
||||
* for logging in, searching user info, adding this info
|
||||
* to the Chamilo database...
|
||||
- function ldap_authentication_check()
|
||||
- function ldap_find_user_info()
|
||||
- function ldap_login()
|
||||
- function ldap_put_user_info_locally()
|
||||
- ldap_set_version()
|
||||
|
||||
known bugs
|
||||
----------
|
||||
- (fixed 18 june 2003) code has been internationalized
|
||||
- (fixed 07/05/2003) fixed some non-relative urls or includes
|
||||
- (fixed 28/04/2003) we now use global config.inc variables instead of local ones
|
||||
- (fixed 22/04/2003) the last name of a user was restricted to the first part
|
||||
- (fixed 11/04/2003) the user was never registered as a course manager
|
||||
|
||||
version history
|
||||
---------------
|
||||
This historial has been discontinued. Please use the Mercurial logs for more
|
||||
3.2 - updated to allow for specific term search for teachers identification
|
||||
3.1 - updated code to use database settings, to respect coding conventions
|
||||
* as much as possible (camel-case removed) and to allow for non-anonymous login
|
||||
- Patrick Cool: fixing security hole
|
||||
|
||||
* @author Roan Embrechts
|
||||
*
|
||||
* @version 3.0
|
||||
*
|
||||
* @package chamilo.auth.ldap
|
||||
* Note:
|
||||
* If you are using a firewall, you might need to check port 389 is open in
|
||||
* order for Chamilo to communicate with the LDAP server.
|
||||
* See http://support.chamilo.org/issues/4675 for details.
|
||||
*/
|
||||
/**
|
||||
* Inclusions.
|
||||
*/
|
||||
use ChamiloSession as Session;
|
||||
|
||||
/**
|
||||
* Code.
|
||||
*/
|
||||
require_once api_get_path(SYS_CODE_PATH).'auth/external_login/ldap.inc.php';
|
||||
require 'ldap_var.inc.php';
|
||||
/**
|
||||
* Check login and password with LDAP.
|
||||
*
|
||||
* @return bool when login & password both OK, false otherwise
|
||||
*
|
||||
* @author Roan Embrechts (based on code from Universit<69> Jean Monet)
|
||||
*/
|
||||
function ldap_login($login, $password)
|
||||
{
|
||||
//error_log('Entering ldap_login('.$login.','.$password.')',0);
|
||||
$res = ldap_authentication_check($login, $password);
|
||||
|
||||
// res=-1 -> the user does not exist in the ldap database
|
||||
// res=1 -> invalid password (user does exist)
|
||||
|
||||
if ($res == 1) { //WRONG PASSWORD
|
||||
//$errorMessage = "LDAP User or password incorrect, try again.<br />";
|
||||
if (isset($log)) {
|
||||
unset($log);
|
||||
}
|
||||
if (isset($uid)) {
|
||||
unset($uid);
|
||||
}
|
||||
$loginLdapSucces = false;
|
||||
}
|
||||
if ($res == -1) { //WRONG USERNAME
|
||||
//$errorMessage = "LDAP User or password incorrect, try again.<br />";
|
||||
$login_ldap_success = false;
|
||||
}
|
||||
if ($res == 0) { //LOGIN & PASSWORD OK - SUCCES
|
||||
//$errorMessage = "Successful login w/ LDAP.<br>";
|
||||
$login_ldap_success = true;
|
||||
}
|
||||
|
||||
//$result = "This is the result: $errorMessage";
|
||||
$result = $login_ldap_success;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find user info in LDAP.
|
||||
*
|
||||
* @return array Array with indexes: "firstname", "name", "email", "employeenumber"
|
||||
*
|
||||
* @author Stefan De Wannemacker
|
||||
* @author Roan Embrechts
|
||||
*/
|
||||
function ldap_find_user_info($login)
|
||||
{
|
||||
//error_log('Entering ldap_find_user_info('.$login.')',0);
|
||||
global $ldap_host, $ldap_port, $ldap_basedn, $ldap_rdn, $ldap_pass, $ldap_search_dn;
|
||||
// basic sequence with LDAP is connect, bind, search,
|
||||
// interpret search result, close connection
|
||||
|
||||
//echo "Connecting ...";
|
||||
$ldap_connect = ldap_connect($ldap_host, $ldap_port);
|
||||
ldap_set_version($ldap_connect);
|
||||
if ($ldap_connect) {
|
||||
//echo " Connect to LDAP server successful ";
|
||||
//echo "Binding ...";
|
||||
$ldap_bind = false;
|
||||
$ldap_bind_res = ldap_handle_bind($ldap_connect, $ldap_bind);
|
||||
if ($ldap_bind_res) {
|
||||
//echo " LDAP bind successful... ";
|
||||
//echo " Searching for uid... ";
|
||||
// Search surname entry
|
||||
//OLD: $sr=ldap_search($ldapconnect,"dc=rug, dc=ac, dc=be", "uid=$login");
|
||||
//echo "<p> ldapDc = '$LDAPbasedn' </p>";
|
||||
if (!empty($ldap_search_dn)) {
|
||||
$sr = ldap_search($ldap_connect, $ldap_search_dn, "uid=$login");
|
||||
} else {
|
||||
$sr = ldap_search($ldap_connect, $ldap_basedn, "uid=$login");
|
||||
}
|
||||
//echo " Search result is ".$sr;
|
||||
//echo " Number of entries returned is ".ldap_count_entries($ldapconnect,$sr);
|
||||
//echo " Getting entries ...";
|
||||
$info = ldap_get_entries($ldap_connect, $sr);
|
||||
//echo "Data for ".$info["count"]." items returned:<p>";
|
||||
} // else could echo "LDAP bind failed...";
|
||||
//echo "Closing LDAP connection<hr>";
|
||||
ldap_close($ldap_connect);
|
||||
} // else could echo "<h3>Unable to connect to LDAP server</h3>";
|
||||
//DEBUG: $result["firstname"] = "Jan"; $result["name"] = "De Test"; $result["email"] = "email@ugent.be";
|
||||
$result["firstname"] = $info[0]["cn"][0];
|
||||
$result["name"] = $info[0]["sn"][0];
|
||||
$result["email"] = $info[0]["mail"][0];
|
||||
$tutor_field = api_get_setting('ldap_filled_tutor_field');
|
||||
$result[$tutor_field] = $info[0][$tutor_field]; //employeenumber by default
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function uses the data from ldap_find_user_info()
|
||||
* to add the userdata to Chamilo
|
||||
* "firstname", "name", "email", "isEmployee".
|
||||
*
|
||||
* @author Roan Embrechts
|
||||
*/
|
||||
function ldap_put_user_info_locally($login, $info_array)
|
||||
{
|
||||
//error_log('Entering ldap_put_user_info_locally('.$login.',info_array)',0);
|
||||
global $ldap_pass_placeholder;
|
||||
global $submitRegistration, $submit, $uname, $email,
|
||||
$nom, $prenom, $password, $password1, $status;
|
||||
global $platformLanguage;
|
||||
global $loginFailed, $uidReset, $_user;
|
||||
|
||||
/*----------------------------------------------------------
|
||||
1. set the necessary variables
|
||||
------------------------------------------------------------ */
|
||||
$uname = $login;
|
||||
$email = $info_array["email"];
|
||||
$nom = $info_array["name"];
|
||||
$prenom = $info_array["firstname"];
|
||||
$password = $ldap_pass_placeholder;
|
||||
$password1 = $ldap_pass_placeholder;
|
||||
$official_code = '';
|
||||
|
||||
define("STUDENT", 5);
|
||||
define("COURSEMANAGER", 1);
|
||||
|
||||
$tutor_field = api_get_setting('ldap_filled_tutor_field');
|
||||
$tutor_value = api_get_setting('ldap_filled_tutor_field_value');
|
||||
if (empty($tutor_field)) {
|
||||
$status = STUDENT;
|
||||
} else {
|
||||
if (empty($tutor_value)) {
|
||||
//in this case, we are assuming that the admin didn't give a criteria
|
||||
// so that if the field is not empty, it is a tutor
|
||||
if (!empty($info_array[$tutor_field])) {
|
||||
$status = COURSEMANAGER;
|
||||
} else {
|
||||
$status = STUDENT;
|
||||
}
|
||||
} else {
|
||||
//the tutor_value is filled, so we need to check the contents of the LDAP field
|
||||
if (is_array($info_array[$tutor_field]) && in_array($tutor_value, $info_array[$tutor_field])) {
|
||||
$status = COURSEMANAGER;
|
||||
} else {
|
||||
$status = STUDENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
//$official_code = xxx; //example: choose an attribute
|
||||
|
||||
/*----------------------------------------------------------
|
||||
2. add info to Chamilo
|
||||
------------------------------------------------------------ */
|
||||
|
||||
$language = api_get_setting('platformLanguage');
|
||||
if (empty($language)) {
|
||||
$language = 'english';
|
||||
}
|
||||
$_userId = UserManager::create_user(
|
||||
$prenom,
|
||||
$nom,
|
||||
$status,
|
||||
$email,
|
||||
$uname,
|
||||
$password,
|
||||
$official_code,
|
||||
$language,
|
||||
'',
|
||||
'',
|
||||
'ldap'
|
||||
);
|
||||
|
||||
//echo "new user added to Chamilo, id = $_userId";
|
||||
|
||||
//user_id, username, password, auth_source
|
||||
|
||||
/*----------------------------------------------------------
|
||||
3. register session
|
||||
------------------------------------------------------------ */
|
||||
|
||||
$uData['user_id'] = $_userId;
|
||||
$uData['username'] = $uname;
|
||||
$uData['auth_source'] = "ldap";
|
||||
|
||||
$loginFailed = false;
|
||||
$uidReset = true;
|
||||
$_user['user_id'] = $uData['user_id'];
|
||||
Session::write('_uid', $_user['user_id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* The code of UGent uses these functions to authenticate.
|
||||
* function AuthVerifEnseignant ($uname, $passwd)
|
||||
* function AuthVerifEtudiant ($uname, $passwd)
|
||||
* function Authentif ($uname, $passwd).
|
||||
*
|
||||
* @todo translate the comments and code to english
|
||||
* @todo let these functions use the variables in config.inc instead of ldap_var.inc
|
||||
*/
|
||||
/**
|
||||
* Checks the existence of a member in LDAP.
|
||||
*
|
||||
* @param string username input on keyboard
|
||||
* @param string password given by user
|
||||
*
|
||||
* @return int 0 if authentication succeeded, 1 if password was incorrect, -1 if it didn't belong to LDAP
|
||||
*/
|
||||
function ldap_authentication_check($uname, $passwd)
|
||||
{
|
||||
//error_log('Entering ldap_authentication_check('.$uname.','.$passwd.')',0);
|
||||
global $ldap_host, $ldap_port, $ldap_basedn, $ldap_host2, $ldap_port2, $ldap_rdn, $ldap_pass;
|
||||
//error_log('Entering ldap_authentication_check('.$uname.','.$passwd.')',0);
|
||||
// Establish anonymous connection with LDAP server
|
||||
// Etablissement de la connexion anonyme avec le serveur LDAP
|
||||
$ds = ldap_connect($ldap_host, $ldap_port);
|
||||
ldap_set_version($ds);
|
||||
|
||||
$test_bind = false;
|
||||
$test_bind_res = ldap_handle_bind($ds, $test_bind);
|
||||
//if problem, use the replica
|
||||
if ($test_bind_res === false) {
|
||||
$ds = ldap_connect($ldap_host2, $ldap_port2);
|
||||
ldap_set_version($ds);
|
||||
} // else: error_log('Connected to server '.$ldap_host);
|
||||
if ($ds !== false) {
|
||||
//Creation of filter containing values input by the user
|
||||
// Here it might be necessary to use $filter="(samaccountName=$uname)"; - see http://support.chamilo.org/issues/4675
|
||||
$filter = "(uid=$uname)";
|
||||
// Open anonymous LDAP connection
|
||||
$result = false;
|
||||
$ldap_bind_res = ldap_handle_bind($ds, $result);
|
||||
// Executing the search with the $filter parametr
|
||||
//error_log('Searching for '.$filter.' on LDAP server',0);
|
||||
$sr = ldap_search($ds, $ldap_basedn, $filter);
|
||||
$info = ldap_get_entries($ds, $sr);
|
||||
$dn = ($info[0]["dn"]);
|
||||
// debug !! echo"<br> dn = $dn<br> pass = $passwd<br>";
|
||||
// closing 1st connection
|
||||
ldap_close($ds);
|
||||
}
|
||||
|
||||
// test the Distinguish Name from the 1st connection
|
||||
if ($dn == "") {
|
||||
return -1; // doesn't belong to the addressbook
|
||||
}
|
||||
//bug ldap.. if password empty, return 1!
|
||||
if ($passwd == "") {
|
||||
return 1;
|
||||
}
|
||||
// Opening 2nd LDAP connection : Connection user for password check
|
||||
$ds = ldap_connect($ldap_host, $ldap_port);
|
||||
ldap_set_version($ds);
|
||||
if (!$test_bind) {
|
||||
$ds = ldap_connect($ldap_host2, $ldap_port2);
|
||||
ldap_set_version($ds);
|
||||
}
|
||||
// return in case of wrong password connection error
|
||||
if (@ldap_bind($ds, $dn, $passwd) === false) {
|
||||
return 1; // invalid password
|
||||
} else {// connection successfull
|
||||
return 0;
|
||||
}
|
||||
} // end of check
|
||||
/**
|
||||
* Set the protocol version with version from config file (enables LDAP version 3).
|
||||
*
|
||||
* @param resource resource LDAP connexion resource, passed by reference
|
||||
*/
|
||||
function ldap_set_version(&$resource)
|
||||
{
|
||||
//error_log('Entering ldap_set_version(&$resource)',0);
|
||||
global $ldap_version;
|
||||
if ($ldap_version > 2) {
|
||||
ldap_set_option($resource, LDAP_OPT_PROTOCOL_VERSION, 3);
|
||||
//ok - don't do anything
|
||||
//failure - should switch back to version 2 by default
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Handle bind (whether authenticated or not).
|
||||
*
|
||||
* @param resource The LDAP handler to which we are connecting (by reference)
|
||||
* @param resource The LDAP bind handler we will be modifying
|
||||
* @param bool $ldap_bind
|
||||
*
|
||||
* @return bool Status of the bind assignment. True for success, false for failure.
|
||||
*/
|
||||
function ldap_handle_bind(&$ldap_handler, &$ldap_bind)
|
||||
{
|
||||
//error_log('Entering ldap_handle_bind(&$ldap_handler,&$ldap_bind)',0);
|
||||
global $ldap_rdn, $ldap_pass, $extldap_config;
|
||||
$ldap_rdn = $extldap_config['admin_dn'];
|
||||
$ldap_pass = $extldap_config['admin_password'];
|
||||
if (api_get_configuration_value('ldap_encrypt_admin_password')) {
|
||||
$ldap_pass = api_decrypt_ldap_password($extldap_config['admin_password']);
|
||||
}
|
||||
if (!empty($ldap_rdn) and !empty($ldap_pass)) {
|
||||
//error_log('Trying authenticated login :'.$ldap_rdn.'/'.$ldap_pass,0);
|
||||
$ldap_bind = ldap_bind($ldap_handler, $ldap_rdn, $ldap_pass);
|
||||
if (!$ldap_bind) {
|
||||
//error_log('Authenticated login failed',0);
|
||||
//try in anonymous mode, you never know...
|
||||
$ldap_bind = ldap_bind($ldap_handler);
|
||||
}
|
||||
} else {
|
||||
// this is an "anonymous" bind, typically read-only access:
|
||||
$ldap_bind = ldap_bind($ldap_handler);
|
||||
}
|
||||
if (!$ldap_bind) {
|
||||
return false;
|
||||
} else {
|
||||
//error_log('Login finally OK',0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get the total number of users on the platform.
|
||||
*
|
||||
* @see SortableTable#get_total_number_of_items()
|
||||
*
|
||||
* @author Mustapha Alouani
|
||||
*/
|
||||
function ldap_get_users()
|
||||
{
|
||||
global $ldap_basedn, $ldap_host, $ldap_port, $ldap_rdn, $ldap_pass, $ldap_search_dn, $extldap_user_correspondance;
|
||||
|
||||
$keyword_firstname = isset($_GET['keyword_firstname']) ? trim(Database::escape_string($_GET['keyword_firstname'])) : '';
|
||||
$keyword_lastname = isset($_GET['keyword_lastname']) ? trim(Database::escape_string($_GET['keyword_lastname'])) : '';
|
||||
$keyword_username = isset($_GET['keyword_username']) ? trim(Database::escape_string($_GET['keyword_username'])) : '';
|
||||
$keyword_type = isset($_GET['keyword_type']) ? Database::escape_string($_GET['keyword_type']) : '';
|
||||
|
||||
$ldap_query = [];
|
||||
|
||||
if ($keyword_username != "") {
|
||||
$ldap_query[] = str_replace('%username%', $keyword_username, $ldap_search_dn);
|
||||
} else {
|
||||
if ($keyword_lastname != "") {
|
||||
$ldap_query[] = "(".$extldap_user_correspondance['lastname']."=".$keyword_lastname."*)";
|
||||
}
|
||||
if ($keyword_firstname != "") {
|
||||
$ldap_query[] = "(".$extldap_user_correspondance['firstname']."=".$keyword_firstname."*)";
|
||||
}
|
||||
}
|
||||
if ($keyword_type != "" && $keyword_type != "all") {
|
||||
$ldap_query[] = "(employeeType=".$keyword_type.")";
|
||||
}
|
||||
|
||||
if (count($ldap_query) > 1) {
|
||||
$str_query = "(& ";
|
||||
foreach ($ldap_query as $query) {
|
||||
$str_query .= " $query";
|
||||
}
|
||||
$str_query .= " )";
|
||||
} else {
|
||||
$str_query = count($ldap_query) > 0 ? $ldap_query[0] : null;
|
||||
}
|
||||
|
||||
$ds = ldap_connect($ldap_host, $ldap_port);
|
||||
ldap_set_version($ds);
|
||||
if ($ds && count($ldap_query) > 0) {
|
||||
$r = false;
|
||||
$res = ldap_handle_bind($ds, $r);
|
||||
//$sr = ldap_search($ds, "ou=test-ou,$ldap_basedn", $str_query);
|
||||
$sr = ldap_search($ds, $ldap_basedn, $str_query);
|
||||
//echo "Le nombre de resultats est : ".ldap_count_entries($ds,$sr)."<p>";
|
||||
$info = ldap_get_entries($ds, $sr);
|
||||
|
||||
return $info;
|
||||
} else {
|
||||
if (count($ldap_query) != 0) {
|
||||
echo Display::return_message(get_lang('LDAPConnectionError'), 'error');
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total number of users on the platform.
|
||||
*
|
||||
* @see SortableTable#get_total_number_of_items()
|
||||
*
|
||||
* @author Mustapha Alouani
|
||||
*/
|
||||
function ldap_get_number_of_users()
|
||||
{
|
||||
$info = ldap_get_users();
|
||||
if (count($info) > 0) {
|
||||
return $info['count'];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the users to display on the current page.
|
||||
*
|
||||
* @see SortableTable#get_table_data($from)
|
||||
*
|
||||
* @author Mustapha Alouani
|
||||
*/
|
||||
function ldap_get_user_data($from, $number_of_items, $column, $direction)
|
||||
{
|
||||
global $extldap_user_correspondance;
|
||||
|
||||
$users = [];
|
||||
$is_western_name_order = api_is_western_name_order();
|
||||
if (isset($_GET['submit'])) {
|
||||
$info = ldap_get_users();
|
||||
if ($info['count'] > 0) {
|
||||
for ($key = 0; $key < $info["count"]; $key++) {
|
||||
$user = [];
|
||||
// Get uid from dn
|
||||
//YW: this might be a variation between LDAP 2 and LDAP 3, but in LDAP 3, the uid is in
|
||||
//the corresponding index of the array
|
||||
//$dn_array=ldap_explode_dn($info[$key]["dn"],1);
|
||||
//$user[] = $dn_array[0]; // uid is first key
|
||||
//$user[] = $dn_array[0]; // uid is first key
|
||||
$user[] = $info[$key][$extldap_user_correspondance['username']][0];
|
||||
$user[] = $info[$key][$extldap_user_correspondance['username']][0];
|
||||
if ($is_western_name_order) {
|
||||
$user[] = api_convert_encoding($info[$key][$extldap_user_correspondance['firstname']][0], api_get_system_encoding(), 'UTF-8');
|
||||
$user[] = api_convert_encoding($info[$key][$extldap_user_correspondance['lastname']][0], api_get_system_encoding(), 'UTF-8');
|
||||
} else {
|
||||
$user[] = api_convert_encoding($info[$key][$extldap_user_correspondance['firstname']][0], api_get_system_encoding(), 'UTF-8');
|
||||
$user[] = api_convert_encoding($info[$key][$extldap_user_correspondance['lastname']][0], api_get_system_encoding(), 'UTF-8');
|
||||
}
|
||||
$user[] = $info[$key]['mail'][0];
|
||||
$user[] = $info[$key][$extldap_user_correspondance['username']][0];
|
||||
$users[] = $user;
|
||||
}
|
||||
} else {
|
||||
echo Display::return_message(get_lang('NoUser'), 'error');
|
||||
}
|
||||
}
|
||||
|
||||
return $users;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the modify-column of the table.
|
||||
*
|
||||
* @param int $user_id The user id
|
||||
* @param string $url_params
|
||||
*
|
||||
* @return string Some HTML-code with modify-buttons
|
||||
*
|
||||
* @author Mustapha Alouani
|
||||
*/
|
||||
function modify_filter($user_id, $url_params, $row)
|
||||
{
|
||||
$query_string = "id[]=".$row[0];
|
||||
if (!empty($_GET['id_session'])) {
|
||||
$query_string .= '&id_session='.Security::remove_XSS($_GET['id_session']);
|
||||
}
|
||||
$icon = '';
|
||||
if (UserManager::is_username_available($user_id)) {
|
||||
$icon = 'invitation_friend.png';
|
||||
} else {
|
||||
$icon = 'reload.png';
|
||||
}
|
||||
//$url_params_id="id=".$row[0];
|
||||
$result = '<a href="ldap_users_list.php?action=add_user&user_id='.$user_id.'&'.$query_string.'&sec_token='.Security::getTokenFromSession().'" onclick="javascript:if(!confirm('."'".addslashes(api_htmlentities(get_lang("ConfirmYourChoice"), ENT_QUOTES, api_get_system_encoding()))."'".')) return false;">'.Display::return_icon($icon, get_lang('AddUsers')).'</a>';
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a user to the Chamilo database or updates its data.
|
||||
*
|
||||
* @param string username (and uid inside LDAP)
|
||||
*
|
||||
* @author Mustapha Alouani
|
||||
*/
|
||||
function ldap_add_user($login)
|
||||
{
|
||||
if ($ldap_user = extldap_authenticate($login, 'nopass', true)) {
|
||||
return extldap_add_user_by_array($ldap_user);
|
||||
}
|
||||
}
|
||||
|
||||
function ldap_add_user_by_array($data, $update_if_exists = true)
|
||||
{
|
||||
$lastname = api_convert_encoding($data['sn'][0], api_get_system_encoding(), 'UTF-8');
|
||||
$firstname = api_convert_encoding($data['cn'][0], api_get_system_encoding(), 'UTF-8');
|
||||
$email = $data['mail'][0];
|
||||
// Get uid from dn
|
||||
$dn_array = ldap_explode_dn($data['dn'], 1);
|
||||
$username = $dn_array[0]; // uid is first key
|
||||
$outab[] = $data['edupersonprimaryaffiliation'][0]; // Here, "student"
|
||||
//$val = ldap_get_values_len($ds, $entry, "userPassword");
|
||||
//$val = ldap_get_values_len($ds, $data, "userPassword");
|
||||
//$password = $val[0];
|
||||
// TODO the password, if encrypted at the source, will be encrypted twice, which makes it useless. Try to fix that.
|
||||
$password = $data['userPassword'][0];
|
||||
$structure = $data['edupersonprimaryorgunitdn'][0];
|
||||
$array_structure = explode(",", $structure);
|
||||
$array_val = explode("=", $array_structure[0]);
|
||||
$etape = $array_val[1];
|
||||
$array_val = explode("=", $array_structure[1]);
|
||||
$annee = $array_val[1];
|
||||
// To ease management, we add the step-year (etape-annee) code
|
||||
$official_code = $etape."-".$annee;
|
||||
$auth_source = 'ldap';
|
||||
// No expiration date for students (recover from LDAP's shadow expiry)
|
||||
$expiration_date = '';
|
||||
$active = 1;
|
||||
if (empty($status)) {
|
||||
$status = 5;
|
||||
}
|
||||
if (empty($phone)) {
|
||||
$phone = '';
|
||||
}
|
||||
if (empty($picture_uri)) {
|
||||
$picture_uri = '';
|
||||
}
|
||||
// Adding user
|
||||
$user_id = 0;
|
||||
if (UserManager::is_username_available($username)) {
|
||||
$user_id = UserManager::create_user(
|
||||
$firstname,
|
||||
$lastname,
|
||||
$status,
|
||||
$email,
|
||||
$username,
|
||||
$password,
|
||||
$official_code,
|
||||
api_get_setting('platformLanguage'),
|
||||
$phone,
|
||||
$picture_uri,
|
||||
$auth_source,
|
||||
$expiration_date,
|
||||
$active
|
||||
);
|
||||
} else {
|
||||
if ($update_if_exists) {
|
||||
$user = api_get_user_info($username);
|
||||
$user_id = $user['user_id'];
|
||||
UserManager::update_user(
|
||||
$user_id,
|
||||
$firstname,
|
||||
$lastname,
|
||||
$username,
|
||||
null,
|
||||
null,
|
||||
$email,
|
||||
$status,
|
||||
$official_code,
|
||||
$phone,
|
||||
$picture_uri,
|
||||
$expiration_date,
|
||||
$active
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $user_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a list of users to one session.
|
||||
*
|
||||
* @param array Array of user ids
|
||||
* @param string Course code
|
||||
*/
|
||||
function ldap_add_user_to_session($UserList, $id_session)
|
||||
{
|
||||
// Database Table Definitions
|
||||
$tbl_session_rel_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
|
||||
|
||||
$id_session = (int) $id_session;
|
||||
// Once users are imported in the users base, we can assign them to the session
|
||||
$result = Database::query("SELECT c_id FROM $tbl_session_rel_course WHERE session_id ='$id_session'");
|
||||
$CourseList = [];
|
||||
while ($row = Database::fetch_array($result)) {
|
||||
$CourseList[] = $row['c_id'];
|
||||
}
|
||||
|
||||
SessionManager::insertUsersInCourses($UserList, $CourseList, $id_session);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize users from the configured LDAP connection (in auth.conf.php). If
|
||||
* configured to disable old users,.
|
||||
*
|
||||
* @param bool $disableOldUsers Whether to disable users who have disappeared from LDAP (true) or just leave them be (default: false)
|
||||
* @param bool $deleteStudents Go one step further and delete completely students missing from LDAP
|
||||
* @param bool $deleteTeachers Go even one step further and also delete completely teachers missing from LDAP
|
||||
*
|
||||
* @return int Total number of users added (not counting possible removals)
|
||||
*/
|
||||
function syncro_users(
|
||||
$disableOldUsers = false,
|
||||
$deleteStudents = false,
|
||||
$deleteTeachers = false
|
||||
) {
|
||||
global $ldap_basedn, $ldap_host, $ldap_port, $ldap_rdn, $ldap_pass, $ldap_search_dn, $debug;
|
||||
$i = 0;
|
||||
if ($debug) {
|
||||
error_log('Connecting... ('.__FUNCTION__.')');
|
||||
}
|
||||
$ldapConnect = ldap_connect($ldap_host, $ldap_port);
|
||||
ldap_set_version($ldapConnect);
|
||||
if ($ldapConnect) {
|
||||
if ($debug) {
|
||||
error_log('Connected to LDAP server successfully! Binding... ('.__FUNCTION__.')');
|
||||
}
|
||||
$ldapBind = false;
|
||||
$ldapBindRes = ldap_handle_bind($ldapConnect, $ldapBind);
|
||||
if ($ldapBindRes) {
|
||||
if ($debug) {
|
||||
error_log('Bind successful! Searching for uid in LDAP DC: '.$ldap_search_dn);
|
||||
}
|
||||
$allUserQuery = "uid=*";
|
||||
if (!empty($ldap_search_dn)) {
|
||||
$sr = ldap_search($ldapConnect, $ldap_search_dn, $allUserQuery);
|
||||
} else {
|
||||
//OLD: $sr=ldap_search($ldapconnect,"dc=rug, dc=ac, dc=be", "uid=$login");
|
||||
$sr = ldap_search($ldapConnect, $ldap_basedn, $allUserQuery);
|
||||
}
|
||||
if ($debug) {
|
||||
error_log('Entries returned: '.ldap_count_entries($ldapConnect, $sr));
|
||||
}
|
||||
$info = ldap_get_entries($ldapConnect, $sr);
|
||||
for ($key = 0; $key < $info['count']; $key++) {
|
||||
$user_id = ldap_add_user_by_array($info[$key], false);
|
||||
if ($user_id) {
|
||||
if ($debug) {
|
||||
error_log('User #'.$user_id.' created from LDAP');
|
||||
}
|
||||
$i++;
|
||||
} else {
|
||||
if ($debug) {
|
||||
error_log('User '.$info[$key]['sn'][0].' ('.$info[$key]['mail'][0].') could not be created');
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($disableOldUsers === true) {
|
||||
if ($debug) {
|
||||
error_log('Disable mode selected in '.__FUNCTION__);
|
||||
if ($deleteStudents) {
|
||||
error_log('...with complete deletion of users if disabled');
|
||||
}
|
||||
}
|
||||
// Get a big array of all user IDs, usernames only if they are
|
||||
// registered as auth_source = 'ldap'
|
||||
// This array will take about 60 bytes per user in memory, so
|
||||
// having 100K users should only take a few (6?) MB and will
|
||||
// highly reduce the number of DB queries
|
||||
$usersDBShortList = [];
|
||||
$usersLDAPShortList = [];
|
||||
$sql = "SELECT id, username, status FROM user WHERE auth_source = 'ldap' ORDER BY username";
|
||||
$res = Database::query($sql);
|
||||
if ($res !== false) {
|
||||
// First build a list of users present in LDAP
|
||||
for ($key = 0; $key < $info['count']; $key++) {
|
||||
$dn_array = ldap_explode_dn($info[$key]['dn'], 1);
|
||||
$usersLDAPShortList[$dn_array[0]] = 1;
|
||||
}
|
||||
// Go through all 'extldap' users. For any that cannot
|
||||
// be found in the LDAP list, disable
|
||||
while ($row = Database::fetch_assoc($res)) {
|
||||
$usersDBShortList[$row['username']] = $row['id'];
|
||||
// If any of those users is NOT in LDAP, disable or remove
|
||||
if (empty($usersLDAPShortList[$row['username']])) {
|
||||
if ($deleteStudents === true && $row['status'] == 5) {
|
||||
UserManager::delete_user($usersDBShortList[$row['username']]);
|
||||
if ($debug) {
|
||||
error_log('Student '.$row['username'].' removed from Chamilo');
|
||||
}
|
||||
} elseif ($deleteTeachers === true && $row['status'] == 1) {
|
||||
UserManager::delete_user($usersDBShortList[$row['username']]);
|
||||
if ($debug) {
|
||||
error_log('Teacher '.$row['username'].' removed from Chamilo');
|
||||
}
|
||||
} else {
|
||||
UserManager::disable($usersDBShortList[$row['username']]);
|
||||
if ($debug) {
|
||||
error_log('User '.$row['username'].' disabled in Chamilo');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($debug) {
|
||||
error_log('Data for '.$info['count'].' items processed');
|
||||
}
|
||||
//echo "Data for ".$info["count"]." items returned:<p>";
|
||||
} else {
|
||||
error_log('Could not bind to LDAP server');
|
||||
}
|
||||
ldap_close($ldapConnect);
|
||||
} else {
|
||||
error_log('Could not connect to LDAP server');
|
||||
}
|
||||
error_log('Ended execution of function '.__FUNCTION__);
|
||||
}
|
||||
6
main/auth/ldap/index.html
Normal file
6
main/auth/ldap/index.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
49
main/auth/ldap/ldap_var.inc.php
Normal file
49
main/auth/ldap/ldap_var.inc.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
/**
|
||||
* LDAP settings
|
||||
* In the older code, there was a distinction between
|
||||
* the teacher and student LDAP server. Later I decided not
|
||||
* to make this distinction. However, it could be built in
|
||||
* in the future but then perhaps in a more general way.
|
||||
*
|
||||
* Originally, Thomas and I agreed to store all settings in one file
|
||||
* (configuration.php) to make it easier for claroline admins to make changes.
|
||||
* Since October 2003, this changed: the include directory has been
|
||||
* changed to be called "inc", and all tools should have their own file(s).
|
||||
*
|
||||
* This file "ldap_var.inc.php" was already used by the
|
||||
* older french authentification functions. I have moved the new
|
||||
* variables from the configuration.php to here as well.
|
||||
*
|
||||
* @author Roan Embrechts
|
||||
*
|
||||
* @package chamilo.auth.ldap
|
||||
*/
|
||||
/**
|
||||
* Configuration settings.
|
||||
*/
|
||||
// your ldap server
|
||||
$ldap_host = $extldap_config['host'][0];
|
||||
// your ldap server's port number
|
||||
$ldap_port = @$extldap_config['port'] ?: null;
|
||||
//domain
|
||||
$ldap_basedn = $extldap_config['base_dn'];
|
||||
|
||||
//search term for students
|
||||
$ldap_search_dn = $extldap_config['user_search'];
|
||||
|
||||
//additional server params for use of replica in case of problems
|
||||
$ldap_host2 = count($extldap_config['host']) > 1 ? $extldap_config['host'][1] : null;
|
||||
$ldap_port2 = $extldap_config['port'];
|
||||
|
||||
//protocol version - set to 3 for LDAP 3
|
||||
$ldap_version = $extldap_config['protocol_version'];
|
||||
|
||||
//non-anonymous LDAP mode
|
||||
$ldap_rdn = $extldap_config['admin_dn'];
|
||||
$ldap_pass = $extldap_config['admin_password'];
|
||||
if (api_get_configuration_value('ldap_encrypt_admin_password')) {
|
||||
$ldap_pass = api_decrypt_ldap_password($extldap_config['admin_password']);
|
||||
}
|
||||
$ldap_pass_placeholder = "PLACEHOLDER";
|
||||
44
main/auth/ldap/login.php
Normal file
44
main/auth/ldap/login.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
use ChamiloSession as Session;
|
||||
|
||||
/**
|
||||
* Users trying to login, who already exist in the Chamilo database
|
||||
* and have ldap as authentication type get verified here.
|
||||
*
|
||||
* @author Roan Embrechts
|
||||
*
|
||||
* @package chamilo.auth.ldap
|
||||
*/
|
||||
/**
|
||||
* An external authentification module needs to set
|
||||
* - $loginFailed
|
||||
* - $uidReset
|
||||
* - $_user['user_id']
|
||||
* - register the $_user['user_id'] in the session.
|
||||
*
|
||||
* As the LDAP code shows, this is not as difficult as you might think.
|
||||
* LDAP authentification module
|
||||
* this calls the loginWithLdap function
|
||||
* from the LDAP library, and sets a few
|
||||
* variables based on the result.
|
||||
*/
|
||||
|
||||
//require_once('../../inc/global.inc.php'); - this script should be loaded by the /index.php script anyway, so global is already loaded
|
||||
|
||||
require_once 'authldap.php';
|
||||
$loginLdapSucces = ldap_login($login, $password);
|
||||
|
||||
if ($loginLdapSucces) {
|
||||
$loginFailed = false;
|
||||
$uidReset = true;
|
||||
$_user['user_id'] = $uData['user_id'];
|
||||
Session::write('_uid', $_uid);
|
||||
// Jand: copied from event_login in events.lib.php to enable login statistics:
|
||||
Event::eventLogin($uData['user_id']);
|
||||
} else {
|
||||
$loginFailed = true;
|
||||
unset($_user['user_id']);
|
||||
$uidReset = false;
|
||||
}
|
||||
36
main/auth/ldap/newUser.php
Normal file
36
main/auth/ldap/newUser.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
/**
|
||||
* Users trying to login, who do not yet exist in the Chamilo database,
|
||||
* can be added by this script which tries to retrieve ldap information
|
||||
* about them.
|
||||
*
|
||||
* @author Roan Embrechts
|
||||
*
|
||||
* @package chamilo.auth.ldap
|
||||
*/
|
||||
/**
|
||||
* when a user does not exist yet in dokeos,
|
||||
* but he or she does exist in the LDAP,
|
||||
* we add him to the dokeos database.
|
||||
*/
|
||||
//require_once('../../inc/global.inc.php'); - this script should be loaded by the /index.php script anyway, so global is already loaded
|
||||
require_once 'authldap.php';
|
||||
|
||||
$ldap_login_success = ldap_login($login, $password);
|
||||
|
||||
if ($ldap_login_success) {
|
||||
//error_log('Found user '.$login.' on LDAP server',0);
|
||||
/*
|
||||
In here, we know that
|
||||
- the user does not exist in dokeos
|
||||
- the users login and password are correct
|
||||
*/
|
||||
$info_array = ldap_find_user_info($login);
|
||||
ldap_put_user_info_locally($login, $info_array);
|
||||
} else {
|
||||
//error_log('Could not find '.$login.' on LDAP server',0);
|
||||
$loginFailed = true;
|
||||
unset($_user['user_id']);
|
||||
$uidReset = false;
|
||||
}
|
||||
6
main/auth/ldap/syncro_users.php
Normal file
6
main/auth/ldap/syncro_users.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
require_once '../../inc/global.inc.php';
|
||||
require_once 'authldap.php';
|
||||
|
||||
syncro_users();
|
||||
186
main/auth/lostPassword.php
Normal file
186
main/auth/lostPassword.php
Normal file
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
/**
|
||||
* SCRIPT PURPOSE :.
|
||||
*
|
||||
* This script allows users to retrieve the password of their profile(s)
|
||||
* on the basis of their e-mail address. The password is send via email
|
||||
* to the user.
|
||||
*
|
||||
* Special case : If the password are encrypted in the database, we have
|
||||
* to generate a new one.
|
||||
*
|
||||
* @todo refactor, move relevant functions to code libraries
|
||||
*/
|
||||
require_once __DIR__.'/../inc/global.inc.php';
|
||||
|
||||
// Custom pages
|
||||
// Had to move the form handling in here, because otherwise there would
|
||||
// already be some display output.
|
||||
|
||||
// Forbidden to retrieve the lost password
|
||||
if (api_get_setting('allow_lostpassword') === 'false') {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$reset = Request::get('reset');
|
||||
$userId = Request::get('id');
|
||||
|
||||
$this_section = SECTION_CAMPUS;
|
||||
|
||||
$tool_name = get_lang('LostPassword');
|
||||
|
||||
if ($reset && $userId) {
|
||||
$messageText = Login::reset_password($reset, $userId, true);
|
||||
Display::addFlash(
|
||||
Display::return_message($messageText, 'info', false)
|
||||
);
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit;
|
||||
}
|
||||
|
||||
$form = new FormValidator('lost_password', 'post', '', '', [], FormValidator::LAYOUT_GRID);
|
||||
$form->addHeader($tool_name);
|
||||
$form->addText(
|
||||
'user',
|
||||
[
|
||||
get_lang('LoginOrEmailAddress'),
|
||||
get_lang('EnterEmailUserAndWellSendYouPassword'),
|
||||
],
|
||||
true
|
||||
);
|
||||
|
||||
$captcha = api_get_setting('allow_captcha');
|
||||
$allowCaptcha = $captcha === 'true';
|
||||
|
||||
if ($allowCaptcha) {
|
||||
$ajax = api_get_path(WEB_AJAX_PATH).'form.ajax.php?a=get_captcha';
|
||||
$options = [
|
||||
'width' => 220,
|
||||
'height' => 90,
|
||||
'callback' => $ajax.'&var='.basename(__FILE__, '.php'),
|
||||
'sessionVar' => basename(__FILE__, '.php'),
|
||||
'imageOptions' => [
|
||||
'font_size' => 20,
|
||||
'font_path' => api_get_path(SYS_FONTS_PATH).'opensans/',
|
||||
'font_file' => 'OpenSans-Regular.ttf',
|
||||
//'output' => 'gif'
|
||||
],
|
||||
];
|
||||
$form->setLayout('inline');
|
||||
$captcha_question = $form->addElement(
|
||||
'CAPTCHA_Image',
|
||||
'captcha_question',
|
||||
'',
|
||||
$options
|
||||
);
|
||||
$form->addElement('static', null, null, get_lang('ClickOnTheImageForANewOne'));
|
||||
$form->addElement('text', 'captcha', get_lang('EnterTheLettersYouSee'), ['size' => 40]);
|
||||
$form->addRule('captcha', get_lang('EnterTheCharactersYouReadInTheImage'), 'required', null, 'client');
|
||||
$form->addRule('captcha', get_lang('TheTextYouEnteredDoesNotMatchThePicture'), 'CAPTCHA', $captcha_question);
|
||||
}
|
||||
|
||||
$form->addButtonSend(get_lang('Send'), 'submit', false, [], 'btn-block', null);
|
||||
|
||||
if ($form->validate()) {
|
||||
$values = $form->exportValues();
|
||||
$user = Login::get_user_accounts_by_username($values['user']);
|
||||
|
||||
if (!$user) {
|
||||
$messageText = get_lang('NoUserAccountWithThisEmailAddress');
|
||||
|
||||
if (CustomPages::enabled() && CustomPages::exists(CustomPages::LOST_PASSWORD)) {
|
||||
CustomPages::display(
|
||||
CustomPages::LOST_PASSWORD,
|
||||
['info' => $messageText]
|
||||
);
|
||||
exit;
|
||||
}
|
||||
|
||||
Display::addFlash(
|
||||
Display::return_message($messageText, 'error', false)
|
||||
);
|
||||
header('Location: '.api_get_self());
|
||||
exit;
|
||||
}
|
||||
|
||||
if ('true' === api_get_plugin_setting('whispeakauth', WhispeakAuthPlugin::SETTING_ENABLE)) {
|
||||
WhispeakAuthPlugin::deleteEnrollment($user['uid']);
|
||||
}
|
||||
|
||||
$passwordEncryption = api_get_configuration_value('password_encryption');
|
||||
|
||||
if ($passwordEncryption === 'none') {
|
||||
$messageText = Login::send_password_to_user($user, true);
|
||||
|
||||
if (CustomPages::enabled() && CustomPages::exists(CustomPages::INDEX_UNLOGGED)) {
|
||||
CustomPages::display(
|
||||
CustomPages::INDEX_UNLOGGED,
|
||||
['info' => $messageText]
|
||||
);
|
||||
exit;
|
||||
}
|
||||
|
||||
Display::addFlash(
|
||||
Display::return_message($messageText, 'info', false)
|
||||
);
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($user['auth_source'] == 'extldap') {
|
||||
Display::addFlash(
|
||||
Display::return_message(get_lang('CouldNotResetPasswordBecauseLDAP'), 'info', false)
|
||||
);
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit;
|
||||
}
|
||||
|
||||
$userResetPasswordSetting = api_get_setting('user_reset_password');
|
||||
|
||||
if ($userResetPasswordSetting === 'true') {
|
||||
$userObj = api_get_user_entity($user['uid']);
|
||||
Login::sendResetEmail($userObj);
|
||||
|
||||
if (CustomPages::enabled() && CustomPages::exists(CustomPages::INDEX_UNLOGGED)) {
|
||||
CustomPages::display(
|
||||
CustomPages::INDEX_UNLOGGED,
|
||||
['info' => get_lang('CheckYourEmailAndFollowInstructions')]
|
||||
);
|
||||
exit;
|
||||
}
|
||||
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit;
|
||||
}
|
||||
|
||||
$messageText = Login::handle_encrypted_password($user, true);
|
||||
|
||||
if (CustomPages::enabled() && CustomPages::exists(CustomPages::INDEX_UNLOGGED)) {
|
||||
CustomPages::display(
|
||||
CustomPages::INDEX_UNLOGGED,
|
||||
['info' => $messageText]
|
||||
);
|
||||
exit;
|
||||
}
|
||||
|
||||
Display::addFlash(
|
||||
Display::return_message($messageText, 'info', false)
|
||||
);
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit;
|
||||
}
|
||||
|
||||
if (CustomPages::enabled() && CustomPages::exists(CustomPages::LOST_PASSWORD)) {
|
||||
CustomPages::display(
|
||||
CustomPages::LOST_PASSWORD,
|
||||
['form' => $form->returnForm()]
|
||||
);
|
||||
exit;
|
||||
}
|
||||
|
||||
$tpl = new Template(null);
|
||||
$tpl->assign('content', $form->toHtml());
|
||||
$tpl->display_one_col_template();
|
||||
145
main/auth/my_progress.php
Normal file
145
main/auth/my_progress.php
Normal file
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
/**
|
||||
* Reporting page on the user's own progress.
|
||||
*/
|
||||
$cidReset = true;
|
||||
require_once __DIR__.'/../inc/global.inc.php';
|
||||
|
||||
api_block_anonymous_users();
|
||||
|
||||
if (api_get_configuration_value('block_my_progress_page')) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$this_section = SECTION_TRACKING;
|
||||
$nameTools = get_lang('MyProgress');
|
||||
|
||||
$htmlHeadXtra[] = api_get_js('jquery.timelinr-0.9.54.js');
|
||||
$htmlHeadXtra[] = "<script>
|
||||
$(function() {
|
||||
$().timelinr({
|
||||
containerDiv: '#my_timeline',
|
||||
autoPlayPause: 2000
|
||||
})
|
||||
});
|
||||
</script>";
|
||||
|
||||
$pluginCalendar = api_get_plugin_setting('learning_calendar', 'enabled') === 'true';
|
||||
|
||||
if ($pluginCalendar) {
|
||||
$plugin = LearningCalendarPlugin::create();
|
||||
$plugin->setJavaScript($htmlHeadXtra);
|
||||
}
|
||||
|
||||
$user_id = api_get_user_id();
|
||||
$courseUserList = CourseManager::get_courses_list_by_user_id($user_id);
|
||||
$dates = $issues = '';
|
||||
$sessionId = isset($_GET['session_id']) ? (int) $_GET['session_id'] : 0;
|
||||
$courseCode = isset($_GET['course']) ? Security::remove_XSS($_GET['course']) : null;
|
||||
$showGraph = false === api_get_configuration_value('hide_session_graph_in_my_progress');
|
||||
|
||||
$isAllowedToEdit = api_is_allowed_to_edit();
|
||||
|
||||
if (!empty($courseUserList)) {
|
||||
$items = MySpace::get_connections_from_course_list(
|
||||
$user_id,
|
||||
$courseUserList
|
||||
);
|
||||
$first = null;
|
||||
$last = null;
|
||||
$last_item = count($items);
|
||||
$count = 1;
|
||||
foreach ($items as $result) {
|
||||
$login = $result['login'];
|
||||
$courseId = $result['c_id'];
|
||||
$courseInfo = api_get_course_info_by_id($courseId);
|
||||
|
||||
if ($count == 1) {
|
||||
$first = '<a href="#'.$login.'">'.get_lang('First').'</a>';
|
||||
}
|
||||
if ($count == $last_item) {
|
||||
$last = '<a href="#'.$login.'">'.get_lang('Last').'</a>';
|
||||
}
|
||||
$course_info = api_get_course_info_by_id($result['c_id']);
|
||||
$course_image = '<img src="'.$course_info['course_image_large'].'">';
|
||||
$dates .= '<li><a href="#'.$login.'">'.api_convert_and_format_date($login, DATE_FORMAT_SHORT).'</a></li>';
|
||||
|
||||
$entered = sprintf(
|
||||
get_lang('YouHaveEnteredTheCourseXInY'),
|
||||
'" '.$courseInfo['name'].' "',
|
||||
api_convert_and_format_date($login, DATE_TIME_FORMAT_LONG)
|
||||
);
|
||||
|
||||
$issues .= '<li id ="'.$login.'">
|
||||
<div class="img-course">'.$course_image.'</div>
|
||||
<div class="text-course">
|
||||
<p>'.$entered.'</p>
|
||||
</div>
|
||||
</li>';
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
$content = Tracking::showUserProgress(
|
||||
$user_id,
|
||||
$sessionId,
|
||||
'',
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
$showGraph
|
||||
);
|
||||
$showAllSessionCourses = api_get_configuration_value('my_progress_session_show_all_courses');
|
||||
|
||||
if ($showAllSessionCourses && !empty($sessionId) && empty($courseCode)) {
|
||||
$userSessionCourses = UserManager::get_courses_list_by_session($user_id, $sessionId);
|
||||
foreach ($userSessionCourses as $userSessionCourse) {
|
||||
$content .= Tracking::show_course_detail(
|
||||
$user_id,
|
||||
$userSessionCourse['course_code'],
|
||||
$sessionId,
|
||||
$isAllowedToEdit
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$content .= Tracking::show_course_detail($user_id, $courseCode, $sessionId, $isAllowedToEdit);
|
||||
}
|
||||
|
||||
if (!empty($dates)) {
|
||||
$content .= Display::page_subheader(get_lang('Timeline'));
|
||||
$content .= '
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div id="my_timeline">
|
||||
<ul id="dates">'.$dates.'</ul>
|
||||
<ul id="issues">'.$issues.'</ul>
|
||||
<div id="grad_left"></div>
|
||||
<div id="grad_right"></div>
|
||||
<a href="#" id="prev"></a>
|
||||
<a href="#" id="next"></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
';
|
||||
}
|
||||
|
||||
if (api_get_configuration_value('private_messages_about_user_visible_to_user') === true) {
|
||||
$allowMessages = api_get_configuration_value('private_messages_about_user');
|
||||
if ($allowMessages === true) {
|
||||
$content .= Display::page_subheader2(get_lang('Messages'));
|
||||
$content .= MessageManager::getMessagesAboutUserToString(api_get_user_info());
|
||||
}
|
||||
}
|
||||
|
||||
$message = null;
|
||||
if (empty($content)) {
|
||||
$message = Display::return_message(get_lang('NoDataAvailable'), 'warning');
|
||||
}
|
||||
|
||||
$tpl = new Template($nameTools);
|
||||
$tpl->assign('message', $message);
|
||||
$tpl->assign('content', $content);
|
||||
$tpl->display_one_col_template();
|
||||
27
main/auth/okn/metadata.php
Normal file
27
main/auth/okn/metadata.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/* For license terms, see /license.txt */
|
||||
|
||||
use OneLogin\Saml2\Settings;
|
||||
|
||||
require_once '../../../main/inc/global.inc.php';
|
||||
|
||||
/**
|
||||
* SAML Metadata view.
|
||||
*/
|
||||
require_once 'settings.php';
|
||||
|
||||
try {
|
||||
// Now we only validate SP settings
|
||||
$settings = new Settings($settingsInfo, true);
|
||||
$metadata = $settings->getSPMetadata();
|
||||
$errors = $settings->validateMetadata($metadata);
|
||||
if (empty($errors)) {
|
||||
header('Content-Type: text/xml');
|
||||
echo $metadata;
|
||||
} else {
|
||||
throw new OneLogin\Saml2\Error('Invalid SP metadata: '.implode(', ', $errors), OneLogin\Saml2\Error::METADATA_SP_INVALID);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
15
main/auth/okn/report.php
Normal file
15
main/auth/okn/report.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
require_once '../../../main/inc/global.inc.php';
|
||||
|
||||
if (isset($_REQUEST['key']) && isset($_REQUEST['username'])) {
|
||||
$securityKey = api_get_configuration_value('security_key');
|
||||
$result = api_is_valid_secret_key($_REQUEST['key'], $securityKey);
|
||||
if ($result) {
|
||||
$userInfo = api_get_user_info_from_username($_REQUEST['username']);
|
||||
if ($userInfo) {
|
||||
$result = Tracking::getCourseLpProgress($userInfo['id'], 0);
|
||||
echo json_encode($result);
|
||||
}
|
||||
}
|
||||
}
|
||||
157
main/auth/okn/settings.dist.php
Normal file
157
main/auth/okn/settings.dist.php
Normal file
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
exit;
|
||||
|
||||
require_once '../../../main/inc/global.inc.php';
|
||||
|
||||
$spBaseUrl = api_get_path(WEB_CODE_PATH).'auth/okn/';
|
||||
|
||||
$url = 'https://example.es/';
|
||||
$realm = 'master';
|
||||
$path = '/path';
|
||||
|
||||
//$certificate = file_get_contents($path);
|
||||
|
||||
$settingsInfo = [
|
||||
'course_list' => ['ABC', 'CDE'],
|
||||
'strict' => false,
|
||||
'debug' => true,
|
||||
'sp' => [
|
||||
'entityId' => $spBaseUrl.'metadata.php',
|
||||
'assertionConsumerService' => [
|
||||
'url' => $spBaseUrl.'start.php?acs',
|
||||
],
|
||||
'singleLogoutService' => [
|
||||
'url' => $spBaseUrl.'start.php?sls',
|
||||
],
|
||||
'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified',
|
||||
],
|
||||
'idp' => [
|
||||
'entityId' => $url.'auth/realms/'.$realm, // Example http://localhost:8080/auth/realms/master
|
||||
'singleSignOnService' => [
|
||||
'url' => $url.'auth/realms/'.$realm.'/protocol/saml', // example http://localhost:8080/auth/realms/master/protocol/saml
|
||||
],
|
||||
'singleLogoutService' => [
|
||||
'url' => $url.'auth/realms/'.$realm.'/protocol/saml', // example http://localhost:8080/auth/realms/master/protocol/saml
|
||||
],
|
||||
//'x509cert' => $certificate,
|
||||
],
|
||||
];
|
||||
|
||||
// advanced settings
|
||||
//
|
||||
//
|
||||
//// Compression settings
|
||||
//'compress' => array (
|
||||
// 'requests' => true,
|
||||
// 'responses' => true
|
||||
//),
|
||||
// // Security settings
|
||||
// 'security' => array (
|
||||
//
|
||||
// /** signatures and encryptions offered */
|
||||
//
|
||||
// // Indicates that the nameID of the <samlp:logoutRequest> sent by this SP
|
||||
// // will be encrypted.
|
||||
// 'nameIdEncrypted' => false,
|
||||
//
|
||||
// // Indicates whether the <samlp:AuthnRequest> messages sent by this SP
|
||||
// // will be signed. [Metadata of the SP will offer this info]
|
||||
// 'authnRequestsSigned' => false,
|
||||
//
|
||||
// // Indicates whether the <samlp:logoutRequest> messages sent by this SP
|
||||
// // will be signed.
|
||||
// 'logoutRequestSigned' => false,
|
||||
//
|
||||
// // Indicates whether the <samlp:logoutResponse> messages sent by this SP
|
||||
// // will be signed.
|
||||
// 'logoutResponseSigned' => false,
|
||||
//
|
||||
// /* Sign the Metadata
|
||||
// False || True (use sp certs) || array (
|
||||
// keyFileName => 'metadata.key',
|
||||
// certFileName => 'metadata.crt'
|
||||
// )
|
||||
// */
|
||||
// 'signMetadata' => false,
|
||||
//
|
||||
// /** signatures and encryptions required **/
|
||||
//
|
||||
// // Indicates a requirement for the <samlp:Response>, <samlp:LogoutRequest>
|
||||
// // and <samlp:LogoutResponse> elements received by this SP to be signed.
|
||||
// 'wantMessagesSigned' => false,
|
||||
//
|
||||
// // Indicates a requirement for the <saml:Assertion> elements received by
|
||||
// // this SP to be encrypted.
|
||||
// 'wantAssertionsEncrypted' => false,
|
||||
//
|
||||
// // Indicates a requirement for the <saml:Assertion> elements received by
|
||||
// // this SP to be signed. [Metadata of the SP will offer this info]
|
||||
// 'wantAssertionsSigned' => false,
|
||||
//
|
||||
// // Indicates a requirement for the NameID element on the SAMLResponse
|
||||
// // received by this SP to be present.
|
||||
// 'wantNameId' => true,
|
||||
//
|
||||
// // Indicates a requirement for the NameID received by
|
||||
// // this SP to be encrypted.
|
||||
// 'wantNameIdEncrypted' => false,
|
||||
//
|
||||
// // Authentication context.
|
||||
// // Set to false and no AuthContext will be sent in the AuthNRequest.
|
||||
// // Set true or don't present this parameter and you will get an AuthContext 'exact' 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport'.
|
||||
// // Set an array with the possible auth context values: array ('urn:oasis:names:tc:SAML:2.0:ac:classes:Password', 'urn:oasis:names:tc:SAML:2.0:ac:classes:X509').
|
||||
// 'requestedAuthnContext' => true,
|
||||
//
|
||||
// // Indicates if the SP will validate all received xmls.
|
||||
// // (In order to validate the xml, 'strict' and 'wantXMLValidation' must be true).
|
||||
// 'wantXMLValidation' => true,
|
||||
//
|
||||
// // If true, SAMLResponses with an empty value at its Destination
|
||||
// // attribute will not be rejected for this fact.
|
||||
// 'relaxDestinationValidation' => false,
|
||||
//
|
||||
// // Algorithm that the toolkit will use on signing process. Options:
|
||||
// // 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'
|
||||
// // 'http://www.w3.org/2000/09/xmldsig#dsa-sha1'
|
||||
// // 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'
|
||||
// // 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384'
|
||||
// // 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512'
|
||||
// // Notice that sha1 is a deprecated algorithm and should not be used
|
||||
// 'signatureAlgorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256',
|
||||
//
|
||||
// // Algorithm that the toolkit will use on digest process. Options:
|
||||
// // 'http://www.w3.org/2000/09/xmldsig#sha1'
|
||||
// // 'http://www.w3.org/2001/04/xmlenc#sha256'
|
||||
// // 'http://www.w3.org/2001/04/xmldsig-more#sha384'
|
||||
// // 'http://www.w3.org/2001/04/xmlenc#sha512'
|
||||
// // Notice that sha1 is a deprecated algorithm and should not be used
|
||||
// 'digestAlgorithm' => 'http://www.w3.org/2001/04/xmlenc#sha256',
|
||||
//
|
||||
// // ADFS URL-Encodes SAML data as lowercase, and the toolkit by default uses
|
||||
// // uppercase. Turn it True for ADFS compatibility on signature verification
|
||||
// 'lowercaseUrlencoding' => false,
|
||||
//),
|
||||
//
|
||||
// // Contact information template, it is recommended to supply a
|
||||
// // technical and support contacts.
|
||||
// 'contactPerson' => array (
|
||||
// 'technical' => array (
|
||||
// 'givenName' => 'example',
|
||||
// 'emailAddress' => 'test@example.org'
|
||||
// ),
|
||||
// 'support' => array (
|
||||
// 'givenName' => 'example',
|
||||
// 'emailAddress' => 'test@example.org'
|
||||
// ),
|
||||
//),
|
||||
//
|
||||
// // Organization information template, the info in en_US lang is
|
||||
// // recomended, add more if required.
|
||||
// 'organization' => array (
|
||||
// 'en-US' => array(
|
||||
// 'name' => 'chamilo',
|
||||
// 'displayname' => 'chamilo',
|
||||
// 'url' => 'chamilo.org'
|
||||
// ),
|
||||
//),
|
||||
254
main/auth/okn/start.php
Normal file
254
main/auth/okn/start.php
Normal file
@@ -0,0 +1,254 @@
|
||||
<?php
|
||||
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
use ChamiloSession as Session;
|
||||
use OneLogin\Saml2\Auth;
|
||||
use OneLogin\Saml2\AuthnRequest;
|
||||
use OneLogin\Saml2\Settings;
|
||||
|
||||
require_once '../../../main/inc/global.inc.php';
|
||||
|
||||
// Create a settings.dist.php
|
||||
if (file_exists('settings.php')) {
|
||||
require_once 'settings.php';
|
||||
} else {
|
||||
$message = '';
|
||||
if (api_is_platform_admin()) {
|
||||
$message = 'Create a settings.php';
|
||||
}
|
||||
api_not_allowed(true, $message);
|
||||
}
|
||||
|
||||
$content = '';
|
||||
$auth = new Auth($settingsInfo);
|
||||
$settings = new Settings($settingsInfo);
|
||||
$authRequest = new AuthnRequest($settings);
|
||||
|
||||
$samlRequest = $authRequest->getRequest(true);
|
||||
$idpData = $settings->getIdPData();
|
||||
|
||||
if (isset($_GET['email']) || isset($_GET['email_bis'])) {
|
||||
$auth->login();
|
||||
// If AuthNRequest ID need to be saved in order to later validate it, do instead
|
||||
/*$ssoBuiltUrl = $auth->login(null, [], false, false, true);
|
||||
$_SESSION['AuthNRequestID'] = $auth->getLastRequestID();
|
||||
header('Pragma: no-cache');
|
||||
header('Cache-Control: no-cache, must-revalidate');
|
||||
header('Location: ' . $ssoBuiltUrl);
|
||||
exit();*/
|
||||
} elseif (isset($_GET['slo'])) {
|
||||
$returnTo = null;
|
||||
$parameters = [];
|
||||
$nameId = Session::read('samlNameId');
|
||||
$sessionIndex = Session::read('samlSessionIndex');
|
||||
$nameIdFormat = Session::read('samlNameIdFormat');
|
||||
$auth->logout($returnTo, $parameters, $nameId, $sessionIndex, false, $nameIdFormat);
|
||||
} elseif (isset($_GET['acs'])) {
|
||||
$requestID = Session::read('AuthNRequestID');
|
||||
$auth->processResponse($requestID);
|
||||
$errors = $auth->getErrors();
|
||||
if (!empty($errors)) {
|
||||
$content .= '<p>'.implode(', ', $errors).'</p>';
|
||||
}
|
||||
|
||||
if (!$auth->isAuthenticated()) {
|
||||
api_not_allowed(true, $content.'<p>Not authenticated</p>');
|
||||
exit;
|
||||
}
|
||||
|
||||
$attributes = $auth->getAttributes();
|
||||
|
||||
$valueList = [];
|
||||
$attributeNameList = [
|
||||
'email',
|
||||
'username',
|
||||
'firstname',
|
||||
'lastname1',
|
||||
'lastname2',
|
||||
'courses',
|
||||
];
|
||||
|
||||
// Check normal params
|
||||
foreach ($attributeNameList as $name) {
|
||||
if (isset($attributes[$name]) && !empty($attributes[$name])) {
|
||||
$valueList[$name] = $attributes[$name];
|
||||
}
|
||||
}
|
||||
|
||||
// Check bis params
|
||||
foreach ($attributeNameList as $name) {
|
||||
$bisName = $name.'_bis';
|
||||
if (isset($attributes[$bisName]) && !empty($attributes[$bisName])) {
|
||||
$valueList[$name] = $attributes[$bisName];
|
||||
}
|
||||
}
|
||||
|
||||
$attributes = $valueList;
|
||||
|
||||
if (!isset($attributes['email']) ||
|
||||
!isset($attributes['firstname']) ||
|
||||
!isset($attributes['lastname1']) ||
|
||||
!isset($attributes['lastname2']) ||
|
||||
!isset($attributes['username'])
|
||||
) {
|
||||
echo 'Not enough parameters, current values: ';
|
||||
echo '<pre>';
|
||||
var_dump($auth->getAttributes());
|
||||
exit;
|
||||
}
|
||||
|
||||
foreach ($attributes as &$attribute) {
|
||||
$attribute = implode('', $attribute);
|
||||
}
|
||||
|
||||
$username = $attributes['username'];
|
||||
$userInfo = api_get_user_info_from_username($username);
|
||||
$userId = null;
|
||||
|
||||
if (empty($userInfo)) {
|
||||
$lastName = $attributes['lastname1'].' '.$attributes['lastname2'];
|
||||
$userId = UserManager::create_user(
|
||||
$attributes['firstname'],
|
||||
$lastName,
|
||||
STUDENT,
|
||||
$attributes['email'],
|
||||
$username,
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'okn'
|
||||
);
|
||||
if ($userId) {
|
||||
$userInfo = api_get_user_info($userId);
|
||||
} else {
|
||||
echo "Error cannot create user: $username";
|
||||
}
|
||||
} else {
|
||||
// Only load users that were created using this method.
|
||||
if ($userInfo['auth_source'] === 'okn') {
|
||||
$userId = $userInfo['user_id'];
|
||||
} else {
|
||||
echo "Error cannot handle user $username, because it was not created by okn";
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($userId)) {
|
||||
$courseCode = null;
|
||||
if (isset($settingsInfo['course_list']) && !empty($settingsInfo['course_list'])) {
|
||||
foreach ($settingsInfo['course_list'] as $courseCode) {
|
||||
CourseManager::subscribeUser($userId, $courseCode, STUDENT, 0, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($attributes['courses']) && !empty($attributes['courses'])) {
|
||||
$courses = explode(',', $attributes['courses']);
|
||||
$firstCourseCode = '';
|
||||
if (!empty($courses)) {
|
||||
$counter = 1;
|
||||
foreach ($courses as $course) {
|
||||
$courseInfo = api_get_course_info($course);
|
||||
if ($courseInfo) {
|
||||
if ($counter == 1) {
|
||||
$firstCourseCode = $course;
|
||||
}
|
||||
CourseManager::subscribeUser($userId, $courseInfo['code'], STUDENT, 0, 0, false);
|
||||
}
|
||||
$counter++;
|
||||
}
|
||||
$courseCode = $firstCourseCode;
|
||||
}
|
||||
}
|
||||
|
||||
// Clean flash messages
|
||||
Session::write('flash_messages', '');
|
||||
|
||||
// Set chamilo sessions
|
||||
Session::write('samlUserdata', $auth->getAttributes());
|
||||
Session::write('samlNameId', $auth->getNameId());
|
||||
Session::write('samlNameIdFormat', $auth->getNameIdFormat());
|
||||
Session::write('samlSessionIndex', $auth->getSessionIndex());
|
||||
Session::erase('AuthNRequestID');
|
||||
|
||||
// Filling session variables with new data
|
||||
Session::write('_uid', $userId);
|
||||
Session::write('_user', $userInfo);
|
||||
Session::write('is_platformAdmin', false);
|
||||
Session::write('is_allowedCreateCourse', false);
|
||||
|
||||
Event::eventLogin($userId);
|
||||
|
||||
if (!empty($courseCode)) {
|
||||
$courseInfo = api_get_course_info($courseCode);
|
||||
header('Location: '.$courseInfo['course_public_url']);
|
||||
exit;
|
||||
}
|
||||
header('Location: '.api_get_path(WEB_PATH).'user_portal.php');
|
||||
exit;
|
||||
} else {
|
||||
echo 'User not found';
|
||||
}
|
||||
exit;
|
||||
|
||||
if (!empty($userId)) {
|
||||
} else {
|
||||
Display::addFlash(Display::return_message(get_lang('InvalidId')));
|
||||
}
|
||||
|
||||
/*if (isset($_POST['RelayState']) && \OneLogin\Saml2\Utils::getSelfURL() != $_POST['RelayState']) {
|
||||
$auth->redirectTo($_POST['RelayState']);
|
||||
}*/
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit;
|
||||
} elseif (isset($_GET['sls'])) {
|
||||
$requestID = Session::read('LogoutRequestID');
|
||||
$auth->processSLO(false, $requestID);
|
||||
$errors = $auth->getErrors();
|
||||
|
||||
if (empty($errors)) {
|
||||
Session::erase('samlNameId');
|
||||
Session::erase('samlSessionIndex');
|
||||
Session::erase('samlNameIdFormat');
|
||||
Session::erase('samlUserdata');
|
||||
Session::erase('AuthNRequestID');
|
||||
Session::erase('LogoutRequestID');
|
||||
|
||||
Display::addFlash(Display::return_message('Sucessfully logged out'));
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit;
|
||||
} else {
|
||||
api_not_allowed(true, implode(', ', $errors));
|
||||
}
|
||||
}
|
||||
|
||||
$template = new Template('');
|
||||
|
||||
if (isset($_SESSION['samlUserdata'])) {
|
||||
$attributes = Session::read('samlUserdata');
|
||||
$params = [];
|
||||
if (!empty($attributes)) {
|
||||
$content .= 'You have the following attributes:<br>';
|
||||
$content .= '<table class="table"><thead><th>Name</th><th>Values</th></thead><tbody>';
|
||||
foreach ($attributes as $attributeName => $attributeValues) {
|
||||
$content .= '<tr><td>'.htmlentities($attributeName).'</td><td><ul>';
|
||||
foreach ($attributeValues as $attributeValue) {
|
||||
$content .= '<li>'.htmlentities($attributeValue).'</li>';
|
||||
}
|
||||
$content .= '</ul></td></tr>';
|
||||
}
|
||||
$content .= '</tbody></table>';
|
||||
} else {
|
||||
$content .= "<p>You don't have any attribute</p>";
|
||||
}
|
||||
|
||||
$content .= '<p><a href="?slo" >Logout</a></p>';
|
||||
} else {
|
||||
$content .= '<p><a href="?sso" >Login</a></p>';
|
||||
//$content .= '<p><a href="?sso2" >Login and access to attrs.php page</a></p>';
|
||||
}
|
||||
|
||||
$template->assign('content', $content);
|
||||
$template->display_one_col_template();
|
||||
490
main/auth/openid/login.php
Normal file
490
main/auth/openid/login.php
Normal file
@@ -0,0 +1,490 @@
|
||||
<?php
|
||||
|
||||
/* For licensing terms, see /license.txt */
|
||||
/**
|
||||
* OpenID login method
|
||||
*
|
||||
* The OpenID login method relies on authentication servers providing a public
|
||||
* URL that can confirm the identity of a person, thus avoiding the spread
|
||||
* use of password transmissions over non-secure lines (for Dokeos, it is a
|
||||
* good way of avoiding password theft)
|
||||
* @package chamilo.auth.openid
|
||||
*/
|
||||
|
||||
require_once 'openid.lib.php';
|
||||
require_once 'xrds.lib.php';
|
||||
|
||||
function openid_form(): FormValidator
|
||||
{
|
||||
$form = new FormValidator(
|
||||
'openid_login',
|
||||
'post',
|
||||
null,
|
||||
null,
|
||||
array('class' => 'form-vertical form_login')
|
||||
);
|
||||
$form -> addElement('text', 'openid_url', array(get_lang('OpenIDURL'), Display::url(get_lang('OpenIDWhatIs'), 'main/auth/openid/whatis.php')), array('class' => 'openid_input'));
|
||||
$form -> addElement('button', 'submit', get_lang('Login'));
|
||||
$form->applyFilter('openid_url', 'trim');
|
||||
$form->protect();
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* The initial step of OpenID authentication responsible for the following:
|
||||
* - Perform discovery on the claimed OpenID.
|
||||
* - If possible, create an association with the Provider's endpoint.
|
||||
* - Create the authentication request.
|
||||
* - Perform the appropriate redirect.
|
||||
*
|
||||
* @param $claimed_id The OpenID to authenticate
|
||||
* @param $return_to The endpoint to return to from the OpenID Provider
|
||||
*/
|
||||
function openid_begin($claimed_id, $return_to = '', $form_values = array()) {
|
||||
|
||||
$claimed_id = _openid_normalize($claimed_id);
|
||||
$services = openid_discovery($claimed_id);
|
||||
if (count($services) == 0) {
|
||||
echo 'Sorry, that is not a valid OpenID. Please ensure you have spelled your ID correctly.';
|
||||
return;
|
||||
}
|
||||
$op_endpoint = $services[0]['uri'];
|
||||
// Store the discovered endpoint in the session (so we don't have to rediscover).
|
||||
$_SESSION['openid_op_endpoint'] = $op_endpoint;
|
||||
// Store the claimed_id in the session (for handling delegation).
|
||||
$_SESSION['openid_claimed_id'] = $claimed_id;
|
||||
// Store the login form values so we can pass them to
|
||||
// user_exteral_login later.
|
||||
$_SESSION['openid_user_login_values'] = $form_values;
|
||||
|
||||
// If bcmath is present, then create an association
|
||||
$assoc_handle = '';
|
||||
if (function_exists('bcadd')) {
|
||||
$assoc_handle = openid_association($op_endpoint);
|
||||
}
|
||||
// Now that there is an association created, move on
|
||||
// to request authentication from the IdP
|
||||
$identity = (!empty($services[0]['delegate'])) ? $services[0]['delegate'] : $claimed_id;
|
||||
if (isset($services[0]['types']) && is_array($services[0]['types']) && in_array(OPENID_NS_2_0 . '/server', $services[0]['types'])) {
|
||||
$identity = 'http://openid.net/identifier_select/2.0';
|
||||
}
|
||||
$authn_request = openid_authentication_request($claimed_id, $identity, $return_to, $assoc_handle, $services[0]['version']);
|
||||
if ($services[0]['version'] == 2) {
|
||||
echo openid_redirect($op_endpoint, $authn_request);
|
||||
} else {
|
||||
echo openid_redirect_http($op_endpoint, $authn_request);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Completes OpenID authentication by validating returned data from the OpenID
|
||||
* Provider.
|
||||
* @param array $response Array of returned from the OpenID provider (typically $_REQUEST).
|
||||
* @return array $response Response values for further processing with $response['status'] set to one of 'success', 'failed' or 'cancel'.
|
||||
*/
|
||||
function openid_complete($response) {
|
||||
// Default to failed response
|
||||
$response['status'] = 'failed';
|
||||
if (isset($_SESSION['openid_op_endpoint']) && isset($_SESSION['openid_claimed_id'])) {
|
||||
_openid_fix_post($response);
|
||||
$op_endpoint = $_SESSION['openid_op_endpoint'];
|
||||
$claimed_id = $_SESSION['openid_claimed_id'];
|
||||
unset($_SESSION['openid_op_endpoint']);
|
||||
unset($_SESSION['openid_claimed_id']);
|
||||
if (isset($response['openid.mode'])) {
|
||||
if ($response['openid.mode'] == 'cancel') {
|
||||
$response['status'] = 'cancel';
|
||||
} else {
|
||||
if (openid_verify_assertion($op_endpoint, $response)) {
|
||||
$response['openid.identity'] = $claimed_id;
|
||||
$response['status'] = 'success';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform discovery on a claimed ID to determine the OpenID provider endpoint.
|
||||
*
|
||||
* @param $claimed_id The OpenID URL to perform discovery on.
|
||||
*
|
||||
* @return Array of services discovered (including OpenID version, endpoint
|
||||
* URI, etc).
|
||||
*/
|
||||
function openid_discovery($claimed_id)
|
||||
{
|
||||
$services = array();
|
||||
|
||||
$xrds_url = $claimed_id;
|
||||
if (_openid_is_xri($claimed_id)) {
|
||||
$xrds_url = 'http://xri.net/' . $claimed_id;
|
||||
}
|
||||
$url = @parse_url($xrds_url);
|
||||
if ($url['scheme'] == 'http' || $url['scheme'] == 'https') {
|
||||
// For regular URLs, try Yadis resolution first, then HTML-based discovery
|
||||
$headers = array('Accept' => 'application/xrds+xml');
|
||||
//TODO
|
||||
$result = openid_http_request($xrds_url, $headers);
|
||||
|
||||
if (!isset($result->error)) {
|
||||
if (isset($result->headers['Content-Type']) && preg_match("/application\/xrds\+xml/", $result->headers['Content-Type'])) {
|
||||
// Parse XML document to find URL
|
||||
$services = xrds_parse($result->data);
|
||||
} else {
|
||||
$xrds_url = NULL;
|
||||
if (isset($result->headers['X-XRDS-Location'])) {
|
||||
$xrds_url = $result->headers['X-XRDS-Location'];
|
||||
} else {
|
||||
// Look for meta http-equiv link in HTML head
|
||||
$xrds_url = _openid_meta_httpequiv('X-XRDS-Location', $result->data);
|
||||
}
|
||||
if (!empty($xrds_url)) {
|
||||
$headers = array('Accept' => 'application/xrds+xml');
|
||||
//TODO
|
||||
$xrds_result = openid_http_request($xrds_url, $headers);
|
||||
if (!isset($xrds_result->error)) {
|
||||
$services = xrds_parse($xrds_result->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for HTML delegation
|
||||
if (count($services) == 0) {
|
||||
// Look for 2.0 links
|
||||
$uri = _openid_link_href('openid2.provider', $result->data);
|
||||
$delegate = _openid_link_href('openid2.local_id', $result->data);
|
||||
$version = 2;
|
||||
|
||||
// 1.0 links
|
||||
if (empty($uri)) {
|
||||
$uri = _openid_link_href('openid.server', $result->data);
|
||||
$delegate = _openid_link_href('openid.delegate', $result->data);
|
||||
$version = 1;
|
||||
}
|
||||
if (!empty($uri)) {
|
||||
$services[] = array('uri' => $uri, 'delegate' => $delegate, 'version' => $version);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $services;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to create a shared secret with the OpenID Provider.
|
||||
* @param $op_endpoint URL of the OpenID Provider endpoint.
|
||||
* @return object $assoc_handle The association handle.
|
||||
*/
|
||||
function openid_association($op_endpoint) {
|
||||
//@todo Remove Old Associations:
|
||||
$openid_association = Database::get_main_table(TABLE_MAIN_OPENID_ASSOCIATION);
|
||||
$sql = "DELETE FROM $openid_association
|
||||
WHERE created + expires_in < '" . api_get_utc_datetime() . "'";
|
||||
Database::query($sql);
|
||||
|
||||
// Check to see if we have an association for this IdP already
|
||||
$op_endpoint = Database::escape_string($op_endpoint);
|
||||
$sql = "SELECT assoc_handle
|
||||
FROM $openid_association
|
||||
WHERE idp_endpoint_uri = '$op_endpoint'";
|
||||
$assoc_handle = Database::query($sql);
|
||||
if (Database::num_rows($assoc_handle) <= 1) {
|
||||
$mod = OPENID_DH_DEFAULT_MOD;
|
||||
$gen = OPENID_DH_DEFAULT_GEN;
|
||||
$r = _openid_dh_rand($mod);
|
||||
$private = bcadd($r, 1);
|
||||
$public = bcpowmod($gen, $private, $mod);
|
||||
|
||||
// If there is no existing association, then request one
|
||||
$assoc_request = openid_association_request($public);
|
||||
$assoc_message = _openid_encode_message(_openid_create_message($assoc_request));
|
||||
$assoc_headers = array('Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8');
|
||||
//TODO
|
||||
$assoc_result = openid_http_request($op_endpoint, $assoc_headers, 'POST', $assoc_message);
|
||||
if (isset($assoc_result->error)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$assoc_response = _openid_parse_message($assoc_result->data);
|
||||
if (isset($assoc_response['mode']) && $assoc_response['mode'] == 'error') {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ($assoc_response['session_type'] == 'DH-SHA1') {
|
||||
$spub = _openid_dh_base64_to_long($assoc_response['dh_server_public']);
|
||||
$enc_mac_key = base64_decode($assoc_response['enc_mac_key']);
|
||||
$shared = bcpowmod($spub, $private, $mod);
|
||||
$assoc_response['mac_key'] = base64_encode(_openid_dh_xorsecret($shared, $enc_mac_key));
|
||||
}
|
||||
//TODO
|
||||
$openid_association = Database::get_main_table(TABLE_MAIN_OPENID_ASSOCIATION);
|
||||
Database::query(sprintf("INSERT INTO $openid_association (idp_endpoint_uri, session_type, assoc_handle, assoc_type, expires_in, mac_key, created) VALUES('%s', '%s', '%s', '%s', %d, '%s', %d)", $op_endpoint, $assoc_response['session_type'], $assoc_response['assoc_handle'], $assoc_response['assoc_type'], $assoc_response['expires_in'], $assoc_response['mac_key'], api_get_utc_datetime()));
|
||||
|
||||
$assoc_handle = $assoc_response['assoc_handle'];
|
||||
}
|
||||
return $assoc_handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* ?
|
||||
*/
|
||||
function openid_association_request($public) {
|
||||
|
||||
$request = array(
|
||||
'openid.ns' => OPENID_NS_2_0,
|
||||
'openid.mode' => 'associate',
|
||||
'openid.session_type' => 'DH-SHA1',
|
||||
'openid.assoc_type' => 'HMAC-SHA1'
|
||||
);
|
||||
|
||||
if ($request['openid.session_type'] == 'DH-SHA1' || $request['openid.session_type'] == 'DH-SHA256') {
|
||||
$cpub = _openid_dh_long_to_base64($public);
|
||||
$request['openid.dh_consumer_public'] = $cpub;
|
||||
}
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function openid_authentication_request($claimed_id, $identity, $return_to = '', $assoc_handle = '', $version = 2) {
|
||||
|
||||
$realm = ($return_to) ? $return_to : api_get_self();
|
||||
|
||||
$ns = ($version == 2) ? OPENID_NS_2_0 : OPENID_NS_1_0;
|
||||
$request = array(
|
||||
'openid.ns' => $ns,
|
||||
'openid.mode' => 'checkid_setup',
|
||||
'openid.identity' => $identity,
|
||||
'openid.claimed_id' => $claimed_id,
|
||||
'openid.assoc_handle' => $assoc_handle,
|
||||
'openid.return_to' => $return_to,
|
||||
);
|
||||
|
||||
if ($version == 2) {
|
||||
$request['openid.realm'] = $realm;
|
||||
} else {
|
||||
$request['openid.trust_root'] = $realm;
|
||||
}
|
||||
|
||||
// Simple Registration - we don't ask lastname and firstname because the only
|
||||
// available similar data is "fullname" and we would have to guess where to split
|
||||
$request['openid.sreg.required'] = 'nickname,email';
|
||||
$request['openid.ns.sreg'] = "http://openid.net/extensions/sreg/1.1";
|
||||
|
||||
//$request = array_merge($request, module_invoke_all('openid', 'request', $request));
|
||||
//$request = array_merge($request);
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to verify the response received from the OpenID Provider.
|
||||
*
|
||||
* @param $op_endpoint The OpenID Provider URL.
|
||||
* @param $response Array of repsonse values from the provider.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
function openid_verify_assertion($op_endpoint, $response) {
|
||||
|
||||
$valid = FALSE;
|
||||
|
||||
//TODO
|
||||
$openid_association = Database::get_main_table(TABLE_MAIN_OPENID_ASSOCIATION);
|
||||
$sql = sprintf("SELECT * FROM $openid_association WHERE assoc_handle = '%s'", $response['openid.assoc_handle']);
|
||||
$res = Database::query($sql);
|
||||
$association = Database::fetch_object($res);
|
||||
if ($association && isset($association->session_type)) {
|
||||
$keys_to_sign = explode(',', $response['openid.signed']);
|
||||
$self_sig = _openid_signature($association, $response, $keys_to_sign);
|
||||
if ($self_sig == $response['openid.sig']) {
|
||||
$valid = TRUE;
|
||||
} else {
|
||||
$valid = FALSE;
|
||||
}
|
||||
} else {
|
||||
$request = $response;
|
||||
$request['openid.mode'] = 'check_authentication';
|
||||
$message = _openid_create_message($request);
|
||||
$headers = array('Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8');
|
||||
$result = openid_http_request($op_endpoint, $headers, 'POST', _openid_encode_message($message));
|
||||
if (!isset($result->error)) {
|
||||
$response = _openid_parse_message($result->data);
|
||||
if (strtolower(trim($response['is_valid'])) == 'true') {
|
||||
$valid = TRUE;
|
||||
} else {
|
||||
$valid = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a HTTP request - This function has been copied straight over from Drupal 6 code (drupal_http_request)
|
||||
* @param string $data
|
||||
*/
|
||||
function openid_http_request($url, $headers = array(), $method = 'GET', $data = NULL, $retry = 3) {
|
||||
$result = new stdClass();
|
||||
|
||||
// Parse the URL and make sure we can handle the schema.
|
||||
$uri = parse_url($url);
|
||||
|
||||
switch ($uri['scheme']) {
|
||||
case 'http':
|
||||
$port = isset($uri['port']) ? $uri['port'] : 80;
|
||||
$host = $uri['host'] . ($port != 80 ? ':' . $port : '');
|
||||
$fp = @fsockopen($uri['host'], $port, $errno, $errstr, 15);
|
||||
break;
|
||||
case 'https':
|
||||
// Note: Only works for PHP 4.3 compiled with OpenSSL.
|
||||
$port = isset($uri['port']) ? $uri['port'] : 443;
|
||||
$host = $uri['host'] . ($port != 443 ? ':' . $port : '');
|
||||
$fp = @fsockopen('ssl://' . $uri['host'], $port, $errno, $errstr, 20);
|
||||
break;
|
||||
default:
|
||||
$result->error = 'invalid schema ' . $uri['scheme'];
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Make sure the socket opened properly.
|
||||
if (!$fp) {
|
||||
// When a network error occurs, we make sure that it is a negative number so
|
||||
// it can clash with the HTTP status codes.
|
||||
$result->code = -$errno;
|
||||
$result->error = trim($errstr);
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Construct the path to act on.
|
||||
$path = isset($uri['path']) ? $uri['path'] : '/';
|
||||
if (isset($uri['query'])) {
|
||||
$path .= '?' . $uri['query'];
|
||||
}
|
||||
|
||||
// Create HTTP request.
|
||||
$defaults = array(
|
||||
// RFC 2616: "non-standard ports MUST, default ports MAY be included".
|
||||
// We don't add the port to prevent from breaking rewrite rules checking the
|
||||
// host that do not take into account the port number.
|
||||
'Host' => "Host: $host",
|
||||
'User-Agent' => 'User-Agent: Chamilo (+http://www.chamilo.org/)',
|
||||
'Content-Length' => 'Content-Length: ' . strlen($data)
|
||||
);
|
||||
|
||||
// If the server url has a user then attempt to use basic authentication
|
||||
if (isset($uri['user'])) {
|
||||
$defaults['Authorization'] = 'Authorization: Basic ' . base64_encode($uri['user'] . (!empty($uri['pass']) ? ":" . $uri['pass'] : ''));
|
||||
}
|
||||
|
||||
foreach ($headers as $header => $value) {
|
||||
$defaults[$header] = $header . ': ' . $value;
|
||||
}
|
||||
|
||||
$request = $method . ' ' . $path . " HTTP/1.0\r\n";
|
||||
$request .= implode("\r\n", $defaults);
|
||||
$request .= "\r\n\r\n";
|
||||
if ($data) {
|
||||
$request .= $data . "\r\n";
|
||||
}
|
||||
$result->request = $request;
|
||||
|
||||
fwrite($fp, $request);
|
||||
|
||||
// Fetch response.
|
||||
$response = '';
|
||||
while (!feof($fp) && $chunk = fread($fp, 1024)) {
|
||||
$response .= $chunk;
|
||||
}
|
||||
fclose($fp);
|
||||
|
||||
// Parse response.
|
||||
list($split, $result->data) = explode("\r\n\r\n", $response, 2);
|
||||
$split = preg_split("/\r\n|\n|\r/", $split);
|
||||
|
||||
list($protocol, $code, $text) = explode(' ', trim(array_shift($split)), 3);
|
||||
$result->headers = array();
|
||||
|
||||
// Parse headers.
|
||||
while ($line = trim(array_shift($split))) {
|
||||
list($header, $value) = explode(':', $line, 2);
|
||||
if (isset($result->headers[$header]) && $header == 'Set-Cookie') {
|
||||
// RFC 2109: the Set-Cookie response header comprises the token Set-
|
||||
// Cookie:, followed by a comma-separated list of one or more cookies.
|
||||
$result->headers[$header] .= ',' . trim($value);
|
||||
} else {
|
||||
$result->headers[$header] = trim($value);
|
||||
}
|
||||
}
|
||||
|
||||
$responses = array(
|
||||
100 => 'Continue', 101 => 'Switching Protocols',
|
||||
200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content',
|
||||
300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect',
|
||||
400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Time-out', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Large', 415 => 'Unsupported Media Type', 416 => 'Requested range not satisfiable', 417 => 'Expectation Failed',
|
||||
500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported'
|
||||
);
|
||||
// RFC 2616 states that all unknown HTTP codes must be treated the same as the
|
||||
// base code in their class.
|
||||
if (!isset($responses[$code])) {
|
||||
$code = floor($code / 100) * 100;
|
||||
}
|
||||
|
||||
switch ($code) {
|
||||
case 200: // OK
|
||||
case 304: // Not modified
|
||||
break;
|
||||
case 301: // Moved permanently
|
||||
case 302: // Moved temporarily
|
||||
case 307: // Moved temporarily
|
||||
$location = $result->headers['Location'];
|
||||
|
||||
if ($retry) {
|
||||
$result = openid_http_request($result->headers['Location'], $headers, $method, $data, --$retry);
|
||||
$result->redirect_code = $result->code;
|
||||
}
|
||||
$result->redirect_url = $location;
|
||||
|
||||
break;
|
||||
default:
|
||||
$result->error = $text;
|
||||
}
|
||||
|
||||
$result->code = $code;
|
||||
return $result;
|
||||
}
|
||||
|
||||
function openid_is_allowed_provider($identityUrl): bool
|
||||
{
|
||||
$allowedProviders = api_get_configuration_value('auth_openid_allowed_providers');
|
||||
|
||||
if (false === $allowedProviders) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$host = parse_url($identityUrl, PHP_URL_HOST) ?: $identityUrl;
|
||||
|
||||
foreach ($allowedProviders as $provider) {
|
||||
if (strpos($provider, '*') !== false) {
|
||||
$regex = '/^' . str_replace('\*', '.*', preg_quote($provider, '/')) . '$/';
|
||||
|
||||
if (preg_match($regex, $host)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if ($host === $provider) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
420
main/auth/openid/openid.lib.php
Normal file
420
main/auth/openid/openid.lib.php
Normal file
@@ -0,0 +1,420 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
/**
|
||||
* OpenID utility functions. Taken from Drupal 6 code (from dries)
|
||||
* @package chamilo.auth.openid
|
||||
*/
|
||||
/**
|
||||
* Code
|
||||
*/
|
||||
// Diffie-Hellman Key Exchange Default Value.
|
||||
define('OPENID_DH_DEFAULT_MOD', '155172898181473697471232257763715539915724801' .
|
||||
'966915404479707795314057629378541917580651227423698188993727816152646631' .
|
||||
'438561595825688188889951272158842675419950341258706556549803580104870537' .
|
||||
'681476726513255747040765857479291291572334510643245094715007229621094194' .
|
||||
'349783925984760375594985848253359305585439638443');
|
||||
|
||||
// Constants for Diffie-Hellman key exchange computations.
|
||||
define('OPENID_DH_DEFAULT_GEN', '2');
|
||||
define('OPENID_SHA1_BLOCKSIZE', 64);
|
||||
define('OPENID_RAND_SOURCE', '/dev/urandom');
|
||||
|
||||
// OpenID namespace URLs
|
||||
define('OPENID_NS_2_0', 'http://specs.openid.net/auth/2.0');
|
||||
define('OPENID_NS_1_1', 'http://openid.net/signon/1.1');
|
||||
define('OPENID_NS_1_0', 'http://openid.net/signon/1.0');
|
||||
|
||||
/**
|
||||
* Performs an HTTP 302 redirect (for the 1.x protocol).
|
||||
* This function should be deprecated for 1.8.6.2 needs documentation
|
||||
*/
|
||||
function openid_redirect_http($url, $message) {
|
||||
$query = array();
|
||||
foreach ($message as $key => $val) {
|
||||
$query[] = $key . '=' . urlencode($val);
|
||||
}
|
||||
$sep = (strpos($url, '?') === FALSE) ? '?' : '&';
|
||||
header('Location: ' . $url . $sep . implode('&', $query), TRUE, 302);
|
||||
//exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a js auto-submit redirect for (for the 2.x protocol)
|
||||
* This function should be deprecated for 1.8.6.2 needs documentation
|
||||
*/
|
||||
function openid_redirect($url, $message) {
|
||||
$output = '<html><head><title>' . get_lang('OpenIDRedirect') . "</title></head>\n<body>";
|
||||
$output .= '<form method="post" action="' . $url . '" id="openid-redirect-form">';
|
||||
foreach ($message as $key => $value) {
|
||||
$output .='<input type="hidden" name="' . $key . '" value="' . $value . '">';
|
||||
}
|
||||
$output .= '<noscript><input type="submit" name="submit" value="' . get_lang('Send') . '"/></noscript>';
|
||||
$output .= '</form>';
|
||||
$output .= '<script type="text/javascript">document.getElementById("openid-redirect-form").submit();</script>';
|
||||
$output .= "</body></html>";
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given identifier is an XRI ID.
|
||||
*/
|
||||
function _openid_is_xri($identifier) {
|
||||
$firstchar = substr($identifier, 0, 1);
|
||||
if ($firstchar == "@" || $firstchar == "=")
|
||||
return TRUE;
|
||||
|
||||
if (stristr($identifier, 'xri://') !== FALSE) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize the given identifier as per spec.
|
||||
*/
|
||||
function _openid_normalize($identifier) {
|
||||
if (_openid_is_xri($identifier)) {
|
||||
return _openid_normalize_xri($identifier);
|
||||
} else {
|
||||
return _openid_normalize_url($identifier);
|
||||
}
|
||||
}
|
||||
|
||||
function _openid_normalize_xri($xri) {
|
||||
$normalized_xri = $xri;
|
||||
if (stristr($xri, 'xri://') !== FALSE) {
|
||||
$normalized_xri = substr($xri, 6);
|
||||
}
|
||||
return $normalized_xri;
|
||||
}
|
||||
|
||||
function _openid_normalize_url($url) {
|
||||
$normalized_url = $url;
|
||||
|
||||
if (stristr($url, '://') === FALSE) {
|
||||
$normalized_url = 'http://' . $url;
|
||||
}
|
||||
|
||||
if (substr_count($normalized_url, '/') < 3) {
|
||||
$normalized_url .= '/';
|
||||
}
|
||||
|
||||
return $normalized_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a serialized message packet as per spec: $key:$value\n .
|
||||
*/
|
||||
function _openid_create_message($data) {
|
||||
$serialized = '';
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
if ((strpos($key, ':') !== FALSE) || (strpos($key, "\n") !== FALSE) || (strpos($value, "\n") !== FALSE)) {
|
||||
return null;
|
||||
}
|
||||
$serialized .= "$key:$value\n";
|
||||
}
|
||||
return $serialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a message from _openid_create_message for HTTP Post
|
||||
* @param null|string $message
|
||||
*/
|
||||
function _openid_encode_message($message) {
|
||||
$encoded_message = '';
|
||||
|
||||
$items = explode("\n", $message);
|
||||
foreach ($items as $item) {
|
||||
$parts = explode(':', $item, 2);
|
||||
|
||||
if (count($parts) == 2) {
|
||||
if ($encoded_message != '') {
|
||||
$encoded_message .= '&';
|
||||
}
|
||||
$encoded_message .= rawurlencode(trim($parts[0])) . '=' . rawurlencode(trim($parts[1]));
|
||||
}
|
||||
}
|
||||
|
||||
return $encoded_message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a direct communication message
|
||||
* into an associative array.
|
||||
*/
|
||||
function _openid_parse_message($message) {
|
||||
$parsed_message = array();
|
||||
|
||||
$items = explode("\n", $message);
|
||||
foreach ($items as $item) {
|
||||
$parts = explode(':', $item, 2);
|
||||
|
||||
if (count($parts) == 2) {
|
||||
$parsed_message[$parts[0]] = $parts[1];
|
||||
}
|
||||
}
|
||||
|
||||
return $parsed_message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a nonce value - formatted per OpenID spec.
|
||||
*/
|
||||
function _openid_nonce() {
|
||||
// YYYY-MM-DDThh:mm:ssTZD UTC, plus some optional extra unique chars
|
||||
return gmstrftime('%Y-%m-%dT%H:%M:%S%Z') .
|
||||
chr(mt_rand(0, 25) + 65) .
|
||||
chr(mt_rand(0, 25) + 65) .
|
||||
chr(mt_rand(0, 25) + 65) .
|
||||
chr(mt_rand(0, 25) + 65);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull the href attribute out of an html link element.
|
||||
* @param string $rel
|
||||
*/
|
||||
function _openid_link_href($rel, $html) {
|
||||
$rel = preg_quote($rel);
|
||||
preg_match('|<link\s+rel=["\'](.*)' . $rel . '(.*)["\'](.*)/?>|iU', $html, $matches);
|
||||
if (isset($matches[3])) {
|
||||
preg_match('|href=["\']([^"]+)["\']|iU', $matches[0], $href);
|
||||
return trim($href[1]);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull the http-equiv attribute out of an html meta element
|
||||
* @param string $equiv
|
||||
*/
|
||||
function _openid_meta_httpequiv($equiv, $html) {
|
||||
preg_match('|<meta\s+http-equiv=["\']' . $equiv . '["\'](.*)/?>|iU', $html, $matches);
|
||||
if (isset($matches[1])) {
|
||||
preg_match('|content=["\']([^"]+)["\']|iU', $matches[1], $content);
|
||||
return $content[1];
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign certain keys in a message
|
||||
* @param $association - object loaded from openid_association or openid_server_association table
|
||||
* - important fields are ->assoc_type and ->mac_key
|
||||
* @param $message_array - array of entire message about to be sent
|
||||
* @param $keys_to_sign - keys in the message to include in signature (without
|
||||
* 'openid.' appended)
|
||||
*/
|
||||
function _openid_signature($association, $message_array, $keys_to_sign) {
|
||||
$signature = '';
|
||||
$sign_data = array();
|
||||
|
||||
foreach ($keys_to_sign as $key) {
|
||||
if (isset($message_array['openid.' . $key])) {
|
||||
$sign_data[$key] = $message_array['openid.' . $key];
|
||||
}
|
||||
}
|
||||
|
||||
$message = _openid_create_message($sign_data);
|
||||
$secret = base64_decode($association->mac_key);
|
||||
$signature = _openid_hmac($secret, $message);
|
||||
|
||||
return base64_encode($signature);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param null|string $text
|
||||
*/
|
||||
function _openid_hmac($key, $text) {
|
||||
if (strlen($key) > OPENID_SHA1_BLOCKSIZE) {
|
||||
$key = _openid_sha1($key, true);
|
||||
}
|
||||
|
||||
$key = str_pad($key, OPENID_SHA1_BLOCKSIZE, chr(0x00));
|
||||
$ipad = str_repeat(chr(0x36), OPENID_SHA1_BLOCKSIZE);
|
||||
$opad = str_repeat(chr(0x5c), OPENID_SHA1_BLOCKSIZE);
|
||||
$hash1 = _openid_sha1(($key ^ $ipad) . $text, true);
|
||||
$hmac = _openid_sha1(($key ^ $opad) . $hash1, true);
|
||||
|
||||
return $hmac;
|
||||
}
|
||||
|
||||
function _openid_sha1($text) {
|
||||
$hex = sha1($text);
|
||||
$raw = '';
|
||||
for ($i = 0; $i < 40; $i += 2) {
|
||||
$hexcode = substr($hex, $i, 2);
|
||||
$charcode = (int) base_convert($hexcode, 16, 10);
|
||||
$raw .= chr($charcode);
|
||||
}
|
||||
return $raw;
|
||||
}
|
||||
|
||||
function _openid_dh_base64_to_long($str) {
|
||||
$b64 = base64_decode($str);
|
||||
|
||||
return _openid_dh_binary_to_long($b64);
|
||||
}
|
||||
|
||||
function _openid_dh_long_to_base64($str) {
|
||||
return base64_encode(_openid_dh_long_to_binary($str));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $str
|
||||
*/
|
||||
function _openid_dh_binary_to_long($str) {
|
||||
$bytes = array_merge(unpack('C*', $str));
|
||||
|
||||
$n = 0;
|
||||
foreach ($bytes as $byte) {
|
||||
$n = bcmul($n, pow(2, 8));
|
||||
$n = bcadd($n, $byte);
|
||||
}
|
||||
|
||||
return $n;
|
||||
}
|
||||
|
||||
function _openid_dh_long_to_binary($long) {
|
||||
$cmp = bccomp($long, 0);
|
||||
if ($cmp < 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ($cmp == 0) {
|
||||
return "\x00";
|
||||
}
|
||||
|
||||
$bytes = array();
|
||||
|
||||
while (bccomp($long, 0) > 0) {
|
||||
array_unshift($bytes, bcmod($long, 256));
|
||||
$long = bcdiv($long, pow(2, 8));
|
||||
}
|
||||
|
||||
if ($bytes && ($bytes[0] > 127)) {
|
||||
array_unshift($bytes, 0);
|
||||
}
|
||||
|
||||
$string = '';
|
||||
foreach ($bytes as $byte) {
|
||||
$string .= pack('C', $byte);
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $secret
|
||||
*/
|
||||
function _openid_dh_xorsecret($shared, $secret) {
|
||||
$dh_shared_str = _openid_dh_long_to_binary($shared);
|
||||
$sha1_dh_shared = _openid_sha1($dh_shared_str);
|
||||
$xsecret = "";
|
||||
for ($i = 0; $i < strlen($secret); $i++) {
|
||||
$xsecret .= chr(ord($secret[$i]) ^ ord($sha1_dh_shared[$i]));
|
||||
}
|
||||
|
||||
return $xsecret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $stop
|
||||
*/
|
||||
function _openid_dh_rand($stop) {
|
||||
static $duplicate_cache = array();
|
||||
|
||||
// Used as the key for the duplicate cache
|
||||
$rbytes = _openid_dh_long_to_binary($stop);
|
||||
|
||||
if (array_key_exists($rbytes, $duplicate_cache)) {
|
||||
list($duplicate, $nbytes) = $duplicate_cache[$rbytes];
|
||||
} else {
|
||||
if ($rbytes[0] == "\x00") {
|
||||
$nbytes = strlen($rbytes) - 1;
|
||||
} else {
|
||||
$nbytes = strlen($rbytes);
|
||||
}
|
||||
|
||||
$mxrand = bcpow(256, $nbytes);
|
||||
|
||||
// If we get a number less than this, then it is in the
|
||||
// duplicated range.
|
||||
$duplicate = bcmod($mxrand, $stop);
|
||||
|
||||
if (count($duplicate_cache) > 10) {
|
||||
$duplicate_cache = array();
|
||||
}
|
||||
|
||||
$duplicate_cache[$rbytes] = array($duplicate, $nbytes);
|
||||
}
|
||||
|
||||
do {
|
||||
$bytes = "\x00" . _openid_get_bytes($nbytes);
|
||||
$n = _openid_dh_binary_to_long($bytes);
|
||||
// Keep looping if this value is in the low duplicated range.
|
||||
} while (bccomp($n, $duplicate) < 0);
|
||||
|
||||
return bcmod($n, $stop);
|
||||
}
|
||||
|
||||
function _openid_get_bytes($num_bytes) {
|
||||
static $f = null;
|
||||
$bytes = '';
|
||||
if (!isset($f)) {
|
||||
$f = @fopen(OPENID_RAND_SOURCE, "r");
|
||||
}
|
||||
if (!$f) {
|
||||
// pseudorandom used
|
||||
$bytes = '';
|
||||
for ($i = 0; $i < $num_bytes; $i += 4) {
|
||||
$bytes .= pack('L', mt_rand());
|
||||
}
|
||||
$bytes = substr($bytes, 0, $num_bytes);
|
||||
} else {
|
||||
$bytes = fread($f, $num_bytes);
|
||||
}
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix PHP's habit of replacing '.' by '_' in posted data.
|
||||
*/
|
||||
function _openid_fix_post(&$post) {
|
||||
//$extensions = module_invoke_all('openid', 'extension');
|
||||
foreach ($post as $key => $value) {
|
||||
if (strpos($key, 'openid_') === 0) {
|
||||
$fixed_key = str_replace('openid_', 'openid.', $key);
|
||||
$fixed_key = str_replace('openid.ns_', 'openid.ns.', $fixed_key);
|
||||
$fixed_key = str_replace('openid.sreg_', 'openid.sreg.', $fixed_key);
|
||||
//foreach ($extensions as $ext) {
|
||||
// $fixed_key = str_replace('openid.'.$ext.'_', 'openid.'.$ext.'.', $fixed_key);
|
||||
//}
|
||||
unset($post[$key]);
|
||||
$post[$fixed_key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide bcpowmod support for PHP4.
|
||||
*/
|
||||
if (!function_exists('bcpowmod')) {
|
||||
|
||||
function bcpowmod($base, $exp, $mod) {
|
||||
$square = bcmod($base, $mod);
|
||||
$result = 1;
|
||||
while (bccomp($exp, 0) > 0) {
|
||||
if (bcmod($exp, 2)) {
|
||||
$result = bcmod(bcmul($result, $square), $mod);
|
||||
}
|
||||
$square = bcmod(bcmul($square, $square), $mod);
|
||||
$exp = bcdiv($exp, 2);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
14
main/auth/openid/whatis.php
Normal file
14
main/auth/openid/whatis.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
/**
|
||||
* OpenID
|
||||
* @package chamilo.auth.openid
|
||||
*/
|
||||
/**
|
||||
* Code
|
||||
*/
|
||||
require_once '../../inc/global.inc.php';
|
||||
Display::display_header('OpenID', NULL);
|
||||
echo Display::page_header(get_lang('OpenIDWhatIs'));
|
||||
echo get_lang('OpenIDDescription');
|
||||
Display::display_footer();
|
||||
85
main/auth/openid/xrds.lib.php
Normal file
85
main/auth/openid/xrds.lib.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
/**
|
||||
* Parsing library for OpenID
|
||||
* @package chamilo.auth.openid
|
||||
*/
|
||||
/**
|
||||
* Code
|
||||
*/
|
||||
// Global variables to track parsing state
|
||||
$xrds_open_elements = array();
|
||||
$xrds_services = array();
|
||||
$xrds_current_service = array();
|
||||
|
||||
/**
|
||||
* Main entry point for parsing XRDS documents
|
||||
*/
|
||||
function xrds_parse($xml) {
|
||||
global $xrds_services;
|
||||
|
||||
$parser = xml_parser_create_ns();
|
||||
xml_set_element_handler($parser, '_xrds_element_start', '_xrds_element_end');
|
||||
xml_set_character_data_handler($parser, '_xrds_cdata');
|
||||
|
||||
xml_parse($parser, $xml);
|
||||
xml_parser_free($parser);
|
||||
|
||||
return $xrds_services;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parser callback functions
|
||||
*/
|
||||
function _xrds_element_start(&$parser, $name, $attribs) {
|
||||
global $xrds_open_elements;
|
||||
|
||||
$xrds_open_elements[] = _xrds_strip_namespace($name);
|
||||
}
|
||||
|
||||
function _xrds_element_end(&$parser, $name) {
|
||||
global $xrds_open_elements, $xrds_services, $xrds_current_service;
|
||||
|
||||
$name = _xrds_strip_namespace($name);
|
||||
if ($name == 'SERVICE') {
|
||||
if (in_array(OPENID_NS_2_0 .'/signon', $xrds_current_service['types']) ||
|
||||
in_array(OPENID_NS_2_0 .'/server', $xrds_current_service['types'])) {
|
||||
$xrds_current_service['version'] = 2;
|
||||
}
|
||||
elseif (in_array(OPENID_NS_1_1, $xrds_current_service['types']) ||
|
||||
in_array(OPENID_NS_1_0, $xrds_current_service['types'])) {
|
||||
$xrds_current_service['version'] = 1;
|
||||
}
|
||||
if (!empty($xrds_current_service['version'])) {
|
||||
$xrds_services[] = $xrds_current_service;
|
||||
}
|
||||
$xrds_current_service = array();
|
||||
}
|
||||
array_pop($xrds_open_elements);
|
||||
}
|
||||
|
||||
function _xrds_cdata(&$parser, $data) {
|
||||
global $xrds_open_elements, $xrds_services, $xrds_current_service;
|
||||
$path = strtoupper(implode('/', $xrds_open_elements));
|
||||
switch ($path) {
|
||||
case 'XRDS/XRD/SERVICE/TYPE':
|
||||
$xrds_current_service['types'][] = $data;
|
||||
break;
|
||||
case 'XRDS/XRD/SERVICE/URI':
|
||||
$xrds_current_service['uri'] = $data;
|
||||
break;
|
||||
case 'XRDS/XRD/SERVICE/DELEGATE':
|
||||
$xrds_current_service['delegate'] = $data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function _xrds_strip_namespace($name) {
|
||||
// Strip namespacing.
|
||||
$pos = strrpos($name, ':');
|
||||
if ($pos !== FALSE) {
|
||||
$name = substr($name, $pos + 1, strlen($name));
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
83
main/auth/pausetraining.php
Normal file
83
main/auth/pausetraining.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
$cidReset = true;
|
||||
require_once __DIR__.'/../inc/global.inc.php';
|
||||
|
||||
api_block_anonymous_users(true);
|
||||
|
||||
$allow = api_get_plugin_setting('pausetraining', 'tool_enable') === 'true';
|
||||
$allowPauseFormation = api_get_plugin_setting('pausetraining', 'allow_users_to_edit_pause_formation') === 'true';
|
||||
|
||||
if (false === $allow || false === $allowPauseFormation) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$userId = api_get_user_id();
|
||||
|
||||
$userInfo = api_get_user_info($userId);
|
||||
|
||||
$justification = '';
|
||||
$plugin = PauseTraining::create();
|
||||
|
||||
$form = new FormValidator('pausetraining');
|
||||
$form->addHeader($plugin->get_lang('PauseTraining'));
|
||||
|
||||
$extraField = new ExtraField('user');
|
||||
|
||||
$return = $extraField->addElements(
|
||||
$form,
|
||||
$userId,
|
||||
[],
|
||||
false,
|
||||
false,
|
||||
['pause_formation', 'start_pause_date', 'end_pause_date'],
|
||||
[],
|
||||
[],
|
||||
false,
|
||||
true
|
||||
);
|
||||
|
||||
$form->addRule(
|
||||
['extra_start_pause_date', 'extra_end_pause_date'],
|
||||
get_lang('StartDateShouldBeBeforeEndDate'),
|
||||
'date_compare',
|
||||
'lte'
|
||||
);
|
||||
|
||||
$form->addButtonSend(get_lang('Update'));
|
||||
if ($form->validate()) {
|
||||
$values = $form->getSubmitValues(1);
|
||||
$values['item_id'] = $userId;
|
||||
|
||||
if (!isset($values['extra_pause_formation'])) {
|
||||
$values['extra_pause_formation'] = 0;
|
||||
}
|
||||
$extraField = new ExtraFieldValue('user');
|
||||
$extraField->saveFieldValues($values, true, false, [], [], true);
|
||||
|
||||
Display::addFlash(Display::return_message(get_lang('Update')));
|
||||
header('Location: '.api_get_self());
|
||||
exit;
|
||||
}
|
||||
|
||||
$tabs = SocialManager::getHomeProfileTabs('pausetraining');
|
||||
$content = $tabs.$form->returnForm();
|
||||
|
||||
$tpl = new Template(get_lang('ModifyProfile'));
|
||||
|
||||
SocialManager::setSocialUserBlock($tpl, api_get_user_id(), 'home');
|
||||
$menu = SocialManager::show_social_menu(
|
||||
'home',
|
||||
null,
|
||||
api_get_user_id(),
|
||||
false,
|
||||
false
|
||||
);
|
||||
|
||||
$tpl->assign('social_menu_block', $menu);
|
||||
$tpl->assign('social_right_content', $content);
|
||||
$social_layout = $tpl->get_template('social/edit_profile.tpl');
|
||||
|
||||
$tpl->display($social_layout);
|
||||
928
main/auth/profile.php
Normal file
928
main/auth/profile.php
Normal file
@@ -0,0 +1,928 @@
|
||||
<?php
|
||||
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
use Chamilo\UserBundle\Entity\User;
|
||||
use ChamiloSession as Session;
|
||||
|
||||
/**
|
||||
* This file displays the user's profile,
|
||||
* optionally it allows users to modify their profile as well.
|
||||
*
|
||||
* See inc/conf/profile.conf.php to modify settings
|
||||
*/
|
||||
$cidReset = true;
|
||||
require_once __DIR__.'/../inc/global.inc.php';
|
||||
api_block_inactive_user();
|
||||
|
||||
$this_section = SECTION_MYPROFILE;
|
||||
$allowSocialTool = api_get_setting('allow_social_tool') === 'true';
|
||||
if ($allowSocialTool) {
|
||||
$this_section = SECTION_SOCIAL;
|
||||
}
|
||||
|
||||
$logInfo = [
|
||||
'tool' => 'profile',
|
||||
'action' => $this_section,
|
||||
];
|
||||
Event::registerLog($logInfo);
|
||||
|
||||
$_SESSION['this_section'] = $this_section;
|
||||
|
||||
if (!(isset($_user['user_id']) && $_user['user_id']) || api_is_anonymous($_user['user_id'], true)) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$htmlHeadXtra[] = api_get_password_checker_js('#username', '#password1');
|
||||
$htmlHeadXtra[] = api_get_css_asset('cropper/dist/cropper.min.css');
|
||||
$htmlHeadXtra[] = api_get_asset('cropper/dist/cropper.min.js');
|
||||
$htmlHeadXtra[] = '<script>
|
||||
$(function() {
|
||||
$("#id_generate_api_key").on("click", function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
$.ajax({
|
||||
contentType: "application/x-www-form-urlencoded",
|
||||
type: "POST",
|
||||
url: "'.api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=generate_api_key",
|
||||
data: "num_key_id="+"",
|
||||
success: function(datos) {
|
||||
$("#div_api_key").html(datos);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function confirmation(name) {
|
||||
if (confirm("'.get_lang('AreYouSureToDeleteJS', '').' " + name + " ?")) {
|
||||
document.forms["profile"].submit();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function show_image(image,width,height) {
|
||||
width = parseInt(width) + 20;
|
||||
height = parseInt(height) + 20;
|
||||
window_x = window.open(image,\'windowX\',\'width=\'+ width + \', height=\'+ height + \'\');
|
||||
}
|
||||
</script>';
|
||||
|
||||
$jquery_ready_content = '';
|
||||
if (api_get_setting('allow_message_tool') === 'true') {
|
||||
$jquery_ready_content = <<<EOF
|
||||
$(".message-content .message-delete").click(function(){
|
||||
$(this).parents(".message-content").animate({ opacity: "hide" }, "slow");
|
||||
$(".message-view").animate({ opacity: "show" }, "slow");
|
||||
});
|
||||
EOF;
|
||||
}
|
||||
|
||||
$tool_name = is_profile_editable() ? get_lang('ModifProfile') : get_lang('ViewProfile');
|
||||
$table_user = Database::get_main_table(TABLE_MAIN_USER);
|
||||
|
||||
/*
|
||||
* Get initial values for all fields.
|
||||
*/
|
||||
$user_data = $originalUserInfo = api_get_user_info(
|
||||
api_get_user_id(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
);
|
||||
$currentUser = api_get_user_entity($user_data['id']);
|
||||
$array_list_key = UserManager::get_api_keys(api_get_user_id());
|
||||
$id_temp_key = UserManager::get_api_key_id(api_get_user_id(), 'dokeos');
|
||||
$value_array = [];
|
||||
if (isset($array_list_key[$id_temp_key])) {
|
||||
$value_array = $array_list_key[$id_temp_key];
|
||||
}
|
||||
$user_data['api_key_generate'] = $value_array;
|
||||
|
||||
if ($user_data !== false) {
|
||||
if (api_get_setting('login_is_email') === 'true') {
|
||||
$user_data['username'] = $user_data['email'];
|
||||
}
|
||||
if (is_null($user_data['language'])) {
|
||||
$user_data['language'] = api_get_setting('platformLanguage');
|
||||
}
|
||||
}
|
||||
|
||||
$form = new FormValidator('profile');
|
||||
|
||||
if (api_is_western_name_order()) {
|
||||
// FIRST NAME and LAST NAME
|
||||
$form->addElement('text', 'firstname', get_lang('FirstName'), ['size' => 40]);
|
||||
$form->addElement('text', 'lastname', get_lang('LastName'), ['size' => 40]);
|
||||
} else {
|
||||
// LAST NAME and FIRST NAME
|
||||
$form->addElement('text', 'lastname', get_lang('LastName'), ['size' => 40]);
|
||||
$form->addElement('text', 'firstname', get_lang('FirstName'), ['size' => 40]);
|
||||
}
|
||||
if (api_get_setting('profile', 'name') !== 'true') {
|
||||
$form->freeze(['lastname', 'firstname']);
|
||||
}
|
||||
$form->applyFilter(['lastname', 'firstname'], 'stripslashes');
|
||||
$form->applyFilter(['lastname', 'firstname'], 'trim');
|
||||
$form->applyFilter(['lastname', 'firstname'], 'html_filter');
|
||||
$form->addRule('lastname', get_lang('ThisFieldIsRequired'), 'required');
|
||||
$form->addRule('firstname', get_lang('ThisFieldIsRequired'), 'required');
|
||||
|
||||
// USERNAME
|
||||
$form->addElement(
|
||||
'text',
|
||||
'username',
|
||||
get_lang('UserName'),
|
||||
[
|
||||
'id' => 'username',
|
||||
'maxlength' => USERNAME_MAX_LENGTH,
|
||||
'size' => USERNAME_MAX_LENGTH,
|
||||
]
|
||||
);
|
||||
|
||||
if (api_get_setting('profile', 'login') !== 'true' || api_get_setting('login_is_email') === 'true') {
|
||||
$form->freeze('username');
|
||||
}
|
||||
$form->applyFilter('username', 'stripslashes');
|
||||
$form->applyFilter('username', 'trim');
|
||||
$form->addRule('username', get_lang('ThisFieldIsRequired'), 'required');
|
||||
$form->addRule('username', get_lang('UsernameWrong'), 'username');
|
||||
$form->addRule('username', get_lang('UserTaken'), 'username_available', $user_data['username']);
|
||||
|
||||
// OFFICIAL CODE
|
||||
if (defined('CONFVAL_ASK_FOR_OFFICIAL_CODE') && CONFVAL_ASK_FOR_OFFICIAL_CODE === true) {
|
||||
$form->addElement('text', 'official_code', get_lang('OfficialCode'), ['size' => 40]);
|
||||
if (api_get_setting('profile', 'officialcode') !== 'true') {
|
||||
$form->freeze('official_code');
|
||||
}
|
||||
$form->applyFilter('official_code', 'stripslashes');
|
||||
$form->applyFilter('official_code', 'trim');
|
||||
$form->applyFilter('official_code', 'html_filter');
|
||||
if (api_get_setting('registration', 'officialcode') === 'true' &&
|
||||
api_get_setting('profile', 'officialcode') === 'true'
|
||||
) {
|
||||
$form->addRule('official_code', get_lang('ThisFieldIsRequired'), 'required');
|
||||
}
|
||||
}
|
||||
|
||||
// EMAIL
|
||||
$form->addElement('email', 'email', get_lang('Email'), ['size' => 40]);
|
||||
if (api_get_setting('profile', 'email') !== 'true') {
|
||||
$form->freeze('email');
|
||||
}
|
||||
|
||||
if (api_get_setting('registration', 'email') === 'true' && api_get_setting('profile', 'email') === 'true') {
|
||||
$form->applyFilter('email', 'stripslashes');
|
||||
$form->applyFilter('email', 'trim');
|
||||
$form->addRule('email', get_lang('ThisFieldIsRequired'), 'required');
|
||||
$form->addRule('email', get_lang('EmailWrong'), 'email');
|
||||
}
|
||||
|
||||
// OPENID URL
|
||||
if (is_profile_editable() && api_get_setting('openid_authentication') === 'true') {
|
||||
$form->addElement('text', 'openid', get_lang('OpenIDURL'), ['size' => 40]);
|
||||
if (api_get_setting('profile', 'openid') !== 'true') {
|
||||
$form->freeze('openid');
|
||||
}
|
||||
$form->applyFilter('openid', 'trim');
|
||||
}
|
||||
|
||||
// PHONE
|
||||
$form->addElement('text', 'phone', get_lang('Phone'), ['size' => 20]);
|
||||
if (api_get_setting('profile', 'phone') !== 'true') {
|
||||
$form->freeze('phone');
|
||||
}
|
||||
$form->applyFilter('phone', 'stripslashes');
|
||||
$form->applyFilter('phone', 'trim');
|
||||
$form->applyFilter('phone', 'html_filter');
|
||||
|
||||
// PICTURE
|
||||
if (is_profile_editable() && api_get_setting('profile', 'picture') == 'true') {
|
||||
$form->addFile(
|
||||
'picture',
|
||||
[
|
||||
$user_data['picture_uri'] != '' ? get_lang('UpdateImage') : get_lang('AddImage'),
|
||||
get_lang('OnlyImagesAllowed'),
|
||||
],
|
||||
[
|
||||
'id' => 'picture',
|
||||
'class' => 'picture-form',
|
||||
'crop_image' => true,
|
||||
'crop_ratio' => '1 / 1',
|
||||
'accept' => 'image/*',
|
||||
]
|
||||
);
|
||||
|
||||
$form->addProgress();
|
||||
if (!empty($user_data['picture_uri'])) {
|
||||
$form->addElement('checkbox', 'remove_picture', null, get_lang('DelImage'));
|
||||
}
|
||||
$allowed_picture_types = api_get_supported_image_extensions(false);
|
||||
$form->addRule(
|
||||
'picture',
|
||||
get_lang('OnlyImagesAllowed').' ('.implode(', ', $allowed_picture_types).')',
|
||||
'filetype',
|
||||
$allowed_picture_types
|
||||
);
|
||||
}
|
||||
|
||||
// LANGUAGE
|
||||
$form->addSelectLanguage('language', get_lang('Language'));
|
||||
if (api_get_setting('profile', 'language') !== 'true') {
|
||||
$form->freeze('language');
|
||||
}
|
||||
|
||||
// THEME
|
||||
if (is_profile_editable() && api_get_setting('user_selected_theme') === 'true') {
|
||||
$form->addElement('SelectTheme', 'theme', get_lang('Theme'));
|
||||
if (api_get_setting('profile', 'theme') !== 'true') {
|
||||
$form->freeze('theme');
|
||||
}
|
||||
$form->applyFilter('theme', 'trim');
|
||||
}
|
||||
|
||||
// EXTENDED PROFILE this make the page very slow!
|
||||
if (api_get_setting('extended_profile') === 'true') {
|
||||
$width_extended_profile = 500;
|
||||
// MY PERSONAL OPEN AREA
|
||||
$form->addHtmlEditor(
|
||||
'openarea',
|
||||
[get_lang('MyPersonalOpenArea'), get_lang('MyPersonalOpenAreaHelp')],
|
||||
false,
|
||||
false,
|
||||
[
|
||||
'ToolbarSet' => 'Profile',
|
||||
'Width' => $width_extended_profile,
|
||||
'Height' => '350',
|
||||
]
|
||||
);
|
||||
// MY COMPETENCES
|
||||
$form->addHtmlEditor(
|
||||
'competences',
|
||||
[get_lang('MyCompetences'), get_lang('MyCompetencesHelp')],
|
||||
false,
|
||||
false,
|
||||
[
|
||||
'ToolbarSet' => 'Profile',
|
||||
'Width' => $width_extended_profile,
|
||||
'Height' => '130',
|
||||
]
|
||||
);
|
||||
// MY DIPLOMAS
|
||||
$form->addHtmlEditor(
|
||||
'diplomas',
|
||||
[get_lang('MyDiplomas'), get_lang('MyDiplomasHelp')],
|
||||
false,
|
||||
false,
|
||||
[
|
||||
'ToolbarSet' => 'Profile',
|
||||
'Width' => $width_extended_profile,
|
||||
'Height' => '130',
|
||||
]
|
||||
);
|
||||
// WHAT I AM ABLE TO TEACH
|
||||
$form->addHtmlEditor(
|
||||
'teach',
|
||||
[get_lang('MyTeach'), get_lang('MyTeachingCapabilitiesHelp')],
|
||||
false,
|
||||
false,
|
||||
[
|
||||
'ToolbarSet' => 'Profile',
|
||||
'Width' => $width_extended_profile,
|
||||
'Height' => '130',
|
||||
]
|
||||
);
|
||||
|
||||
// MY PRODUCTIONS
|
||||
$form->addElement('file', 'production', [get_lang('MyProductions'), get_lang('MyProductionsHelp')]);
|
||||
if ($production_list = UserManager::build_production_list(api_get_user_id(), '', true)) {
|
||||
$form->addElement('static', 'productions_list', null, $production_list);
|
||||
}
|
||||
// openarea is untrimmed for maximum openness
|
||||
$form->applyFilter(['competences', 'diplomas', 'teach', 'openarea'], 'stripslashes');
|
||||
$form->applyFilter(['competences', 'diplomas', 'teach'], 'trim');
|
||||
}
|
||||
|
||||
$showPassword = is_platform_authentication();
|
||||
$links = api_get_configuration_value('auth_password_links');
|
||||
$extraLink = '';
|
||||
if (!empty($links) &&
|
||||
isset($links['profiles']) &&
|
||||
isset($links['profiles'][$user_data['status']]) &&
|
||||
isset($links['profiles'][$user_data['status']][$user_data['auth_source']])
|
||||
) {
|
||||
$extraUserConditions = $links['profiles'][$user_data['status']][$user_data['auth_source']];
|
||||
if (isset($extraUserConditions['show_password_field'])) {
|
||||
$showPassword = $extraUserConditions['show_password_field'];
|
||||
}
|
||||
|
||||
if (isset($extraUserConditions['extra_link'])) {
|
||||
$extraLink = $extraUserConditions['extra_link'];
|
||||
}
|
||||
}
|
||||
|
||||
// PASSWORD, if auth_source is platform
|
||||
$allow_users_to_change_email_with_no_password = true;
|
||||
if (is_platform_authentication() &&
|
||||
api_get_setting('allow_users_to_change_email_with_no_password') == 'false'
|
||||
) {
|
||||
$allow_users_to_change_email_with_no_password = false;
|
||||
}
|
||||
if (!$allow_users_to_change_email_with_no_password) {
|
||||
$passwordExtraCommentForPasswordChange = get_lang('ToChangeYourEmailMustTypeYourPassword').". ";
|
||||
}
|
||||
|
||||
if ($showPassword &&
|
||||
is_profile_editable() &&
|
||||
api_get_setting('profile', 'password') === 'true'
|
||||
) {
|
||||
$form->addElement(
|
||||
'password',
|
||||
'password0',
|
||||
[get_lang('Pass'), $passwordExtraCommentForPasswordChange.get_lang('TypeCurrentPassword')],
|
||||
[
|
||||
'size' => 40,
|
||||
'show_hide' => true,
|
||||
]
|
||||
);
|
||||
$form->addElement(
|
||||
'password',
|
||||
'password1',
|
||||
get_lang('NewPass'),
|
||||
[
|
||||
'id' => 'password1',
|
||||
'size' => 40,
|
||||
'show_hide' => true,
|
||||
'placeholder' => get_lang('EnterYourNewPassword'),
|
||||
]
|
||||
);
|
||||
$form->addElement(
|
||||
'password',
|
||||
'password2',
|
||||
[get_lang('Confirmation'), get_lang('RepeatYourNewPassword')],
|
||||
[
|
||||
'size' => 40,
|
||||
'show_hide' => true,
|
||||
]
|
||||
);
|
||||
// user must enter identical password twice so we can prevent some user errors
|
||||
$form->addRule(['password1', 'password2'], get_lang('PassTwo'), 'compare');
|
||||
$form->addPasswordRule('password1');
|
||||
$form->addNoSamePasswordRule('password1', $currentUser);
|
||||
} elseif (!$allow_users_to_change_email_with_no_password) {
|
||||
$form->addElement(
|
||||
'password',
|
||||
'password0',
|
||||
[get_lang('Pass'), $passwordExtraCommentForPasswordChange],
|
||||
[
|
||||
'size' => 40,
|
||||
'show_hide' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
$form->addHtml($extraLink);
|
||||
|
||||
$extraField = new ExtraField('user');
|
||||
$return = $extraField->addElements($form, api_get_user_id(), ['pause_formation', 'start_pause_date', 'end_pause_date']);
|
||||
$jquery_ready_content = $return['jquery_ready_content'];
|
||||
|
||||
// the $jquery_ready_content variable collects all functions that
|
||||
// will be load in the $(document).ready javascript function
|
||||
$htmlHeadXtra[] = '<script>
|
||||
$(function() {
|
||||
'.$jquery_ready_content.'
|
||||
});
|
||||
</script>';
|
||||
|
||||
if (api_get_setting('profile', 'apikeys') == 'true') {
|
||||
$form->addElement('html', '<div id="div_api_key">');
|
||||
$form->addElement(
|
||||
'text',
|
||||
'api_key_generate',
|
||||
get_lang('MyApiKey'),
|
||||
['size' => 40, 'id' => 'id_api_key_generate']
|
||||
);
|
||||
$form->addElement('html', '</div>');
|
||||
$form->addButton(
|
||||
'generate_api_key',
|
||||
get_lang('GenerateApiKey'),
|
||||
'cogs',
|
||||
'default',
|
||||
'default',
|
||||
null,
|
||||
['id' => 'id_generate_api_key']
|
||||
);
|
||||
}
|
||||
$form->addHidden('origin', 'profile');
|
||||
// SUBMIT
|
||||
if (is_profile_editable()) {
|
||||
$form->addButtonUpdate(get_lang('SaveSettings'), 'apply_change');
|
||||
} else {
|
||||
$form->freeze();
|
||||
}
|
||||
|
||||
// Student cannot modified their user conditions
|
||||
$extraConditions = api_get_configuration_value('show_conditions_to_user');
|
||||
if ($extraConditions && isset($extraConditions['conditions'])) {
|
||||
$extraConditions = $extraConditions['conditions'];
|
||||
foreach ($extraConditions as $condition) {
|
||||
$element = $form->getElement('extra_'.$condition['variable']);
|
||||
if ($element) {
|
||||
$element->freeze();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$form->setDefaults($user_data);
|
||||
|
||||
$filtered_extension = false;
|
||||
|
||||
if ($form->validate()) {
|
||||
$hook = HookUpdateUser::create();
|
||||
|
||||
if ($hook) {
|
||||
$hook->notifyUpdateUser(HOOK_EVENT_TYPE_PRE);
|
||||
}
|
||||
|
||||
$wrong_current_password = false;
|
||||
$user_data = $form->getSubmitValues(1);
|
||||
$user_data['item_id'] = api_get_user_id();
|
||||
/** @var User $user */
|
||||
$user = UserManager::getRepository()->find(api_get_user_id());
|
||||
|
||||
// set password if a new one was provided
|
||||
$validPassword = false;
|
||||
$passwordWasChecked = false;
|
||||
|
||||
if ($user &&
|
||||
(!empty($user_data['password0']) &&
|
||||
!empty($user_data['password1'])) ||
|
||||
(!empty($user_data['password0']) &&
|
||||
api_get_setting('profile', 'email') == 'true')
|
||||
) {
|
||||
$passwordWasChecked = true;
|
||||
$validPassword = UserManager::checkPassword(
|
||||
$user->getPassword(),
|
||||
$user_data['password0'],
|
||||
$user->getSalt(),
|
||||
$user->getId()
|
||||
);
|
||||
|
||||
if ($validPassword) {
|
||||
$password = $user_data['password1'];
|
||||
} else {
|
||||
Display::addFlash(
|
||||
Display::return_message(
|
||||
get_lang('CurrentPasswordEmptyOrIncorrect'),
|
||||
'warning',
|
||||
false
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$allow_users_to_change_email_with_no_password = true;
|
||||
if (is_platform_authentication() &&
|
||||
api_get_setting('allow_users_to_change_email_with_no_password') == 'false'
|
||||
) {
|
||||
$allow_users_to_change_email_with_no_password = false;
|
||||
}
|
||||
|
||||
// If user sending the email to be changed (input available and not frozen )
|
||||
if (api_get_setting('profile', 'email') == 'true') {
|
||||
if ($allow_users_to_change_email_with_no_password) {
|
||||
if (!check_user_email($user_data['email'])) {
|
||||
$changeemail = $user_data['email'];
|
||||
}
|
||||
} else {
|
||||
// Normal behaviour
|
||||
if (!check_user_email($user_data['email']) && $validPassword) {
|
||||
$changeemail = $user_data['email'];
|
||||
}
|
||||
|
||||
if (!check_user_email($user_data['email']) && empty($user_data['password0'])) {
|
||||
Display::addFlash(
|
||||
Display::return_message(
|
||||
get_lang('ToChangeYourEmailMustTypeYourPassword'),
|
||||
'error',
|
||||
false
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Upload picture if a new one is provided
|
||||
if ($_FILES['picture']['size']) {
|
||||
$new_picture = UserManager::update_user_picture(
|
||||
api_get_user_id(),
|
||||
$_FILES['picture']['name'],
|
||||
$_FILES['picture']['tmp_name'],
|
||||
$user_data['picture_crop_result']
|
||||
);
|
||||
|
||||
if ($new_picture) {
|
||||
$user_data['picture_uri'] = $new_picture;
|
||||
|
||||
Display::addFlash(
|
||||
Display::return_message(
|
||||
get_lang('PictureUploaded'),
|
||||
'normal',
|
||||
false
|
||||
)
|
||||
);
|
||||
}
|
||||
} elseif (!empty($user_data['remove_picture'])) {
|
||||
// remove existing picture if asked
|
||||
UserManager::deleteUserPicture(api_get_user_id());
|
||||
$user_data['picture_uri'] = '';
|
||||
}
|
||||
|
||||
// Remove production.
|
||||
if (isset($user_data['remove_production']) &&
|
||||
is_array($user_data['remove_production'])
|
||||
) {
|
||||
foreach (array_keys($user_data['remove_production']) as $production) {
|
||||
UserManager::remove_user_production(api_get_user_id(), urldecode($production));
|
||||
}
|
||||
if ($production_list = UserManager::build_production_list(api_get_user_id(), true, true)) {
|
||||
$form->insertElementBefore(
|
||||
$form->createElement('static', null, null, $production_list),
|
||||
'productions_list'
|
||||
);
|
||||
}
|
||||
$form->removeElement('productions_list');
|
||||
Display::addFlash(
|
||||
Display::return_message(get_lang('FileDeleted'), 'normal', false)
|
||||
);
|
||||
}
|
||||
|
||||
// upload production if a new one is provided
|
||||
if (isset($_FILES['production']) && $_FILES['production']['size']) {
|
||||
$res = upload_user_production(api_get_user_id());
|
||||
if (!$res) {
|
||||
//it's a bit excessive to assume the extension is the reason why
|
||||
// upload_user_production() returned false, but it's true in most cases
|
||||
$filtered_extension = true;
|
||||
} else {
|
||||
Display::addFlash(
|
||||
Display::return_message(
|
||||
get_lang('ProductionUploaded'),
|
||||
'normal',
|
||||
false
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// remove values that shouldn't go in the database
|
||||
unset(
|
||||
$user_data['password0'],
|
||||
$user_data['password1'],
|
||||
$user_data['password2'],
|
||||
$user_data['MAX_FILE_SIZE'],
|
||||
$user_data['remove_picture'],
|
||||
$user_data['apply_change'],
|
||||
$user_data['email']
|
||||
);
|
||||
|
||||
// Following RFC2396 (http://www.faqs.org/rfcs/rfc2396.html), a URI uses ':' as a reserved character
|
||||
// we can thus ensure the URL doesn't contain any scheme name by searching for ':' in the string
|
||||
$my_user_openid = isset($user_data['openid']) ? $user_data['openid'] : '';
|
||||
if (!preg_match('/^[^:]*:\/\/.*$/', $my_user_openid)) {
|
||||
//ensure there is at least a http:// scheme in the URI provided
|
||||
$user_data['openid'] = 'http://'.$my_user_openid;
|
||||
}
|
||||
$extras = [];
|
||||
|
||||
//Checking the user language
|
||||
$languages = api_get_languages();
|
||||
if (!in_array($user_data['language'], $languages['folder'])) {
|
||||
$user_data['language'] = api_get_setting('platformLanguage');
|
||||
}
|
||||
$_SESSION['_user']['language'] = $user_data['language'];
|
||||
|
||||
//Only update values that are request by the "profile" setting
|
||||
$profile_list = api_get_setting('profile');
|
||||
//Adding missing variables
|
||||
|
||||
$available_values_to_modify = [];
|
||||
foreach ($profile_list as $key => $status) {
|
||||
if ($status == 'true') {
|
||||
switch ($key) {
|
||||
case 'login':
|
||||
$available_values_to_modify[] = 'username';
|
||||
break;
|
||||
case 'name':
|
||||
$available_values_to_modify[] = 'firstname';
|
||||
$available_values_to_modify[] = 'lastname';
|
||||
break;
|
||||
case 'picture':
|
||||
$available_values_to_modify[] = 'picture_uri';
|
||||
break;
|
||||
default:
|
||||
$available_values_to_modify[] = $key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Fixing missing variables
|
||||
$available_values_to_modify = array_merge(
|
||||
$available_values_to_modify,
|
||||
['competences', 'diplomas', 'openarea', 'teach', 'openid', 'address']
|
||||
);
|
||||
|
||||
// build SQL query
|
||||
$sql = "UPDATE $table_user SET";
|
||||
unset($user_data['api_key_generate']);
|
||||
|
||||
foreach ($user_data as $key => $value) {
|
||||
if (substr($key, 0, 6) === 'extra_') { //an extra field
|
||||
continue;
|
||||
} elseif (strpos($key, 'remove_extra_') !== false) {
|
||||
} else {
|
||||
if (in_array($key, $available_values_to_modify)) {
|
||||
$sql .= " $key = '".Database::escape_string($value)."',";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$changePassword = false;
|
||||
// Change email
|
||||
if ($allow_users_to_change_email_with_no_password) {
|
||||
if (isset($changeemail) && in_array('email', $available_values_to_modify)) {
|
||||
$sql .= " email = '".Database::escape_string($changeemail)."' ";
|
||||
}
|
||||
if (isset($password) && in_array('password', $available_values_to_modify)) {
|
||||
$changePassword = true;
|
||||
}
|
||||
} else {
|
||||
if (isset($changeemail) && !isset($password) && in_array('email', $available_values_to_modify)) {
|
||||
$sql .= " email = '".Database::escape_string($changeemail)."'";
|
||||
} else {
|
||||
if (isset($password) && in_array('password', $available_values_to_modify)) {
|
||||
if (isset($changeemail) && in_array('email', $available_values_to_modify)) {
|
||||
$sql .= " email = '".Database::escape_string($changeemail)."' ";
|
||||
}
|
||||
$changePassword = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sql = rtrim($sql, ',');
|
||||
if ($changePassword && !empty($password)) {
|
||||
UserManager::updatePassword(api_get_user_id(), $password);
|
||||
if (api_get_configuration_value('security_password_rotate_days') > 0) {
|
||||
$date = api_get_local_time(
|
||||
null,
|
||||
'UTC',
|
||||
'UTC',
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
'Y-m-d H:i:s'
|
||||
);
|
||||
$extraFieldValue = new ExtraFieldValue('user');
|
||||
$extraFieldValue->save(
|
||||
[
|
||||
'item_id' => $user->getId(),
|
||||
'variable' => 'password_updated_at',
|
||||
'value' => $date,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (api_get_setting('profile', 'officialcode') === 'true' &&
|
||||
isset($user_data['official_code'])
|
||||
) {
|
||||
$sql .= ", official_code = '".Database::escape_string($user_data['official_code'])."'";
|
||||
}
|
||||
|
||||
$sql .= " WHERE id = '".api_get_user_id()."'";
|
||||
Database::query($sql);
|
||||
|
||||
if ($passwordWasChecked == false) {
|
||||
Display::addFlash(
|
||||
Display::return_message(get_lang('ProfileReg'), 'normal', false)
|
||||
);
|
||||
} else {
|
||||
if ($validPassword) {
|
||||
Display::addFlash(
|
||||
Display::return_message(get_lang('ProfileReg'), 'normal', false)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$extraField = new ExtraFieldValue('user');
|
||||
$extraField->saveFieldValues($user_data);
|
||||
|
||||
$userInfo = api_get_user_info(
|
||||
api_get_user_id(),
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
);
|
||||
Session::write('_user', $userInfo);
|
||||
|
||||
$notification = api_get_configuration_value('user_notification_settings');
|
||||
if (!empty($notification)) {
|
||||
foreach ($notification as $label => $notificationSettings) {
|
||||
$sendMessage = false;
|
||||
if (isset($notificationSettings['if_field_changes'])) {
|
||||
foreach ($notificationSettings['if_field_changes'] as $field) {
|
||||
if ($originalUserInfo[$field] != $userInfo[$field]) {
|
||||
$sendMessage = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($sendMessage) {
|
||||
$subject = $notificationSettings['subject'];
|
||||
$content = $notificationSettings['content'];
|
||||
$userInfo['extra_fields'] = UserManager::get_extra_user_data(api_get_user_id());
|
||||
$template = new Template();
|
||||
$template->assign('old', $originalUserInfo);
|
||||
$template->assign('new', $userInfo);
|
||||
$content = $template->fetch($template->get_template($content));
|
||||
|
||||
$emails = explode(',', $notificationSettings['email']);
|
||||
foreach ($emails as $email) {
|
||||
api_mail_html(
|
||||
'',
|
||||
$email,
|
||||
$subject,
|
||||
$content,
|
||||
$userInfo['complete_name'],
|
||||
$notificationSettings['sender_email'],
|
||||
[
|
||||
'reply_to' => [
|
||||
'mail' => $userInfo['mail'],
|
||||
'name' => $userInfo['complete_name'],
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($hook) {
|
||||
Database::getManager()->clear(User::class); // Avoid cache issue (user entity is used before)
|
||||
$user = api_get_user_entity(api_get_user_id()); // Get updated user info for hook event
|
||||
$hook->setEventData(['user' => $user]);
|
||||
$hook->notifyUpdateUser(HOOK_EVENT_TYPE_POST);
|
||||
}
|
||||
|
||||
Session::erase('system_timezone');
|
||||
|
||||
$url = api_get_self();
|
||||
header("Location: $url");
|
||||
exit;
|
||||
}
|
||||
|
||||
$actions = '';
|
||||
if ($allowSocialTool) {
|
||||
if (api_get_setting('extended_profile') === 'true') {
|
||||
if (api_get_setting('allow_message_tool') === 'true') {
|
||||
$actions .= '<a href="'.api_get_path(WEB_PATH).'main/social/profile.php">'.
|
||||
Display::return_icon('shared_profile.png', get_lang('ViewSharedProfile')).'</a>';
|
||||
$actions .= '<a href="'.api_get_path(WEB_PATH).'main/messages/inbox.php">'.
|
||||
Display::return_icon('inbox.png', get_lang('Messages')).'</a>';
|
||||
}
|
||||
$show = isset($_GET['show']) ? '&show='.(int) $_GET['show'] : '';
|
||||
|
||||
if (isset($_GET['type']) && $_GET['type'] === 'extended') {
|
||||
$actions .= '<a href="profile.php?type=reduced'.$show.'">'.
|
||||
Display::return_icon('edit.png', get_lang('EditNormalProfile'), '', 16).'</a>';
|
||||
} else {
|
||||
$actions .= '<a href="profile.php?type=extended'.$show.'">'.
|
||||
Display::return_icon('edit.png', get_lang('EditExtendProfile'), '', 16).'</a>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$show_delete_account_button = api_get_setting('platform_unsubscribe_allowed') === 'true' ? true : false;
|
||||
|
||||
$tpl = new Template(get_lang('ModifyProfile'));
|
||||
|
||||
if ($actions) {
|
||||
$tpl->assign(
|
||||
'actions',
|
||||
Display::toolbarAction('toolbar', [$actions])
|
||||
);
|
||||
}
|
||||
|
||||
SocialManager::setSocialUserBlock($tpl, api_get_user_id(), 'messages');
|
||||
$tabs = SocialManager::getHomeProfileTabs('profile');
|
||||
|
||||
if ($allowSocialTool) {
|
||||
SocialManager::setSocialUserBlock($tpl, api_get_user_id(), 'home');
|
||||
$menu = SocialManager::show_social_menu(
|
||||
'home',
|
||||
null,
|
||||
api_get_user_id(),
|
||||
false,
|
||||
$show_delete_account_button
|
||||
);
|
||||
$tpl->assign('social_menu_block', $menu);
|
||||
$tpl->assign('social_right_content', $tabs.$form->returnForm());
|
||||
$social_layout = $tpl->get_template('social/edit_profile.tpl');
|
||||
|
||||
$tpl->display($social_layout);
|
||||
} else {
|
||||
$bigImage = UserManager::getUserPicture(api_get_user_id(), USER_IMAGE_SIZE_BIG);
|
||||
$normalImage = UserManager::getUserPicture(api_get_user_id(), USER_IMAGE_SIZE_ORIGINAL);
|
||||
|
||||
$imageToShow = '<div id="image-message-container">';
|
||||
$imageToShow .= '<a class="expand-image pull-right" href="'.$bigImage.'" /><img src="'.$normalImage.'"></a>';
|
||||
$imageToShow .= '</div>';
|
||||
|
||||
$content = $imageToShow.$form->returnForm().$tabs;
|
||||
|
||||
$tpl->assign('content', $content);
|
||||
$tpl->display_one_col_template();
|
||||
}
|
||||
|
||||
// Helper functions defined below this point
|
||||
|
||||
/**
|
||||
* Is user auth_source is platform ?
|
||||
*
|
||||
* @return bool Whether auth_source is 'platform' or not
|
||||
*/
|
||||
function is_platform_authentication()
|
||||
{
|
||||
$tabUserInfo = api_get_user_info(api_get_user_id());
|
||||
|
||||
return $tabUserInfo['auth_source'] == PLATFORM_AUTH_SOURCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can a user edit his/her profile?
|
||||
*
|
||||
* @return bool Whether the profile can be edited by the user or not
|
||||
*/
|
||||
function is_profile_editable()
|
||||
{
|
||||
if (isset($GLOBALS['profileIsEditable'])) {
|
||||
return (bool) $GLOBALS['profileIsEditable'];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload a submitted user production.
|
||||
*
|
||||
* @param int $userId User id
|
||||
*
|
||||
* @return mixed The filename of the new production or FALSE if the upload has failed
|
||||
*/
|
||||
function upload_user_production($userId)
|
||||
{
|
||||
$productionRepository = UserManager::getUserPathById($userId, 'system');
|
||||
|
||||
if (!file_exists($productionRepository)) {
|
||||
@mkdir($productionRepository, api_get_permissions_for_new_directories(), true);
|
||||
}
|
||||
$filename = api_replace_dangerous_char($_FILES['production']['name']);
|
||||
$filename = disable_dangerous_file($filename);
|
||||
|
||||
if (filter_extension($filename)) {
|
||||
if (@move_uploaded_file($_FILES['production']['tmp_name'], $productionRepository.$filename)) {
|
||||
return $filename;
|
||||
}
|
||||
}
|
||||
|
||||
return false; // this should be returned if anything went wrong with the upload
|
||||
}
|
||||
|
||||
/**
|
||||
* Check current user's current password.
|
||||
*
|
||||
* @param string $email E-mail
|
||||
*
|
||||
* @return bool Whether this e-mail is already in use or not
|
||||
*/
|
||||
function check_user_email($email)
|
||||
{
|
||||
$userId = api_get_user_id();
|
||||
if ($userId != strval(intval($userId)) || empty($email)) {
|
||||
return false;
|
||||
}
|
||||
$tableUser = Database::get_main_table(TABLE_MAIN_USER);
|
||||
$email = Database::escape_string($email);
|
||||
$sql = "SELECT * FROM $tableUser WHERE user_id = $userId AND email = '$email'";
|
||||
$result = Database::query($sql);
|
||||
|
||||
return Database::num_rows($result) != 0;
|
||||
}
|
||||
27
main/auth/resend_confirmation_mail.php
Normal file
27
main/auth/resend_confirmation_mail.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/* For license terms, see /license.txt */
|
||||
|
||||
require_once __DIR__.'/../inc/global.inc.php';
|
||||
|
||||
// Build the form
|
||||
$form = new FormValidator('resend');
|
||||
$form->addHeader(get_lang('ReSendConfirmationMail'));
|
||||
$form->addText('user', get_lang('UserName'), true);
|
||||
$form->addButtonSend(get_lang('Send'));
|
||||
|
||||
if ($form->validate()) {
|
||||
$values = $form->exportValues();
|
||||
$user = UserManager::getManager()->findUserByUsername($values['user']);
|
||||
if ($user) {
|
||||
UserManager::sendUserConfirmationMail($user);
|
||||
} else {
|
||||
Display::addFlash(Display::return_message(get_lang('UserDoesNotExist')));
|
||||
}
|
||||
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit;
|
||||
}
|
||||
|
||||
$tpl = new Template(null);
|
||||
$tpl->assign('content', $form->toHtml());
|
||||
$tpl->display_one_col_template();
|
||||
124
main/auth/reset.php
Normal file
124
main/auth/reset.php
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
/* For license terms, see /license.txt */
|
||||
|
||||
require_once __DIR__.'/../inc/global.inc.php';
|
||||
|
||||
$token = $_GET['token'] ?? '';
|
||||
|
||||
if (!ctype_alnum($token)) {
|
||||
$token = '';
|
||||
}
|
||||
|
||||
$user = UserManager::getManager()->findUserByConfirmationToken($token);
|
||||
|
||||
if (!$user) {
|
||||
Display::addFlash(
|
||||
Display::return_message(get_lang('LinkExpired'), 'error')
|
||||
);
|
||||
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit;
|
||||
}
|
||||
|
||||
// Build the form
|
||||
$form = new FormValidator('reset', 'POST', api_get_self().'?token='.$token);
|
||||
$form->addElement('header', get_lang('ResetPassword'));
|
||||
$form->addHidden('token', $token);
|
||||
if (!empty($_GET['rotate'])) {
|
||||
$form->addElement('html', Display::return_message(get_lang('PasswordExpiredPleaseSetNewPassword'), 'warning'));
|
||||
}
|
||||
|
||||
$form->addElement(
|
||||
'password',
|
||||
'pass1',
|
||||
get_lang('Password'),
|
||||
[
|
||||
'show_hide' => true,
|
||||
]
|
||||
);
|
||||
$form->addElement(
|
||||
'password',
|
||||
'pass2',
|
||||
get_lang('Confirmation'),
|
||||
['id' => 'pass2', 'size' => 20, 'autocomplete' => 'off']
|
||||
);
|
||||
$form->addRule('pass1', get_lang('ThisFieldIsRequired'), 'required');
|
||||
$form->addRule('pass2', get_lang('ThisFieldIsRequired'), 'required');
|
||||
$form->addRule(['pass1', 'pass2'], get_lang('PassTwo'), 'compare');
|
||||
$form->addPasswordRule('pass1');
|
||||
$form->addNoSamePasswordRule('pass1', $user);
|
||||
$form->addButtonSave(get_lang('Update'));
|
||||
|
||||
$ttl = api_get_setting('user_reset_password_token_limit');
|
||||
if (empty($ttl)) {
|
||||
$ttl = 3600;
|
||||
}
|
||||
|
||||
if ($form->validate()) {
|
||||
$values = $form->exportValues();
|
||||
$password = $values['pass1'];
|
||||
$token = $values['token'];
|
||||
|
||||
/** @var \Chamilo\UserBundle\Entity\User $user */
|
||||
$user = UserManager::getManager()->findUserByConfirmationToken($token);
|
||||
|
||||
if ($user) {
|
||||
if (!$user->isPasswordRequestNonExpired($ttl)) {
|
||||
Display::addFlash(Display::return_message(get_lang('LinkExpired')), 'warning');
|
||||
header('Location: '.api_get_path(WEB_CODE_PATH).'auth/lostPassword.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$user->setPlainPassword($password);
|
||||
$userManager = UserManager::getManager();
|
||||
$userManager->updateUser($user, true);
|
||||
|
||||
$user->setConfirmationToken(null);
|
||||
$user->setPasswordRequestedAt(null);
|
||||
|
||||
Database::getManager()->persist($user);
|
||||
Database::getManager()->flush();
|
||||
|
||||
if (api_get_configuration_value('force_renew_password_at_first_login')) {
|
||||
$extraFieldValue = new ExtraFieldValue('user');
|
||||
$value = $extraFieldValue->get_values_by_handler_and_field_variable($user->getId(), 'ask_new_password');
|
||||
if (!empty($value) && isset($value['value']) && 1 === (int) $value['value']) {
|
||||
$extraFieldValue->delete($value['id']);
|
||||
}
|
||||
}
|
||||
if (api_get_configuration_value('security_password_rotate_days') > 0) {
|
||||
$extraFieldValue = new ExtraFieldValue('user');
|
||||
$date = api_get_local_time(
|
||||
null,
|
||||
'UTC',
|
||||
'UTC',
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
'Y-m-d H:i:s'
|
||||
);
|
||||
$extraFieldValue->save(
|
||||
[
|
||||
'item_id' => $user->getId(),
|
||||
'variable' => 'password_updated_at',
|
||||
'value' => $date,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
Display::addFlash(Display::return_message(get_lang('Updated')));
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit;
|
||||
} else {
|
||||
Display::addFlash(
|
||||
Display::return_message(get_lang('LinkExpired'))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$htmlHeadXtra[] = api_get_password_checker_js('#username', '#reset_pass1');
|
||||
|
||||
$tpl = new Template(null);
|
||||
$tpl->assign('content', $form->toHtml());
|
||||
$tpl->display_one_col_template();
|
||||
55
main/auth/set_temp_password.php
Normal file
55
main/auth/set_temp_password.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/* For license terms, see /license.txt */
|
||||
|
||||
use ChamiloSession as Session;
|
||||
|
||||
/**
|
||||
* This page aims at requesting a password from a user to access a course
|
||||
* protected by password. If the password matches the course password, we
|
||||
* store the fact that user can access it during its session.
|
||||
*/
|
||||
$cidReset = true;
|
||||
require_once __DIR__.'/../inc/global.inc.php';
|
||||
$this_section = SECTION_COURSES;
|
||||
$courseId = isset($_GET['course_id']) ? intval($_GET['course_id']) : null;
|
||||
$sessionId = isset($_GET['session_id']) ? intval($_GET['session_id']) : null;
|
||||
$userId = api_get_user_id();
|
||||
|
||||
/**
|
||||
* Security check.
|
||||
*/
|
||||
if (empty($courseId)) {
|
||||
api_not_allowed();
|
||||
}
|
||||
|
||||
$courseInfo = api_get_course_info_by_id($courseId);
|
||||
|
||||
// Build the form
|
||||
$form = new FormValidator(
|
||||
'set_temp_password',
|
||||
'POST',
|
||||
api_get_self().'?course_id='.$courseId.'&session_id='.$sessionId
|
||||
);
|
||||
$form->addElement('header', get_lang('CourseRequiresPassword'));
|
||||
$form->addElement('hidden', 'course_id', $courseId);
|
||||
$form->addElement('hidden', 'session_id', $sessionId);
|
||||
$form->addElement('password', 'course_password', get_lang('Password'));
|
||||
$form->addButtonSave(get_lang('Accept'));
|
||||
|
||||
if ($form->validate()) {
|
||||
$formValues = $form->exportValues();
|
||||
if (sha1($formValues['course_password']) === $courseInfo['registration_code']) {
|
||||
Session::write('course_password_'.$courseInfo['real_id'], true);
|
||||
header('Location: '.api_get_course_url($courseInfo['code'], $sessionId).
|
||||
'&action=subscribe&sec_token='.Security::get_existing_token());
|
||||
exit;
|
||||
} else {
|
||||
Display::addFlash(
|
||||
Display::return_message(get_lang('CourseRegistrationCodeIncorrect'), 'error')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$tpl = new Template(null);
|
||||
$tpl->assign('content', $form->toHtml());
|
||||
$tpl->display_one_col_template();
|
||||
10
main/auth/shibboleth/_readme.txt
Normal file
10
main/auth/shibboleth/_readme.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Shibboleth authentication module.
|
||||
|
||||
@license see /license.txt
|
||||
@author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
|
||||
To use install Shibboleth on your web server and secure the application url
|
||||
with a web server security directive.
|
||||
|
||||
Modify configuration to your federation's needs.
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
use \Redirect;
|
||||
use \Display;
|
||||
use IndexManager;
|
||||
|
||||
/**
|
||||
* Controller for the Shibboleth authentication system.
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
class ShibbolethController
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @return ShibbolethController
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
static $result = false;
|
||||
if (empty($result))
|
||||
{
|
||||
$result = new self();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log user in with Shibboleth authentication
|
||||
*/
|
||||
function login()
|
||||
{
|
||||
|
||||
if (Shibboleth::session()->is_logged_in())
|
||||
{
|
||||
Redirect::home();
|
||||
}
|
||||
|
||||
$user = Shibboleth::store()->get_user();
|
||||
|
||||
if ($user->is_empty())
|
||||
{
|
||||
$message = get_lang('SystemCouldNotLogYouIn');
|
||||
Shibboleth::display()->error_page($message);
|
||||
}
|
||||
|
||||
$is_new_user = !User::store()->shibboleth_id_exists($user->unique_id);
|
||||
|
||||
if ($is_new_user && empty($user->email) && Shibboleth::config()->is_email_mandatory)
|
||||
{
|
||||
$form = ShibbolethEmailForm::instance();
|
||||
if ($email = $form->get_email())
|
||||
{
|
||||
$user->email = $email;
|
||||
}
|
||||
else
|
||||
{
|
||||
$content = $form->display();
|
||||
Shibboleth::display()->page($content);
|
||||
}
|
||||
}
|
||||
|
||||
Shibboleth::save($user);
|
||||
$chamilo_user = User::store()->get_by_shibboleth_id($user->unique_id);
|
||||
Shibboleth::session()->login($chamilo_user->user_id);
|
||||
|
||||
if ($is_new_user && $user->status_request)
|
||||
{
|
||||
Shibboleth::redirect('/main/auth/shibboleth/app/view/request.php');
|
||||
}
|
||||
else
|
||||
{
|
||||
Shibboleth::redirect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log user in using the standard Chamilo way of logging in.
|
||||
* Useful when the normal login screen is removed from the user interface
|
||||
* - replaced by Shibboleth login - and user want to login using a standard
|
||||
* account
|
||||
*/
|
||||
public function admin_login()
|
||||
{
|
||||
$title = get_lang('InternalLogin');
|
||||
if (Shibboleth::session()->is_logged_in())
|
||||
{
|
||||
$message = get_lang('AlreadyLoggedIn');
|
||||
Shibboleth::display()->message_page($message, $title);
|
||||
}
|
||||
$index_manager = new IndexManager('');
|
||||
$html = $index_manager->display_login_form();
|
||||
Shibboleth::display()->page($html, $title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the request new status page to administrator for new users.
|
||||
*/
|
||||
public function request_status()
|
||||
{
|
||||
/*
|
||||
* That may happen if a user visit that url again.
|
||||
*/
|
||||
if (!Shibboleth::session()->is_logged_in())
|
||||
{
|
||||
Shibboleth::redirect();
|
||||
}
|
||||
$user = Shibboleth::session()->user();
|
||||
if ($user['status'] == Shibboleth::TEACHER_STATUS)
|
||||
{
|
||||
//Maximum user right is reached.
|
||||
Shibboleth::redirect();
|
||||
}
|
||||
|
||||
$form = ShibbolethStatusRequestForm::instance();
|
||||
|
||||
if ($form->cancelled())
|
||||
{
|
||||
Shibboleth::redirect();
|
||||
}
|
||||
|
||||
if ($reason = $form->get_reason())
|
||||
{
|
||||
$subject = get_lang('RequestStatus');
|
||||
$status = $form->get_status();
|
||||
$status = Shibboleth::format_status($status);
|
||||
|
||||
$message = <<<EOT
|
||||
New status: $status
|
||||
|
||||
Reason:
|
||||
$reason
|
||||
EOT;
|
||||
|
||||
$success = Shibboleth::email_admin($subject, $message);
|
||||
if ($success)
|
||||
{
|
||||
$request_submitted = get_lang('RequestSubmitted');
|
||||
Shibboleth::display()->message_page($request_submitted);
|
||||
}
|
||||
else
|
||||
{
|
||||
$request_failed = get_lang('RequestFailed');
|
||||
Shibboleth::display()->error_page($request_failed);
|
||||
}
|
||||
}
|
||||
|
||||
$title = get_lang('RequestStatus');
|
||||
Display :: display_header($title);
|
||||
echo $form->display();
|
||||
Display :: display_footer();
|
||||
}
|
||||
|
||||
}
|
||||
44
main/auth/shibboleth/app/model/admin.class.php
Normal file
44
main/auth/shibboleth/app/model/admin.class.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
require_once __DIR__.'/scaffold/admin.class.php';
|
||||
|
||||
/**
|
||||
* A Chamilo admin. Model for the Admin table.
|
||||
*
|
||||
* Should be moved to the core. It only exists because it is not available through
|
||||
* the API.
|
||||
*
|
||||
* The _Admin objet is generated by the scaffolder. Admin inherits from it to allow
|
||||
* modifications without touching the generated file. Don't modify _Admin as
|
||||
* it may change in the future. Instead add modifications to this class.
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
class Admin extends _Admin
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Store for Admin objects. Interact with the database. Allows to save and retrieve
|
||||
* admin objects.
|
||||
*
|
||||
* Should be moved to the core. It only exists because it is not available through
|
||||
* the API.
|
||||
*
|
||||
* The _AdminStore objet is generated by the scaffolder. This class inherits from it to allow
|
||||
* modifications without touching the generated file. Don't modify the _ object as
|
||||
* it may change in the future. Instead add modifications to this class.
|
||||
*
|
||||
* @copyright (c) 2012 University of Geneva
|
||||
* @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>
|
||||
*/
|
||||
class AdminStore extends _AdminStore
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
134
main/auth/shibboleth/app/model/scaffold/admin.class.php
Normal file
134
main/auth/shibboleth/app/model/scaffold/admin.class.php
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
/**
|
||||
* This file is autogenerated. Do not modifiy it.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* Model for table admin
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
class _Admin
|
||||
{
|
||||
|
||||
/**
|
||||
* Store for Admin objects. Interact with the database.
|
||||
*
|
||||
* @return AdminStore
|
||||
*/
|
||||
public static function store()
|
||||
{
|
||||
static $result = false;
|
||||
if (empty($result))
|
||||
{
|
||||
$result = new AdminStore();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return Admin
|
||||
*/
|
||||
public static function create($data = null)
|
||||
{
|
||||
return self::store()->create_object($data);
|
||||
}
|
||||
|
||||
public $user_id = null;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
return self::store()->save($this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Store for Admin objects. Interact with the database.
|
||||
*
|
||||
* @copyright (c) 2012 University of Geneva
|
||||
* @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>
|
||||
*/
|
||||
class _AdminStore extends Store
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @return AdminStore
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
static $result = false;
|
||||
if (empty($result))
|
||||
{
|
||||
$result = new self();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('admin', '\Shibboleth\Admin', 'user_id');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return Admin
|
||||
*/
|
||||
public function get($w)
|
||||
{
|
||||
$args = func_get_args();
|
||||
$f = array('parent', 'get');
|
||||
return call_user_func_array($f, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return Admin
|
||||
*/
|
||||
public function create_object($data)
|
||||
{
|
||||
return parent::create_object($data);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return Admin
|
||||
*/
|
||||
public function get_by_user_id($value)
|
||||
{
|
||||
return $this->get(array('user_id' => $value));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function user_id_exists($value)
|
||||
{
|
||||
return $this->exist(array('user_id' => $value));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete_by_user_id($value)
|
||||
{
|
||||
return $this->delete(array('user_id' => $value));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
185
main/auth/shibboleth/app/model/scaffold/user.class.php
Normal file
185
main/auth/shibboleth/app/model/scaffold/user.class.php
Normal file
@@ -0,0 +1,185 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
/**
|
||||
* This file is autogenerated. Do not modifiy it.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* Model for table user
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
class _User
|
||||
{
|
||||
|
||||
/**
|
||||
* Store for User objects. Interact with the database.
|
||||
*
|
||||
* @return UserStore
|
||||
*/
|
||||
public static function store()
|
||||
{
|
||||
static $result = false;
|
||||
if (empty($result))
|
||||
{
|
||||
$result = new UserStore();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return User
|
||||
*/
|
||||
public static function create($data = null)
|
||||
{
|
||||
return self::store()->create_object($data);
|
||||
}
|
||||
|
||||
public $user_id = null;
|
||||
public $lastname = null;
|
||||
public $firstname = null;
|
||||
public $username = null;
|
||||
public $password = null;
|
||||
public $auth_source = null;
|
||||
public $shibb_unique_id = null;
|
||||
public $email = null;
|
||||
public $status = null;
|
||||
public $official_code = null;
|
||||
public $phone = null;
|
||||
public $picture_uri = null;
|
||||
public $creator_id = null;
|
||||
public $competences = null;
|
||||
public $diplomas = null;
|
||||
public $openarea = null;
|
||||
public $teach = null;
|
||||
public $productions = null;
|
||||
public $language = null;
|
||||
public $registration_date = null;
|
||||
public $expiration_date = null;
|
||||
public $active = null;
|
||||
public $openid = null;
|
||||
public $theme = null;
|
||||
public $hr_dept_id = null;
|
||||
public $shibb_persistent_id = null;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
return self::store()->save($this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Store for User objects. Interact with the database.
|
||||
*
|
||||
* @copyright (c) 2012 University of Geneva
|
||||
* @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>
|
||||
*/
|
||||
class _UserStore extends Store
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @return UserStore
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
static $result = false;
|
||||
if (empty($result))
|
||||
{
|
||||
$result = new self();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('user', '\Shibboleth\User', 'user_id');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return User
|
||||
*/
|
||||
public function get($w)
|
||||
{
|
||||
$args = func_get_args();
|
||||
$f = array('parent', 'get');
|
||||
return call_user_func_array($f, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return User
|
||||
*/
|
||||
public function create_object($data)
|
||||
{
|
||||
return parent::create_object($data);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return User
|
||||
*/
|
||||
public function get_by_user_id($value)
|
||||
{
|
||||
return $this->get(array('user_id' => $value));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function user_id_exists($value)
|
||||
{
|
||||
return $this->exist(array('user_id' => $value));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete_by_user_id($value)
|
||||
{
|
||||
return $this->delete(array('user_id' => $value));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return User
|
||||
*/
|
||||
public function get_by_username($value)
|
||||
{
|
||||
return $this->get(array('username' => $value));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function username_exists($value)
|
||||
{
|
||||
return $this->exist(array('username' => $value));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete_by_username($value)
|
||||
{
|
||||
return $this->delete(array('username' => $value));
|
||||
}
|
||||
|
||||
}
|
||||
197
main/auth/shibboleth/app/model/shibboleth_store.class.php
Normal file
197
main/auth/shibboleth/app/model/shibboleth_store.class.php
Normal file
@@ -0,0 +1,197 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
/**
|
||||
* Returns Shibboleth user's values based on Shibboleth's configuration.
|
||||
* Shibboleth returns not only whether a user is authenticated but returns as
|
||||
* well several paralemeter fields.
|
||||
*
|
||||
* If a user is not authenticated nothing is returned.
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
class ShibbolethStore
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @return ShibbolethStore
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
static $result = false;
|
||||
if (empty($result))
|
||||
{
|
||||
$result = new self();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return ShibbolethConfig
|
||||
*/
|
||||
public static function config()
|
||||
{
|
||||
return Shibboleth::config();
|
||||
}
|
||||
|
||||
public function get_unique_id()
|
||||
{
|
||||
return $this->get(__FUNCTION__);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the user has more than one surname, it is possible depending of the user
|
||||
* home organization that they are all given to the resource.
|
||||
* In the case of the University of Geneva, with two surnames, three different values
|
||||
* for the surname are sent. They are:
|
||||
* 1) "givenname1"
|
||||
* 2) "givenname2"
|
||||
* 3) "givenname1 givenname2"
|
||||
* meaning the string is as follow: "givenname1;givenname2;givenname1 givenname2"
|
||||
*
|
||||
* In such a case, the correct surname is the one which is followed by a space.
|
||||
* This function tests if such a situation is encountered, and returns the first given name.
|
||||
*
|
||||
* @author Nicolas Rod
|
||||
*/
|
||||
public function get_firstname()
|
||||
{
|
||||
$result = $this->get(__FUNCTION__);
|
||||
|
||||
if (!is_array($result))
|
||||
{
|
||||
$result = ucfirst($result);
|
||||
return $result;
|
||||
}
|
||||
foreach ($result as $name)
|
||||
{
|
||||
$parts = explode(' ', $name);
|
||||
|
||||
if (count($parts) > 1)
|
||||
{
|
||||
$result = reset($parts);
|
||||
$result = ucfirst($result);
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
$result = reset($result);
|
||||
$result = ucfirst($result);
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function get_lastname()
|
||||
{
|
||||
$result = $this->get(__FUNCTION__);
|
||||
$result = ucfirst($result);
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function get_email()
|
||||
{
|
||||
return $this->get(__FUNCTION__);
|
||||
}
|
||||
|
||||
public function get_language()
|
||||
{
|
||||
return $this->get(__FUNCTION__);
|
||||
}
|
||||
|
||||
public function get_gender()
|
||||
{
|
||||
return $this->get(__FUNCTION__);
|
||||
}
|
||||
|
||||
public function get_address()
|
||||
{
|
||||
return $this->get(__FUNCTION__);
|
||||
}
|
||||
|
||||
public function get_staff_category()
|
||||
{
|
||||
return $this->get(__FUNCTION__);
|
||||
}
|
||||
|
||||
public function get_home_organization_type()
|
||||
{
|
||||
return $this->get(__FUNCTION__);
|
||||
}
|
||||
|
||||
public function get_home_organization()
|
||||
{
|
||||
return $this->get(__FUNCTION__);
|
||||
}
|
||||
|
||||
public function get_affiliation()
|
||||
{
|
||||
return $this->get(__FUNCTION__);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ShibbolethUser
|
||||
*/
|
||||
public function get_user()
|
||||
{
|
||||
$result = new ShibbolethUser();
|
||||
foreach ($result as $key => $val)
|
||||
{
|
||||
$f = array($this, "get_$key");
|
||||
if (is_callable($f))
|
||||
{
|
||||
$result->{$key} = call_user_func($f);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shibboleth value stored in $_SERVER if it exists or $default if it is not the case.
|
||||
*
|
||||
* @param string $name the generic name. I.e. one of the class const.
|
||||
* @param string $default default value if it is not provided by Shibboleth
|
||||
* @return string
|
||||
*/
|
||||
public function get($name = '', $default = '')
|
||||
{
|
||||
$config = (array) Shibboleth::config();
|
||||
if ($name)
|
||||
{
|
||||
$name = str_replace('get_', '', $name);
|
||||
$shib_name = isset($config[$name]) ? $config[$name] : '';
|
||||
if ($shib_name)
|
||||
{
|
||||
$result = isset($_SERVER[$shib_name]) ? $_SERVER[$shib_name] : $default;
|
||||
$result = explode(';', $result);
|
||||
if (empty($result))
|
||||
{
|
||||
$result = $default;
|
||||
}
|
||||
else if (count($result) == 1)
|
||||
{
|
||||
$result = reset($result);
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = $result;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
$result = array();
|
||||
foreach ($config as $key => $val)
|
||||
{
|
||||
$f = array($this, "get_$key");
|
||||
if (is_callable($f))
|
||||
{
|
||||
$result[$key] = call_user_func($f);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
33
main/auth/shibboleth/app/model/shibboleth_user.class.php
Normal file
33
main/auth/shibboleth/app/model/shibboleth_user.class.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
/**
|
||||
* Represent a Shibboleth user. Not to be missunderstand with a Chamilo user
|
||||
* since they don't have the same attributes.
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
class ShibbolethUser
|
||||
{
|
||||
|
||||
public $unique_id = '';
|
||||
public $firstname = '';
|
||||
public $lastname = '';
|
||||
public $email = '';
|
||||
public $language = '';
|
||||
public $gender = '';
|
||||
public $address = '';
|
||||
public $staff_category = '';
|
||||
public $home_organization_type = '';
|
||||
public $home_organization = '';
|
||||
public $affiliation = '';
|
||||
public $persistent_id = '';
|
||||
|
||||
public function is_empty()
|
||||
{
|
||||
return empty($this->unique_id);
|
||||
}
|
||||
|
||||
}
|
||||
95
main/auth/shibboleth/app/model/user.class.php
Normal file
95
main/auth/shibboleth/app/model/user.class.php
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
require_once __DIR__.'/scaffold/user.class.php';
|
||||
|
||||
/**
|
||||
* A Chamilo user. Model for the User table.
|
||||
*
|
||||
* Should be moved to the core. It only exists because it is not available through
|
||||
* the API.
|
||||
*
|
||||
* The _User objet is generated by the scaffolder. User inherits from it to allow
|
||||
* modifications without touching the generated file. Don't modify _User as
|
||||
* it may change in the future. Instead add modifications to this class.
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
class User extends _User
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Store for User objects. Interact with the database. Allows to save and retrieve
|
||||
* user objects.
|
||||
*
|
||||
* Should be moved to the core. It only exists because it is not available through
|
||||
* the API.
|
||||
*
|
||||
* The _UserStore objet is generated by the scaffolder. This class inherits from it to allow
|
||||
* modifications without touching the generated file. Don't modify the _ object as
|
||||
* it may change in the future. Instead add modifications to this class.
|
||||
*
|
||||
* @copyright (c) 2012 University of Geneva
|
||||
* @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>
|
||||
*/
|
||||
class UserStore extends _UserStore
|
||||
{
|
||||
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
ShibbolethUpgrade::update();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $id
|
||||
* @return User
|
||||
*/
|
||||
public function get_by_shibboleth_id($id)
|
||||
{
|
||||
return $this->get(array('shibb_unique_id' => $id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
*/
|
||||
public function shibboleth_id_exists($id)
|
||||
{
|
||||
return $this->exist(array('shibb_unique_id' => $id));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param User $object
|
||||
*/
|
||||
protected function before_save($object)
|
||||
{
|
||||
$object->username = $object->username ? $object->username : $this->generate_username();
|
||||
$object->password = $object->password ? $object->password : api_generate_password();
|
||||
$object->language = $object->language ? $object->language : $this->default_language();
|
||||
}
|
||||
|
||||
function default_language()
|
||||
{
|
||||
return api_get_setting('platformLanguage');
|
||||
}
|
||||
|
||||
function generate_username()
|
||||
{
|
||||
$result = uniqid('s', true);
|
||||
$result = str_replace('.', '', $result);
|
||||
while ($this->username_exists($result))
|
||||
{
|
||||
$result = uniqid('s', true);
|
||||
$result = str_replace('.', '', $result);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
266
main/auth/shibboleth/app/shibboleth.class.php
Normal file
266
main/auth/shibboleth/app/shibboleth.class.php
Normal file
@@ -0,0 +1,266 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
use \Redirect;
|
||||
|
||||
/**
|
||||
* Shibboleth main class. Provides access to various Shibboleth sub components and
|
||||
* provides the high level functionalities.
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
class Shibboleth
|
||||
{
|
||||
|
||||
const NAME = 'shibboleth';
|
||||
const UNKNOWN_STATUS = -1;
|
||||
const TEACHER_STATUS = 1;
|
||||
const STUDENT_STATUS = 5;
|
||||
|
||||
static $config = null;
|
||||
|
||||
public static function format_status($status)
|
||||
{
|
||||
if ($status == Shibboleth::TEACHER_STATUS) {
|
||||
return 'Teacher';
|
||||
} else if ($status == Shibboleth::STUDENT_STATUS) {
|
||||
return 'Student';
|
||||
} else if ($status == Shibboleth::UNKNOWN_STATUS) {
|
||||
return 'Unknown';
|
||||
} else {
|
||||
return '???';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return ShibbolethConfig
|
||||
*/
|
||||
public static function config()
|
||||
{
|
||||
self::$config = self::$config ? self::$config : new ShibbolethConfig();
|
||||
return self::$config;
|
||||
}
|
||||
|
||||
public static function set_config($config)
|
||||
{
|
||||
self::$config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return ShibbolethSession
|
||||
*/
|
||||
public static function session()
|
||||
{
|
||||
return ShibbolethSession::instance();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return ShibbolethStore
|
||||
*/
|
||||
public static function store()
|
||||
{
|
||||
return ShibbolethStore::instance();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return ShibbolethDisplay
|
||||
*/
|
||||
public static function display()
|
||||
{
|
||||
return ShibbolethDisplay::instance();
|
||||
}
|
||||
|
||||
public static function sys_path()
|
||||
{
|
||||
$path = __DIR__.'/../';
|
||||
return $path;
|
||||
}
|
||||
|
||||
public static function url($path = '')
|
||||
{
|
||||
$result = api_get_path('WEB_PATH');
|
||||
$result .= '/main/auth/shibboleth/' . $path;
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function redirect($url = '')
|
||||
{
|
||||
if (empty($url)) {
|
||||
$url = isset($_SESSION['shibb_direct_url']) ? $_SESSION['shibb_direct_url'] : '';
|
||||
unset($_SESSION['shibb_direct_url']);
|
||||
|
||||
/*
|
||||
* Tests if the user tried to login directly in a protected course before to come here
|
||||
* (this variable could be set in the modified code of /chamilo/inc/lib/main_api.lib.php)
|
||||
*
|
||||
* Note:
|
||||
* this part was added to give the possibility to access Chamilo directly on a course URL from a link diplayed in a portal.
|
||||
* This is not a direct Shibboleth related functionnality, but this could be used in a shibbolethized
|
||||
* Dokeos installation, mainly if you have a SSO system in your network.
|
||||
* Please note that the file /claroline/inc/lib/main_api.lib.php must be adapted to your Shibboleth settings
|
||||
* If any interest or question, please contact Nicolas.Rod_at_adm.unige.ch
|
||||
*
|
||||
*/
|
||||
}
|
||||
if ($url) {
|
||||
//needed to log the user in his courses. Normally it is done by visiting /chamilo/index.php
|
||||
// $include_path = api_get_path(INCLUDE_PATH);
|
||||
// require("$include_path/local.inc.php");
|
||||
//
|
||||
// if (strpos($url, '?') === false) {
|
||||
// $url = "$url?";
|
||||
// }
|
||||
//
|
||||
// $rootWeb = api_get_path('WEB_PATH');
|
||||
// $first_slash_pos = strpos($rootWeb, '/', 8);
|
||||
// $rootWeb_wo_uri = substr($rootWeb, 0, $first_slash_pos);
|
||||
// $url = $rootWeb_wo_uri . $course_url . '_stop';
|
||||
Redirect::go($url);
|
||||
}
|
||||
Redirect::home();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param ShibbolethUser $shibb_user
|
||||
*/
|
||||
public static function save($shibb_user)
|
||||
{
|
||||
$shibb_user->status = self::infer_user_status($shibb_user);
|
||||
$shibb_user->status_request = self::infer_status_request($shibb_user);
|
||||
$shibb_user->shibb_unique_id = $shibb_user->unique_id;
|
||||
$shibb_user->shibb_persistent_id = $shibb_user->persistent_id;
|
||||
|
||||
$user = User::store()->get_by_shibboleth_id($shibb_user->unique_id);
|
||||
if (empty($user)) {
|
||||
$shibb_user->auth_source == self::NAME;
|
||||
return User::create($shibb_user)->save();
|
||||
}
|
||||
|
||||
$shibb_user->status_request = false;
|
||||
$fields = self::config()->update_fields;
|
||||
foreach ($fields as $key => $updatable) {
|
||||
if ($updatable) {
|
||||
$user->{$key} = $shibb_user->{$key};
|
||||
}
|
||||
}
|
||||
$user->auth_source == self::NAME;
|
||||
$user->shibb_unique_id = $shibb_user->shibb_unique_id;
|
||||
$user->shibb_persistent_id = $shibb_user->shibb_persistent_id;
|
||||
$user->save();
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Infer the rights/status the user can have in Chamilo based on his affiliation attribute
|
||||
*
|
||||
* @param ShibbolethUser $user
|
||||
* @return The Chamilo user status, one of TEACHER, STUDENT or UNKNOWN
|
||||
*/
|
||||
public static function infer_user_status($user)
|
||||
{
|
||||
$affiliations = $user->affiliation;
|
||||
$affiliations = is_array($affiliations) ? $affiliations : array($affiliations);
|
||||
|
||||
$map = self::config()->affiliation_status;
|
||||
|
||||
$rights = array();
|
||||
foreach ($affiliations as $affiliation) {
|
||||
$affiliation = strtolower($affiliation);
|
||||
if (isset($map[$affiliation])) {
|
||||
$right = $map[$affiliation];
|
||||
$rights[$right] = $right;
|
||||
}
|
||||
}
|
||||
|
||||
$teacher_status = isset($rights[self::TEACHER_STATUS]);
|
||||
$student_status = isset($rights[self::STUDENT_STATUS]);
|
||||
|
||||
//if the user has got teacher rights, we doesn't check anything else
|
||||
if ($teacher_status) {
|
||||
return self::TEACHER_STATUS;
|
||||
}
|
||||
|
||||
if ($student_status) {
|
||||
return self::STUDENT_STATUS;
|
||||
}
|
||||
|
||||
$result = self::config()->default_status;
|
||||
$result = (int) $result;
|
||||
$result = ($result == Shibboleth::TEACHER_STATUS || $result == Shibboleth::STUDENT_STATUS) ? $result : Shibboleth::UNKNOWN_STATUS;
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the user can ask for a greater status than student.
|
||||
* This happens for staff members.
|
||||
*
|
||||
* @param ShibbolethUser $user
|
||||
* @return boolean
|
||||
*/
|
||||
public static function infer_status_request($user)
|
||||
{
|
||||
if ($user->status == self::TEACHER_STATUS) {
|
||||
return false;
|
||||
}
|
||||
if ($user->status == self::UNKNOWN_STATUS) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$config = Shibboleth::config();
|
||||
$affiliations = $user->affiliation;
|
||||
$affiliations = is_array($affiliations) ? $affiliations : array($affiliations);
|
||||
foreach ($affiliations as $affiliation) {
|
||||
$result = isset($config->affiliation_status_request[$affiliation]) ? $config->affiliation_status_request[$affiliation] : false;
|
||||
if ($result) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an email to the Chamilo and Shibboleth administrators in the name
|
||||
* of the logged-in user.
|
||||
*
|
||||
* @param string $subject
|
||||
*/
|
||||
public static function email_admin($subject, $message)
|
||||
{
|
||||
$user = Shibboleth::session()->user();
|
||||
$firstname = $user['firstname'];
|
||||
$lastname = $user['lastname'];
|
||||
$email = $user['email'];
|
||||
$status = $user['status'];
|
||||
$status = self::format_status($status);
|
||||
|
||||
$signagure = <<<EOT
|
||||
|
||||
_________________________
|
||||
$firstname $lastname
|
||||
$email
|
||||
$status
|
||||
EOT;
|
||||
|
||||
$message .= $signagure;
|
||||
|
||||
$header = "From: $email \n";
|
||||
|
||||
$shibb_admin_email = Shibboleth::config()->admnistrator_email;
|
||||
if ($shibb_admin_email) {
|
||||
$header .= "Cc: $shibb_admin_email";
|
||||
}
|
||||
|
||||
$administrator_email = api_get_setting('emailAdministrator');
|
||||
$result = mail($administrator_email, $subject, $message);
|
||||
return (bool) $result;
|
||||
}
|
||||
|
||||
}
|
||||
18
main/auth/shibboleth/app/view/admin_login.php
Normal file
18
main/auth/shibboleth/app/view/admin_login.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
/**
|
||||
* Administratrive login. Useful when the standard login is not available anymore
|
||||
* which is usually the case.
|
||||
*
|
||||
* This page allow administrators to log into the application using the standard
|
||||
* Chamilo method when Shibboleth is not available.
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
$dir = __DIR__;
|
||||
include_once "$dir/../../init.php";
|
||||
|
||||
ShibbolethController::instance()->admin_login();
|
||||
20
main/auth/shibboleth/app/view/request.php
Normal file
20
main/auth/shibboleth/app/view/request.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
/**
|
||||
* Display the Request another status/additional rights. The request is emailed
|
||||
* to the shibboleth and platform administrators for processing.
|
||||
*
|
||||
* Users such as staff that can be either student or teachers are presented with
|
||||
* this page upon first login.
|
||||
*
|
||||
* Other users - teachers, students - are directly logged-in.
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
$dir = __DIR__;
|
||||
include_once "$dir/../../init.php";
|
||||
|
||||
ShibbolethController::instance()->request_status();
|
||||
66
main/auth/shibboleth/app/view/shibboleth_display.class.php
Normal file
66
main/auth/shibboleth/app/view/shibboleth_display.class.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
use \Display;
|
||||
|
||||
/**
|
||||
* Utility display functions tailored for the Shibboleth pluging.
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
class ShibbolethDisplay
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @return ShibbolethDisplay
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
static $result = false;
|
||||
if (empty($result))
|
||||
{
|
||||
$result = new self();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
*/
|
||||
public function error_page($message)
|
||||
{
|
||||
$page_title = get_lang('ShibbolethLogin');
|
||||
|
||||
Display :: display_header($page_title);
|
||||
echo Display::return_message($message, 'error');
|
||||
Display :: display_footer();
|
||||
die;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
*/
|
||||
public function message_page($message, $title = '')
|
||||
{
|
||||
$title = $title ? $title : get_lang('ShibbolethLogin');
|
||||
|
||||
Display::display_header($title);
|
||||
echo Display::return_message($message, 'confirm');
|
||||
Display::display_footer();
|
||||
die;
|
||||
}
|
||||
|
||||
public function page($content, $title = '')
|
||||
{
|
||||
$title = $title ? $title : get_lang('ShibbolethLogin');
|
||||
|
||||
Display :: display_header($title);
|
||||
echo $content;
|
||||
Display :: display_footer();
|
||||
die;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
/**
|
||||
* Enter email form. When the email is mandatory and the Shibboleth email user field
|
||||
* is empty the system display this form and ask the user to provide an email.
|
||||
*
|
||||
* @todo: add email validation
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
class ShibbolethEmailForm
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @return ShibbolethEmailForm
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
static $result = false;
|
||||
if (empty($result))
|
||||
{
|
||||
$result = new self();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function display()
|
||||
{
|
||||
|
||||
$email = get_lang('Email');
|
||||
$submit = get_lang('Submit');
|
||||
return <<<EOT
|
||||
<form id="email_form" action="" method="post">
|
||||
<label for="">$email</label>
|
||||
<input type="text" value="" tabindex="1" name="email" id="email_email" class=""><br/>
|
||||
<input type="submit" value="$submit" tabindex="2" name="submit" id="email_submit" class="submit">
|
||||
</form>
|
||||
|
||||
EOT;
|
||||
}
|
||||
|
||||
function get_email()
|
||||
{
|
||||
return isset($_POST['email']) ? $_POST['email'] : '';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
use Display;
|
||||
|
||||
/**
|
||||
* Status request form. Display a form allowing the user to request additional
|
||||
* rights/ another status.
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
class ShibbolethStatusRequestForm
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @return ShibbolethStatusRequestForm
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
static $result = false;
|
||||
if (empty($result))
|
||||
{
|
||||
$result = new self();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function display()
|
||||
{
|
||||
if ($this->is_submitted() && $this->get_reason() == '')
|
||||
{
|
||||
$reason_is_mandatory = get_lang('ReasonIsMandatory');
|
||||
echo Display::return_message($reason_is_mandatory, 'error');
|
||||
}
|
||||
|
||||
$status_request_message = get_lang('StatusRequestMessage');
|
||||
$label_new_status = get_lang('NewStatus');
|
||||
$label_reason = get_lang('Reason');
|
||||
$label_ok = get_lang('Ok');
|
||||
$label_cancel = get_lang('Cancel');
|
||||
|
||||
$user = Shibboleth::session()->user();
|
||||
$items = array();
|
||||
if ($user['status'] == Shibboleth::UNKNOWN_STATUS)
|
||||
{
|
||||
$items[Shibboleth::STUDENT_STATUS] = get_lang('Student');
|
||||
}
|
||||
$items[Shibboleth::TEACHER_STATUS] = get_lang('Teacher');
|
||||
$status_options = '';
|
||||
foreach ($items as $key => $value)
|
||||
{
|
||||
$status_options.= "<option value=\"$key\">$value</option>";
|
||||
}
|
||||
|
||||
return <<<EOT
|
||||
<div id="askAccountText">
|
||||
<p>$status_request_message</p>
|
||||
</div>
|
||||
<form method="post" action="request.php" id="status_request_form">
|
||||
|
||||
<input type="hidden" name="formPosted" value="true"/>
|
||||
|
||||
<label for="status">$label_new_status:</label>
|
||||
<select name="status">
|
||||
$status_options
|
||||
</select>
|
||||
<label for="reason">$label_reason:</label>
|
||||
<textarea name="reason" style="min-width:400px; min-height:100px;"></textarea>
|
||||
<p><input name="submit" type="submit" value="$label_ok" style="margin-right:10px;"/><input name="cancel" type="submit" value="$label_cancel" /></p>
|
||||
</form>
|
||||
EOT;
|
||||
}
|
||||
|
||||
public function is_submitted()
|
||||
{
|
||||
return isset($_POST['submit']) ? $_POST['submit'] : false;
|
||||
}
|
||||
|
||||
public function cancelled()
|
||||
{
|
||||
return isset($_POST['cancel']) ? $_POST['cancel'] : false;
|
||||
}
|
||||
|
||||
function get_reason()
|
||||
{
|
||||
return isset($_POST['reason']) ? $_POST['reason'] : '';
|
||||
}
|
||||
|
||||
function get_status()
|
||||
{
|
||||
return isset($_POST['status']) ? $_POST['status'] : '';
|
||||
}
|
||||
|
||||
}
|
||||
16
main/auth/shibboleth/config-dist.php
Normal file
16
main/auth/shibboleth/config-dist.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
/**
|
||||
* Example of a config.php file. Not used. Configuration must appear in
|
||||
* config.php.
|
||||
*
|
||||
* By default set up the aai configuration.
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
require_once __DIR__.'/config/aai.class.php';
|
||||
|
||||
Shibboleth::set_config(aai::config());
|
||||
69
main/auth/shibboleth/config/aai.class.php
Normal file
69
main/auth/shibboleth/config/aai.class.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
/**
|
||||
* Shibboleth configuration for the AAI federation.
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
class aai
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @return ShibbolethConfig
|
||||
*/
|
||||
public static function config()
|
||||
{
|
||||
$result = new ShibbolethConfig();
|
||||
$result->unique_id = 'Shib-SwissEP-UniqueID';
|
||||
$result->firstname = 'Shib-InetOrgPerson-givenName';
|
||||
$result->lastname = 'Shib-Person-surname';
|
||||
$result->email = 'Shib-InetOrgPerson-mail';
|
||||
$result->language = 'Shib-InetOrgPerson-preferredLanguage';
|
||||
$result->gender = 'Shib-SwissEP-Gender';
|
||||
$result->address = 'Shib-OrgPerson-postalAddress';
|
||||
$result->staff_category = 'Shib-SwissEP-StaffCategory';
|
||||
$result->home_organization_type = 'Shib-SwissEP-HomeOrganizationType';
|
||||
$result->home_organization = 'Shib-SwissEP-HomeOrganization';
|
||||
$result->affiliation = 'Shib-EP-Affiliation';
|
||||
$result->persistent_id = 'persistent-id';
|
||||
|
||||
$result->default_status = Shibboleth::STUDENT_STATUS;
|
||||
|
||||
$result->affiliation_status = array(
|
||||
'faculty' => Shibboleth::TEACHER_STATUS,
|
||||
'member' => Shibboleth::STUDENT_STATUS,
|
||||
'staff' => Shibboleth::STUDENT_STATUS,
|
||||
'student' => Shibboleth::STUDENT_STATUS,
|
||||
);
|
||||
|
||||
$result->update_fields = array(
|
||||
'firstname' => true,
|
||||
'lastname' => true,
|
||||
'email' => true,
|
||||
'status' => false,
|
||||
'persistent_id' => true,
|
||||
);
|
||||
/*
|
||||
* Persistent id should never change but it was introduced after unique id.
|
||||
* So we update persistent id on login for those users who are still missing it.
|
||||
*/
|
||||
|
||||
$result->is_email_mandatory = true;
|
||||
|
||||
|
||||
$result->affiliation_status_request = array(
|
||||
'faculty' => false,
|
||||
'member' => false,
|
||||
'staff' => true,
|
||||
'student' => false,
|
||||
);
|
||||
$result->admnistrator_email = '';
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
85
main/auth/shibboleth/db/shibboleth_upgrade.class.php
Normal file
85
main/auth/shibboleth/db/shibboleth_upgrade.class.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
use \Database;
|
||||
|
||||
/**
|
||||
* Migrate the datatabase. Adds needed fields by Shibboleth to the User table.
|
||||
* Upgrade is checked at each user login so there is no need to manually run
|
||||
* an upgrade.
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
class ShibbolethUpgrade
|
||||
{
|
||||
|
||||
/**
|
||||
* Create additional fields required by the shibboleth plugin if those
|
||||
* are missing.
|
||||
*/
|
||||
public static function update()
|
||||
{
|
||||
static $done = false;
|
||||
if ($done)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$done = true;
|
||||
self::create_shibb_unique_id_field_if_missing();
|
||||
self::create_shibb_persistent_id_field_if_missing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the 'shibb_unique_id' field in the table 'user' of the main Chamilo database if it doesn't exist yet
|
||||
*
|
||||
* @author Nicolas Rod
|
||||
* @return false|null
|
||||
*/
|
||||
public static function create_shibb_unique_id_field_if_missing()
|
||||
{
|
||||
$db_name = Database :: get_main_database();
|
||||
|
||||
$sql = "SELECT * FROM `$db_name`.`user` LIMIT 1";
|
||||
$result = Database::query($sql);
|
||||
$row = mysql_fetch_assoc($result);
|
||||
|
||||
$exists = array_key_exists('shibb_unique_id', $row);
|
||||
if ($exists)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//create the 'shibb_unique_id' field
|
||||
$sql = "ALTER TABLE `$db_name`.`user` ADD `shibb_unique_id` VARCHAR( 60 ) AFTER `auth_source`";
|
||||
$result_alter = Database::query($sql);
|
||||
|
||||
/*
|
||||
* Index cannot be a UNIQUE index as it may exist users which don't log in through Shibboleth
|
||||
* and therefore don't have any value for 'shibb_unique_id'
|
||||
*/
|
||||
$sql = "ALTER TABLE `$db_name`.`user` ADD INDEX ( `shibb_unique_id` )";
|
||||
$result_alter = Database::query($sql);
|
||||
}
|
||||
|
||||
public static function create_shibb_persistent_id_field_if_missing()
|
||||
{
|
||||
$db_name = Database :: get_main_database();
|
||||
|
||||
$sql = "SELECT * FROM $db_name.user LIMIT 1";
|
||||
$result = Database::query($sql);
|
||||
$row = mysql_fetch_assoc($result);
|
||||
$exists = array_key_exists('shibb_persistent_id', $row);
|
||||
|
||||
if ($exists)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$sql = "ALTER table $db_name.user ADD COLUMN shibb_persistent_id varchar(255) NULL DEFAULT NULL;";
|
||||
$result = Database::query($sql);
|
||||
return (bool) $result;
|
||||
}
|
||||
|
||||
}
|
||||
8
main/auth/shibboleth/index.php
Normal file
8
main/auth/shibboleth/index.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* Display nothing. This ensure Apache doesn't display the list of files and folders
|
||||
* when it is not propertly configured.
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
23
main/auth/shibboleth/init.php
Normal file
23
main/auth/shibboleth/init.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
/**
|
||||
* Initialize the Shibboleth authentication system. All scripts that can be directly
|
||||
* called must include this file
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
|
||||
$__dir = __DIR__.'/';
|
||||
$no_redirection = true; //no redirection in global.
|
||||
include_once($__dir . '/../../inc/global.inc.php');
|
||||
|
||||
require_once $__dir . 'config.php';
|
||||
|
||||
if (api_get_setting('server_type') == 'test')
|
||||
{
|
||||
include_once $__dir . '/test/shibboleth_test_helper.class.php';
|
||||
include_once $__dir . '/test/shibboleth_test.class.php';
|
||||
}
|
||||
14
main/auth/shibboleth/lib/model.class.php
Normal file
14
main/auth/shibboleth/lib/model.class.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
/**
|
||||
* Description of model
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
class Model
|
||||
{
|
||||
|
||||
}
|
||||
64
main/auth/shibboleth/lib/scaffolder/scaffolder.class.php
Normal file
64
main/auth/shibboleth/lib/scaffolder/scaffolder.class.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
/**
|
||||
* Scaffolder. Genereate code templates from the database layout.
|
||||
* See /template/ for the code being generated
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
class Scaffolder
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @staticvar boolean $result
|
||||
* @return Scaffolder
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
static $result = false;
|
||||
if (empty($result))
|
||||
{
|
||||
$result = new self();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function scaffold($table_name, $class_name = '', $prefix = '_')
|
||||
{
|
||||
$db_name = Database :: get_main_database();
|
||||
$sql = "SELECT * FROM `$db_name`.`$table_name` LIMIT 1";
|
||||
|
||||
$fields = array();
|
||||
$unique_fields = array();
|
||||
$rs = Database::query($sql, null, __FILE__);
|
||||
while ($field = mysql_fetch_field($rs))
|
||||
{
|
||||
$fields[] = $field;
|
||||
if ($field->primary_key)
|
||||
{
|
||||
/**
|
||||
* Could move that to an array to support multiple keys
|
||||
*/
|
||||
$id_name = $field->name;
|
||||
}
|
||||
if ($field->unique_key | $field->primary_key)
|
||||
{
|
||||
$keys[] = $field->name;
|
||||
}
|
||||
}
|
||||
$name = $table_name;
|
||||
$class_name = ucfirst($table_name);
|
||||
|
||||
|
||||
|
||||
ob_start();
|
||||
include __DIR__.'/template/model.php';
|
||||
$result = ob_get_clean();
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
146
main/auth/shibboleth/lib/scaffolder/template/default.php
Normal file
146
main/auth/shibboleth/lib/scaffolder/template/default.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
|
||||
echo '<?php';
|
||||
?>
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
/**
|
||||
* This file is autogenerated. Do not modifiy it.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* Model for table <?php echo $table_name ?>
|
||||
*
|
||||
* @copyright (c) 2012 University of Geneva
|
||||
* @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>
|
||||
*/
|
||||
class <?php echo $prefix . $class_name ?>
|
||||
|
||||
{
|
||||
|
||||
/**
|
||||
* Store for <?php echo $class_name ?> objects. Interact with the database.
|
||||
*
|
||||
* @return <?php echo $class_name ?>Store
|
||||
*/
|
||||
public static function store()
|
||||
{
|
||||
static $result = false;
|
||||
if (empty($result))
|
||||
{
|
||||
$result = new <?php echo $class_name ?>Store();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return <?php echo $class_name ?>
|
||||
*/
|
||||
public static function create($data = null)
|
||||
{
|
||||
return self::store()->create_object($data);
|
||||
}
|
||||
|
||||
<?php foreach($fields as $field){?>
|
||||
public $<?php echo $field->name; ?> = <?php echo $field->def ? $field->def : 'null'; ?>;
|
||||
<?php }?>
|
||||
|
||||
/**
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
return self::store()->save($this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Store for <?php echo $class_name ?> objects. Interact with the database.
|
||||
*
|
||||
* @copyright (c) 2012 University of Geneva
|
||||
* @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>
|
||||
*/
|
||||
class <?php echo $prefix . $class_name ?>Store extends Store
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @return <?php echo $class_name ?>Store
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
static $result = false;
|
||||
if (empty($result))
|
||||
{
|
||||
$result = new self();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('<?php echo $table_name;?>', '<?php echo $class_name;?>', '<?php echo $id_name;?>');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return <?php echo $class_name ?>
|
||||
*/
|
||||
public function get($w)
|
||||
{
|
||||
$args = func_get_args();
|
||||
$f = array('parent', 'get');
|
||||
return call_user_func_array($f, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return <?php echo $class_name ?>
|
||||
*/
|
||||
public function create_object($data)
|
||||
{
|
||||
return parent::create_object($data);
|
||||
}
|
||||
<?php foreach($keys as $key){?>
|
||||
|
||||
/**
|
||||
*
|
||||
* @return <?php echo $class_name ?>
|
||||
*/
|
||||
public function get_by_<?php echo $key ?>($value)
|
||||
{
|
||||
return $this->get(array('<?php echo $key; ?>' => $value));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function <?php echo $key ?>_exists($value)
|
||||
{
|
||||
return $this->exist(array('<?php echo $key; ?>' => $value));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete_by_<?php echo $key ?>($value)
|
||||
{
|
||||
return $this->delete(array('<?php echo $key; ?>' => $value));
|
||||
}
|
||||
<?php }?>
|
||||
}
|
||||
146
main/auth/shibboleth/lib/scaffolder/template/model.php
Normal file
146
main/auth/shibboleth/lib/scaffolder/template/model.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
|
||||
echo '<?php';
|
||||
?>
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
/**
|
||||
* This file is autogenerated. Do not modifiy it.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* Model for table <?php echo $table_name ?>
|
||||
*
|
||||
* @copyright (c) 2012 University of Geneva
|
||||
* @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>
|
||||
*/
|
||||
class <?php echo $prefix . $class_name ?>
|
||||
|
||||
{
|
||||
|
||||
/**
|
||||
* Store for <?php echo $class_name ?> objects. Interact with the database.
|
||||
*
|
||||
* @return <?php echo $class_name ?>Store
|
||||
*/
|
||||
public static function store()
|
||||
{
|
||||
static $result = false;
|
||||
if (empty($result))
|
||||
{
|
||||
$result = new <?php echo $class_name ?>Store();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return <?php echo $class_name ?>
|
||||
*/
|
||||
public static function create($data = null)
|
||||
{
|
||||
return self::store()->create_object($data);
|
||||
}
|
||||
|
||||
<?php foreach($fields as $field){?>
|
||||
public $<?php echo $field->name; ?> = <?php echo $field->def ? $field->def : 'null'; ?>;
|
||||
<?php }?>
|
||||
|
||||
/**
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
return self::store()->save($this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Store for <?php echo $class_name ?> objects. Interact with the database.
|
||||
*
|
||||
* @copyright (c) 2012 University of Geneva
|
||||
* @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>
|
||||
*/
|
||||
class <?php echo $prefix . $class_name ?>Store extends Store
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @return <?php echo $class_name ?>Store
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
static $result = false;
|
||||
if (empty($result))
|
||||
{
|
||||
$result = new self();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('<?php echo $table_name;?>', '<?php echo $class_name;?>', '<?php echo $id_name;?>');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return <?php echo $class_name ?>
|
||||
*/
|
||||
public function get($w)
|
||||
{
|
||||
$args = func_get_args();
|
||||
$f = array('parent', 'get');
|
||||
return call_user_func_array($f, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return <?php echo $class_name ?>
|
||||
*/
|
||||
public function create_object($data)
|
||||
{
|
||||
return parent::create_object($data);
|
||||
}
|
||||
<?php foreach($keys as $key){?>
|
||||
|
||||
/**
|
||||
*
|
||||
* @return <?php echo $class_name ?>
|
||||
*/
|
||||
public function get_by_<?php echo $key ?>($value)
|
||||
{
|
||||
return $this->get(array('<?php echo $key; ?>' => $value));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function <?php echo $key ?>_exists($value)
|
||||
{
|
||||
return $this->exist(array('<?php echo $key; ?>' => $value));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete_by_<?php echo $key ?>($value)
|
||||
{
|
||||
return $this->delete(array('<?php echo $key; ?>' => $value));
|
||||
}
|
||||
<?php }?>
|
||||
}
|
||||
39
main/auth/shibboleth/lib/scaffolder/template/public.php
Normal file
39
main/auth/shibboleth/lib/scaffolder/template/public.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
|
||||
echo '<?php';
|
||||
?>
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
/**
|
||||
*
|
||||
* Model for table <?php echo $table_name ?>
|
||||
*
|
||||
* @copyright (c) 2012 University of Geneva
|
||||
* @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>
|
||||
*/
|
||||
class <?php echo $class_name ?>
|
||||
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Store for <?php echo $class_name ?> objects. Interact with the database.
|
||||
*
|
||||
* @copyright (c) 2012 University of Geneva
|
||||
* @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>
|
||||
*/
|
||||
class <?php echo $class_name ?>Store extends Store
|
||||
{
|
||||
|
||||
}
|
||||
61
main/auth/shibboleth/lib/shibboleth_config.class.php
Normal file
61
main/auth/shibboleth/lib/shibboleth_config.class.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
/**
|
||||
* Shibboleth configuration. All configuration for the Shibboleth authentication
|
||||
* plugin: field names mapping, etc.
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
class ShibbolethConfig
|
||||
{
|
||||
public $unique_id = '';
|
||||
public $firstname = '';
|
||||
public $lastname = '';
|
||||
public $email = '';
|
||||
public $language = '';
|
||||
public $gender = '';
|
||||
public $address = '';
|
||||
public $staff_category = '';
|
||||
public $home_organization_type = '';
|
||||
public $home_organization = '';
|
||||
public $affiliation = '';
|
||||
public $persistent_id = '';
|
||||
|
||||
public $default_status = Shibboleth::UNKNOWN_STATUS;
|
||||
|
||||
/**
|
||||
* Mapping of affiliation => right
|
||||
* @var array
|
||||
*/
|
||||
public $affiliation_status = array();
|
||||
|
||||
/**
|
||||
* Mapping of affiliation => bool. Display the request status form.
|
||||
* @var array
|
||||
*/
|
||||
public $affiliation_status_request = array();
|
||||
|
||||
/**
|
||||
* List of fields to update when the user already exists field_name => boolean.
|
||||
* @var array
|
||||
*/
|
||||
public $update_fields = array();
|
||||
|
||||
/*
|
||||
* True if email is mandatory. False otherwise.
|
||||
*/
|
||||
public $is_email_mandatory = true;
|
||||
|
||||
/**
|
||||
* The email of the shibboleth administrator.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $admnistrator_email = '';
|
||||
|
||||
|
||||
|
||||
}
|
||||
100
main/auth/shibboleth/lib/shibboleth_session.class.php
Normal file
100
main/auth/shibboleth/lib/shibboleth_session.class.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
use ChamiloSession as Session;
|
||||
use Database;
|
||||
use Event;
|
||||
|
||||
/**
|
||||
* A Chamilo user session. Used as there is no session object so far provided by the core API.
|
||||
* Should be moved to the core library.Prefixed by Shibboleth to avoid name clashes.
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
class ShibbolethSession
|
||||
{
|
||||
/**
|
||||
* @return ShibbolethSession
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
static $result = false;
|
||||
if (empty($result)) {
|
||||
$result = new self();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function is_logged_in()
|
||||
{
|
||||
return isset($_SESSION['_user']['user_id']);
|
||||
}
|
||||
|
||||
function user()
|
||||
{
|
||||
return $_SESSION['_user'];
|
||||
}
|
||||
|
||||
function logout()
|
||||
{
|
||||
$_SESSION['_user'] = array();
|
||||
online_logout(null, false);
|
||||
global $logoutInfo;
|
||||
Event::courseLogout($logoutInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Shibboleth session for the user ID
|
||||
*
|
||||
* @param string $uid The user ID
|
||||
* @return array $_user The user infos array created when the user logs in
|
||||
*/
|
||||
function login($uid)
|
||||
{
|
||||
/* This must be set for local.inc.php to register correctly the global variables in session
|
||||
* This is BAD. Logic should be migrated into a function and stop relying on global variables.
|
||||
*/
|
||||
global $_uid, $is_allowedCreateCourse, $is_platformAdmin, $_real_cid, $is_courseAdmin;
|
||||
global $is_courseMember, $is_courseTutor, $is_session_general_coach, $is_allowed_in_course, $is_sessionAdmin, $_gid;
|
||||
$_uid = $uid;
|
||||
|
||||
//is_allowedCreateCourse
|
||||
$user = User::store()->get_by_user_id($uid);
|
||||
if (empty($user)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->logout();
|
||||
|
||||
Session::instance();
|
||||
Session::write('_uid', $_uid);
|
||||
|
||||
global $_user;
|
||||
$_user = (array) $user;
|
||||
|
||||
$_SESSION['_user'] = $_user;
|
||||
$_SESSION['_user']['user_id'] = $_uid;
|
||||
$_SESSION['noredirection'] = true;
|
||||
|
||||
//must be called before 'init_local.inc.php'
|
||||
Event::eventLogin($_uid);
|
||||
|
||||
//used in 'init_local.inc.php' this is BAD but and should be changed
|
||||
$loginFailed = false;
|
||||
$uidReset = true;
|
||||
|
||||
$gidReset = true;
|
||||
$cidReset = false; //FALSE !!
|
||||
|
||||
$mainDbName = Database :: get_main_database();
|
||||
$includePath = api_get_path(SYS_INC_PATH);
|
||||
|
||||
$no_redirection = true;
|
||||
require("$includePath/local.inc.php");
|
||||
|
||||
return $_user;
|
||||
}
|
||||
|
||||
}
|
||||
357
main/auth/shibboleth/lib/store.class.php
Normal file
357
main/auth/shibboleth/lib/store.class.php
Normal file
@@ -0,0 +1,357 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
use \Database;
|
||||
|
||||
/**
|
||||
* A database store. Used interact with the database - save objects, run queries.
|
||||
*
|
||||
* One store = one table.
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
class Store
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @return Store
|
||||
*/
|
||||
public static function create($table_name, $class_name = '', $id_name = 'id', $db_name = '')
|
||||
{
|
||||
return new self($table_name, $class_name, $id_name, $db_name);
|
||||
}
|
||||
|
||||
protected $db_name = '';
|
||||
protected $table_name = '';
|
||||
protected $id_name = '';
|
||||
protected $class_name = '';
|
||||
|
||||
function __construct($table_name, $class_name = '', $id_name = 'id', $db_name = '')
|
||||
{
|
||||
$this->db_name = $db_name ? $db_name : Database::get_main_database();
|
||||
$this->table_name = $table_name;
|
||||
$this->class_name = $class_name;
|
||||
$this->id_name = $id_name;
|
||||
}
|
||||
|
||||
function get_db_name($object = '')
|
||||
{
|
||||
if ($this->db_name)
|
||||
{
|
||||
return $this->db_name;
|
||||
}
|
||||
if ($object)
|
||||
{
|
||||
$result = isset($object->{db_name}) ? $object->{db_name} : '';
|
||||
$result = $result ? $result : Database :: get_main_database();
|
||||
return $result;
|
||||
}
|
||||
|
||||
return Database::get_main_database();
|
||||
}
|
||||
|
||||
function get($w)
|
||||
{
|
||||
$args = func_get_args();
|
||||
$f = array($this, 'get_where');
|
||||
$db_name = $this->get_db_name();
|
||||
$where = call_user_func_array($f, $args);
|
||||
$sql = "SELECT *
|
||||
FROM `{$db_name}`.`{$this->table_name}`
|
||||
WHERE $where";
|
||||
|
||||
$items = $this->query($sql);
|
||||
return (count($items) == 1) ? reset($items) : null;
|
||||
}
|
||||
|
||||
function select($w)
|
||||
{
|
||||
$args = func_get_args();
|
||||
$f = array($this, 'get_where');
|
||||
$db_name = $this->get_db_name();
|
||||
$where = call_user_func_array($f, $args);
|
||||
$sql = "SELECT *
|
||||
FROM `{$db_name}`.`{$this->table_name}`
|
||||
WHERE $where";
|
||||
|
||||
$result = $this->query($sql);
|
||||
return $result;
|
||||
}
|
||||
|
||||
function exist($w)
|
||||
{
|
||||
$args = func_get_args();
|
||||
$f = array($this, 'get');
|
||||
$object = call_user_func_array($f, $args);
|
||||
return !empty($object);
|
||||
}
|
||||
|
||||
function is_new($object)
|
||||
{
|
||||
$id_name = $this->id_name;
|
||||
$id = isset($object->{$id_name}) ? $object->{$id_name} : false;
|
||||
return empty($id);
|
||||
}
|
||||
|
||||
function save($object)
|
||||
{
|
||||
if (empty($object))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$object = is_array($object) ? $this->create_object($object) : $object;
|
||||
$this->before_save($object);
|
||||
if ($this->is_new($object))
|
||||
{
|
||||
$result = $this->insert($object);
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = $this->update($object);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function delete($object)
|
||||
{
|
||||
$args = func_get_args();
|
||||
$f = array($this, 'get_where');
|
||||
$db_name = $this->get_db_name();
|
||||
$where = call_user_func_array($f, $args);
|
||||
$sql = "DELETE
|
||||
FROM `{$db_name
|
||||
}
|
||||
|
||||
`.`{$this->table_name
|
||||
}
|
||||
|
||||
`
|
||||
WHERE $where";
|
||||
|
||||
$result = $this->query($sql);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param array|object $data
|
||||
* @return object
|
||||
*/
|
||||
public function create_object($data = array())
|
||||
{
|
||||
$data = $data ? $data : array();
|
||||
$data = (object) $data;
|
||||
$class = $this->class_name;
|
||||
if (empty($class))
|
||||
{
|
||||
return clone $data;
|
||||
}
|
||||
$result = new $class();
|
||||
|
||||
foreach ($result as $key => $value)
|
||||
{
|
||||
$result->{$key} = property_exists($data, $key) ? $data->{$key} : null;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function fields($object)
|
||||
{
|
||||
static $result = array();
|
||||
if (!empty($result))
|
||||
{
|
||||
return $result;
|
||||
}
|
||||
|
||||
$db_name = $this->get_db_name($object);
|
||||
$sql = "SELECT *
|
||||
FROM `{$db_name}`.`{$this->table_name}`
|
||||
LIMIT 1";
|
||||
$rs = Database::query($sql, null, __FILE__);
|
||||
while ($field = mysql_fetch_field($rs))
|
||||
{
|
||||
$result[] = $field;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function before_save($object)
|
||||
{
|
||||
//hook
|
||||
}
|
||||
|
||||
protected function update($object)
|
||||
{
|
||||
$id = isset($object->{$this->id_name}) ? $object->{$this->id_name} : false;
|
||||
if (empty($id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$items = array();
|
||||
$fields = $this->fields($object);
|
||||
foreach ($fields as $field)
|
||||
{
|
||||
$name = $field->name;
|
||||
if ($name != $this->id_name)
|
||||
{
|
||||
if (property_exists($object, $name))
|
||||
{
|
||||
$value = $object->{$name};
|
||||
$value = $this->format_value($value);
|
||||
$items[] = "$name=$value";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$db_name = $this->get_db_name($object);
|
||||
$sql = "UPDATE `{$db_name}`.`{$this->table_name}` SET ";
|
||||
$sql .= join(', ', $items);
|
||||
$sql .= " WHERE {$this->id_name}=$id";
|
||||
|
||||
$result = $this->execute($sql);
|
||||
if ($result)
|
||||
{
|
||||
$object->{db_name} = $db_name;
|
||||
}
|
||||
return (bool) $result;
|
||||
}
|
||||
|
||||
protected function insert($object)
|
||||
{
|
||||
$id = isset($object->{$this->id_name}) ? $object->{$this->id_name} : false;
|
||||
if (empty($object))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$values = array();
|
||||
$keys = array();
|
||||
$fields = $this->fields($object);
|
||||
foreach ($fields as $field)
|
||||
{
|
||||
$name = $field->name;
|
||||
if ($name != $this->id_name)
|
||||
{
|
||||
if (property_exists($object, $name))
|
||||
{
|
||||
$value = $object->{$name};
|
||||
$value = is_null($value) ? 'DEFAULT' : $this->format_value($value);
|
||||
$values[] = $value;
|
||||
$keys[] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$db_name = $this->get_db_name($object);
|
||||
$sql = "INSERT INTO `{$db_name}`.`{$this->table_name}` ";
|
||||
$sql .= ' (' . join(', ', $keys) . ') ';
|
||||
$sql .= 'VALUES';
|
||||
$sql .= ' (' . join(', ', $values) . ') ';
|
||||
|
||||
$result = $this->execute($sql);
|
||||
if ($result)
|
||||
{
|
||||
$id = mysql_insert_id();
|
||||
$object->{$this->id_name} = $id;
|
||||
$object->{db_name} = $db_name;
|
||||
return $id;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected function get_where($_)
|
||||
{
|
||||
$args = func_get_args();
|
||||
if (count($args) == 1)
|
||||
{
|
||||
$arg = reset($args);
|
||||
if (is_numeric($arg))
|
||||
{
|
||||
$id = (int) $arg;
|
||||
if (empty($id))
|
||||
{
|
||||
return '';
|
||||
}
|
||||
$args = array($this->pk_name, $arg);
|
||||
}
|
||||
else if (is_string($arg))
|
||||
{
|
||||
return $arg;
|
||||
}
|
||||
else if (is_array($arg))
|
||||
{
|
||||
$args = $arg;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $arg;
|
||||
}
|
||||
}
|
||||
$items = array();
|
||||
foreach ($args as $key => $val)
|
||||
{
|
||||
$items[] = $key . ' = ' . $this->format_value($val);
|
||||
}
|
||||
return implode(' AND ', $items);
|
||||
}
|
||||
|
||||
protected function format_value($value)
|
||||
{
|
||||
if (is_null($value))
|
||||
{
|
||||
return 'NULL';
|
||||
}
|
||||
if (is_bool($var))
|
||||
{
|
||||
return $value ? '1' : '0';
|
||||
}
|
||||
else if (is_numeric($value))
|
||||
{
|
||||
return empty($value) ? '0' : $value;
|
||||
}
|
||||
else if (is_string($value))
|
||||
{
|
||||
$value = mysql_escape_string($value);
|
||||
return "'$value'";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $sql
|
||||
* @return array
|
||||
*/
|
||||
protected function query($sql)
|
||||
{
|
||||
$resource = Database::query($sql, null, __FILE__);
|
||||
if ($resource == false)
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
$result = array();
|
||||
while ($data = mysql_fetch_assoc($resource))
|
||||
{
|
||||
$result[] = $this->create_object($data);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sql
|
||||
*/
|
||||
protected function execute($sql)
|
||||
{
|
||||
return Database::query($sql, null, __FILE__);
|
||||
}
|
||||
|
||||
}
|
||||
35
main/auth/shibboleth/login.php
Normal file
35
main/auth/shibboleth/login.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
/**
|
||||
* Shibboleth login page.
|
||||
*
|
||||
* Actual authentication is provided by the Shibboleth Apache security module.
|
||||
* Shibboleth must be properly installed and configured. Then this page must
|
||||
* be secured through an Apache security directive.
|
||||
*
|
||||
* When Shibboleth is properly set up this page will only be available for
|
||||
* authenticated users. The plugin ensure those people are created and logged in.
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
include_once __DIR__.'/init.php';
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
TEST SECTION
|
||||
==============================================================================
|
||||
*
|
||||
* @todo: Only for testing. Comment that out for production
|
||||
*
|
||||
*/
|
||||
//Shibboleth::session()->logout();
|
||||
//ShibbolethTest::helper()->setup_new_student_no_email();
|
||||
//ShibbolethTest::helper()->setup_staff();
|
||||
//ShibbolethTest::helper()->setup_new_teacher();
|
||||
//ShibbolethTest::helper()->setup_new_student();
|
||||
//ShibbolethTest::helper()->setup_new_minimal_data();
|
||||
|
||||
ShibbolethController::instance()->login();
|
||||
36
main/auth/shibboleth/script/scaffold.php
Normal file
36
main/auth/shibboleth/script/scaffold.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
/**
|
||||
* Scaffold script. Generates the required database models for the Shibboleth
|
||||
* plugin.
|
||||
*
|
||||
* Will only run when the server is a test server.
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
$dir = __DIR__;
|
||||
include_once $dir.'/../init.php';
|
||||
include_once $dir.'/../app/lib/scaffolder/scaffolder.class.php';
|
||||
|
||||
if (!ShibbolethTest::is_enabled())
|
||||
{
|
||||
echo 'This is not a test server';
|
||||
die;
|
||||
}
|
||||
|
||||
if (!Shibboleth::session()->is_logged_in())
|
||||
{
|
||||
echo 'Not authorized';
|
||||
die;
|
||||
}
|
||||
|
||||
$name = 'user';
|
||||
$result = Scaffolder::instance()->scaffold($name);
|
||||
|
||||
file_put_contents("$dir/output/$name.class.php", $result);
|
||||
|
||||
header('content-type: text/plain');
|
||||
echo $result;
|
||||
218
main/auth/shibboleth/test/shibboleth_test.class.php
Normal file
218
main/auth/shibboleth/test/shibboleth_test.class.php
Normal file
@@ -0,0 +1,218 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
/**
|
||||
* Various Unit Tests. Note that those tests create users in the database but
|
||||
* don't delete them.
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
class ShibbolethTest
|
||||
{
|
||||
|
||||
static function is_enabled()
|
||||
{
|
||||
return api_get_setting('server_type') == 'test';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ShibbolethTestHelper
|
||||
*/
|
||||
static function helper()
|
||||
{
|
||||
return ShibbolethTestHelper::instance();
|
||||
}
|
||||
|
||||
static function init()
|
||||
{
|
||||
if (!self::is_enabled())
|
||||
{
|
||||
die;
|
||||
}
|
||||
}
|
||||
|
||||
static function test_new_teacher()
|
||||
{
|
||||
self::init();
|
||||
|
||||
self::helper()->setup_new_teacher();
|
||||
$shib_user = Shibboleth::store()->get_user();
|
||||
self::assert(!User::store()->shibboleth_id_exists($shib_user->unique_id));
|
||||
|
||||
Shibboleth::save($shib_user);
|
||||
|
||||
$user = User::store()->get_by_shibboleth_id($shib_user->unique_id);
|
||||
self::assert($user->email == $shib_user->email);
|
||||
self::assert($user->firstname == $shib_user->firstname);
|
||||
self::assert($user->lastname == $shib_user->lastname);
|
||||
self::assert($user->persistent_id == $shib_user->persistent_id);
|
||||
self::assert($user->status == Shibboleth::TEACHER_STATUS);
|
||||
self::assert(!empty($user->password));
|
||||
self::assert(!empty($user->username));
|
||||
}
|
||||
|
||||
static function test_new_student()
|
||||
{
|
||||
self::init();
|
||||
|
||||
self::helper()->setup_new_student();
|
||||
|
||||
$shib_user = Shibboleth::store()->get_user();
|
||||
self::assert(!User::store()->shibboleth_id_exists($shib_user->unique_id));
|
||||
|
||||
Shibboleth::save($shib_user);
|
||||
|
||||
$user = User::store()->get_by_shibboleth_id($shib_user->unique_id);
|
||||
self::assert($user->email == $shib_user->email);
|
||||
self::assert($user->firstname == $shib_user->firstname);
|
||||
self::assert($user->lastname == $shib_user->lastname);
|
||||
self::assert($user->persistent_id == $shib_user->persistent_id);
|
||||
self::assert($user->status == Shibboleth::STUDENT_STATUS);
|
||||
self::assert(!empty($user->password));
|
||||
self::assert(!empty($user->username));
|
||||
}
|
||||
|
||||
static function test_new_staff()
|
||||
{
|
||||
self::init();
|
||||
|
||||
self::helper()->setup_new_staff();
|
||||
|
||||
$shib_user = Shibboleth::store()->get_user();
|
||||
self::assert(!User::store()->shibboleth_id_exists($shib_user->unique_id));
|
||||
|
||||
Shibboleth::save($shib_user);
|
||||
|
||||
$user = User::store()->get_by_shibboleth_id($shib_user->unique_id);
|
||||
self::assert($user->email == $shib_user->email);
|
||||
self::assert($user->firstname == $shib_user->firstname);
|
||||
self::assert($user->lastname == $shib_user->lastname);
|
||||
self::assert($user->persistent_id == $shib_user->persistent_id);
|
||||
self::assert($user->status == Shibboleth::STUDENT_STATUS);
|
||||
self::assert(!empty($user->password));
|
||||
self::assert(!empty($user->username));
|
||||
}
|
||||
|
||||
static function test_new_infer_status_request()
|
||||
{
|
||||
self::init();
|
||||
|
||||
self::helper()->setup_new_staff();
|
||||
$shib_user = Shibboleth::store()->get_user();
|
||||
Shibboleth::save($shib_user);
|
||||
self::assert($shib_user->status_request);
|
||||
|
||||
self::helper()->setup_new_teacher();
|
||||
$shib_user = Shibboleth::store()->get_user();
|
||||
Shibboleth::save($shib_user);
|
||||
|
||||
self::assert(!$shib_user->status_request);
|
||||
|
||||
self::helper()->setup_new_student();
|
||||
$shib_user = Shibboleth::store()->get_user();
|
||||
Shibboleth::save($shib_user);
|
||||
|
||||
self::assert(!$shib_user->status_request);
|
||||
}
|
||||
|
||||
static function test_update_teacher()
|
||||
{
|
||||
self::init();
|
||||
|
||||
$fields = Shibboleth::config()->update_fields;
|
||||
self::assert($fields['email']);
|
||||
self::assert($fields['persistent_id']);
|
||||
self::assert($fields['firstname']);
|
||||
self::assert($fields['lastname']);
|
||||
self::assert(!$fields['status']);
|
||||
|
||||
self::helper()->setup_teacher();
|
||||
$shib_user = Shibboleth::store()->get_user();
|
||||
Shibboleth::save($shib_user);
|
||||
|
||||
$new_shib_user = clone($shib_user);
|
||||
|
||||
$new_shib_user->firstname = 'frs';
|
||||
$new_shib_user->lastname = 'ls';
|
||||
$new_shib_user->email = 'em';
|
||||
$new_shib_user->status = 10;
|
||||
$new_shib_user->persistent_id = 'per';
|
||||
|
||||
Shibboleth::save($new_shib_user);
|
||||
$user = User::store()->get_by_shibboleth_id($shib_user->unique_id);
|
||||
|
||||
self::assert($user->email == $new_shib_user->email);
|
||||
self::assert($value = ($user->shibb_persistent_id == $new_shib_user->persistent_id));
|
||||
|
||||
self::assert($user->firstname == $new_shib_user->firstname);
|
||||
self::assert($user->lastname == $new_shib_user->lastname);
|
||||
self::assert($user->status == $shib_user->status);
|
||||
self::assert(!empty($user->password));
|
||||
self::assert(!empty($user->username));
|
||||
}
|
||||
|
||||
static function test_new_student_multiple_givenname()
|
||||
{
|
||||
self::init();
|
||||
|
||||
self::helper()->setup_new_student_multiple_givenname();
|
||||
|
||||
$shib_user = Shibboleth::store()->get_user();
|
||||
self::assert(!User::store()->shibboleth_id_exists($shib_user->unique_id));
|
||||
|
||||
Shibboleth::save($shib_user);
|
||||
|
||||
$user = User::store()->get_by_shibboleth_id($shib_user->unique_id);
|
||||
|
||||
self::assert($user->email == $shib_user->email);
|
||||
self::assert($user->firstname == 'John');
|
||||
self::assert($user->lastname == $shib_user->lastname);
|
||||
self::assert($user->persistent_id == $shib_user->persistent_id);
|
||||
self::assert($user->status == Shibboleth::STUDENT_STATUS);
|
||||
self::assert(!empty($user->password));
|
||||
self::assert(!empty($user->username));
|
||||
}
|
||||
|
||||
static function test_new_no_affiliation_default()
|
||||
{
|
||||
self::init();
|
||||
|
||||
self::helper()->setup_new_no_affiliation();
|
||||
$shib_user = Shibboleth::store()->get_user();
|
||||
self::assert($config = Shibboleth::config()->default_status == Shibboleth::STUDENT_STATUS);
|
||||
self::assert(!User::store()->shibboleth_id_exists($shib_user->unique_id));
|
||||
self::assert($shib_user->affiliation == '');
|
||||
|
||||
Shibboleth::save($shib_user);
|
||||
|
||||
$user = User::store()->get_by_shibboleth_id($shib_user->unique_id);
|
||||
|
||||
self::assert($user->email == $shib_user->email);
|
||||
self::assert($user->firstname == 'John');
|
||||
self::assert($user->lastname == $shib_user->lastname);
|
||||
self::assert($user->persistent_id == $shib_user->persistent_id);
|
||||
self::assert($user->status == Shibboleth::STUDENT_STATUS);
|
||||
self::assert(!empty($user->password));
|
||||
self::assert(!empty($user->username));
|
||||
}
|
||||
|
||||
static function assert($assertion, $message = '')
|
||||
{
|
||||
if (!$assertion)
|
||||
{
|
||||
$message = "Assert failed $message <br/>";
|
||||
echo $message;
|
||||
// Dump variable for debug
|
||||
error_log(print_r(debug_backtrace(), 1));
|
||||
die;
|
||||
}
|
||||
else
|
||||
{
|
||||
$message = "Assert successful $message <br/>";
|
||||
echo $message;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
133
main/auth/shibboleth/test/shibboleth_test_helper.class.php
Normal file
133
main/auth/shibboleth/test/shibboleth_test_helper.class.php
Normal file
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
/**
|
||||
* Helper functions for the tests. Set up various dummy user types: teacher, student, etc.
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
class ShibbolethTestHelper
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @return ShibbolethTestHelper
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
static $result = false;
|
||||
if (empty($result))
|
||||
{
|
||||
$result = new self();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function setup_teacher()
|
||||
{
|
||||
$_SERVER['Shib-SwissEP-UniqueID'] = 'usr_1';
|
||||
$_SERVER['Shib-EP-Affiliation'] = 'member;staff;faculty';
|
||||
$_SERVER['Shib-InetOrgPerson-givenName'] = 'John';
|
||||
$_SERVER['Shib-Person-surname'] = 'Doe';
|
||||
$_SERVER['Shib-InetOrgPerson-mail'] = 'john.doe@localhost.org';
|
||||
$_SERVER['persistent-id'] = 'idp!viewer!drea34çcv3d';
|
||||
}
|
||||
|
||||
public function setup_student()
|
||||
{
|
||||
$_SERVER['Shib-SwissEP-UniqueID'] = 'usr_1';
|
||||
$_SERVER['Shib-EP-Affiliation'] = 'member';
|
||||
$_SERVER['Shib-InetOrgPerson-givenName'] = 'John';
|
||||
$_SERVER['Shib-Person-surname'] = 'Doe';
|
||||
$_SERVER['Shib-InetOrgPerson-mail'] = 'john.doe@localhost.org';
|
||||
$_SERVER['persistent-id'] = 'idp!viewer!drea34çcv3d';
|
||||
}
|
||||
|
||||
public function setup_staff()
|
||||
{
|
||||
$id = uniqid();
|
||||
$_SERVER['Shib-SwissEP-UniqueID'] = 'usr_123456';
|
||||
$_SERVER['Shib-EP-Affiliation'] = 'member;staff';
|
||||
$_SERVER['Shib-InetOrgPerson-givenName'] = 'John Staff';
|
||||
$_SERVER['Shib-Person-surname'] = 'Doe';
|
||||
$_SERVER['Shib-InetOrgPerson-mail'] = 'john.staff.doe@localhost.org';
|
||||
$_SERVER['persistent-id'] = 'idp!viewer!usr_123456';
|
||||
}
|
||||
|
||||
public function setup_new_student()
|
||||
{
|
||||
$id = uniqid();
|
||||
$_SERVER['Shib-SwissEP-UniqueID'] = 'usr_' . $id;
|
||||
$_SERVER['Shib-EP-Affiliation'] = 'member';
|
||||
$_SERVER['Shib-InetOrgPerson-givenName'] = 'John';
|
||||
$_SERVER['Shib-Person-surname'] = 'Doe' . $id;
|
||||
$_SERVER['Shib-InetOrgPerson-mail'] = 'john.' . $id . 'Doe@localhost.org';
|
||||
$_SERVER['persistent-id'] = 'idp!viewer!' . md5($id);
|
||||
}
|
||||
|
||||
public function setup_new_student_no_email()
|
||||
{
|
||||
$id = uniqid();
|
||||
$_SERVER['Shib-SwissEP-UniqueID'] = 'usr_' . $id;
|
||||
$_SERVER['Shib-EP-Affiliation'] = 'member';
|
||||
$_SERVER['Shib-InetOrgPerson-givenName'] = 'John';
|
||||
$_SERVER['Shib-Person-surname'] = 'Doe' . $id;
|
||||
$_SERVER['Shib-InetOrgPerson-mail'] = '';
|
||||
$_SERVER['persistent-id'] = 'idp!viewer!' . md5($id);
|
||||
}
|
||||
|
||||
public function setup_new_student_multiple_givenname()
|
||||
{
|
||||
$id = uniqid();
|
||||
$_SERVER['Shib-SwissEP-UniqueID'] = 'usr_' . $id;
|
||||
$_SERVER['Shib-EP-Affiliation'] = 'member';
|
||||
$_SERVER['Shib-InetOrgPerson-givenName'] = 'John;Alex;John Alex';
|
||||
$_SERVER['Shib-Person-surname'] = 'Doe' . $id;
|
||||
$_SERVER['Shib-InetOrgPerson-mail'] = 'john.' . $id . 'Doe@localhost.org';
|
||||
$_SERVER['persistent-id'] = 'idp!viewer!' . md5($id);
|
||||
}
|
||||
|
||||
public function setup_new_teacher()
|
||||
{
|
||||
$id = uniqid();
|
||||
$_SERVER['Shib-SwissEP-UniqueID'] = 'usr_' . $id;
|
||||
$_SERVER['Shib-EP-Affiliation'] = 'member;staff;faculty';
|
||||
$_SERVER['Shib-InetOrgPerson-givenName'] = 'John';
|
||||
$_SERVER['Shib-Person-surname'] = 'Doe' . $id;
|
||||
$_SERVER['Shib-InetOrgPerson-mail'] = 'john.' . $id . 'Doe@localhost.org';
|
||||
$_SERVER['persistent-id'] = 'idp!viewer!' . md5($id);
|
||||
}
|
||||
|
||||
public function setup_new_staff()
|
||||
{
|
||||
$id = uniqid();
|
||||
$_SERVER['Shib-SwissEP-UniqueID'] = 'usr_' . $id;
|
||||
$_SERVER['Shib-EP-Affiliation'] = 'member;staff';
|
||||
$_SERVER['Shib-InetOrgPerson-givenName'] = 'John';
|
||||
$_SERVER['Shib-Person-surname'] = 'Doe' . $id;
|
||||
$_SERVER['Shib-InetOrgPerson-mail'] = 'john.' . $id . 'Doe@localhost.org';
|
||||
$_SERVER['persistent-id'] = 'idp!viewer!' . md5($id);
|
||||
}
|
||||
|
||||
public function setup_new_no_affiliation()
|
||||
{
|
||||
$id = uniqid();
|
||||
$_SERVER['Shib-SwissEP-UniqueID'] = 'usr_' . $id;
|
||||
$_SERVER['Shib-EP-Affiliation'] = '';
|
||||
$_SERVER['Shib-InetOrgPerson-givenName'] = 'John';
|
||||
$_SERVER['Shib-Person-surname'] = 'Doe' . $id;
|
||||
$_SERVER['Shib-InetOrgPerson-mail'] = 'john.' . $id . 'Doe@localhost.org';
|
||||
$_SERVER['persistent-id'] = 'idp!viewer!' . md5($id);
|
||||
}
|
||||
|
||||
public function setup_new_minimal_data()
|
||||
{
|
||||
$id = uniqid();
|
||||
$_SERVER['Shib-SwissEP-UniqueID'] = 'usr_' . $id;
|
||||
$_SERVER['Shib-InetOrgPerson-givenName'] = 'John';
|
||||
$_SERVER['Shib-Person-surname'] = 'Doe' . $id;
|
||||
}
|
||||
|
||||
}
|
||||
32
main/auth/shibboleth/test/test.php
Normal file
32
main/auth/shibboleth/test/test.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
/**
|
||||
* Run unit tests. Server needs to be a test server to run those.
|
||||
*
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
include_once __DIR__.'/../init.php';
|
||||
|
||||
if (!ShibbolethTest::is_enabled())
|
||||
{
|
||||
echo 'This is not a test server';
|
||||
die;
|
||||
}
|
||||
|
||||
echo 'Test started<br/>-------------------<br/>';
|
||||
|
||||
ShibbolethTest::test_new_teacher();
|
||||
ShibbolethTest::test_new_student();
|
||||
ShibbolethTest::test_update_teacher();
|
||||
ShibbolethTest::test_new_student_multiple_givenname();
|
||||
ShibbolethTest::test_new_no_affiliation_default();
|
||||
ShibbolethTest::test_new_staff();
|
||||
ShibbolethTest::test_new_infer_status_request();
|
||||
|
||||
echo '-------------------<br/>Done!';
|
||||
|
||||
|
||||
|
||||
20
main/auth/shibboleth/test/test_no_email.php
Normal file
20
main/auth/shibboleth/test/test_no_email.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Shibboleth;
|
||||
|
||||
/**
|
||||
* @license see /license.txt
|
||||
* @author Laurent Opprecht <laurent@opprecht.info>, Nicolas Rod for the University of Geneva
|
||||
*/
|
||||
include_once __DIR__.'/../init.php';
|
||||
|
||||
if (!ShibbolethTest::is_enabled())
|
||||
{
|
||||
echo 'This is not a test server';
|
||||
die;
|
||||
}
|
||||
|
||||
Shibboleth::session()->logout();
|
||||
ShibbolethTest::helper()->setup_new_student_no_email();
|
||||
|
||||
require_once __DIR__.'/../login.php';
|
||||
478
main/auth/sort_my_courses.php
Normal file
478
main/auth/sort_my_courses.php
Normal file
@@ -0,0 +1,478 @@
|
||||
<?php
|
||||
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
$cidReset = true; // Flag forcing the 'current course' reset
|
||||
|
||||
require_once __DIR__.'/../inc/global.inc.php';
|
||||
|
||||
api_block_anonymous_users();
|
||||
|
||||
$auth = new Auth();
|
||||
$user_course_categories = CourseManager::get_user_course_categories(api_get_user_id());
|
||||
$courses_in_category = $auth->getCoursesInCategory(false);
|
||||
|
||||
// Only authorized actions
|
||||
$authorizedActions = [
|
||||
'edit_category',
|
||||
'edit_course_category',
|
||||
'deletecoursecategory',
|
||||
'createcoursecategory',
|
||||
'set_collapsable',
|
||||
'unsubscribe',
|
||||
];
|
||||
if (in_array(trim($_REQUEST['action']), $authorizedActions)) {
|
||||
$action = trim($_REQUEST['action']);
|
||||
}
|
||||
|
||||
$currentUrl = api_get_self();
|
||||
|
||||
$interbreadcrumb[] = [
|
||||
'url' => api_get_self(),
|
||||
'name' => get_lang('SortMyCourses'),
|
||||
];
|
||||
|
||||
// We are moving the course of the user to a different user defined course category (=Sort My Courses).
|
||||
if (isset($_POST['submit_change_course_category'])) {
|
||||
$course2EditCategory = Security::remove_XSS($_POST['course_2_edit_category']);
|
||||
$courseCategories = Security::remove_XSS($_POST['course_categories']);
|
||||
$result = $auth->updateCourseCategory($course2EditCategory, $courseCategories);
|
||||
if ($result) {
|
||||
Display::addFlash(
|
||||
Display::return_message(get_lang('EditCourseCategorySucces'))
|
||||
);
|
||||
}
|
||||
header('Location: '.api_get_self());
|
||||
exit;
|
||||
}
|
||||
|
||||
// We edit course category
|
||||
if (isset($_POST['submit_edit_course_category']) &&
|
||||
isset($_POST['title_course_category'])
|
||||
) {
|
||||
$titleCourseCategory = Security::remove_XSS($_POST['title_course_category']);
|
||||
$categoryId = Security::remove_XSS($_POST['category_id']);
|
||||
$result = $auth->store_edit_course_category($titleCourseCategory, $categoryId);
|
||||
if ($result) {
|
||||
Display::addFlash(
|
||||
Display::return_message(get_lang('CourseCategoryEditStored'))
|
||||
);
|
||||
}
|
||||
|
||||
header('Location: '.api_get_self());
|
||||
exit;
|
||||
}
|
||||
|
||||
// We are creating a new user defined course category (= Create Course Category).
|
||||
if (isset($_POST['create_course_category']) &&
|
||||
isset($_POST['title_course_category']) &&
|
||||
strlen(trim($_POST['title_course_category'])) > 0
|
||||
) {
|
||||
$titleCourseCategory = Security::remove_XSS($_POST['title_course_category']);
|
||||
$result = $auth->store_course_category($titleCourseCategory);
|
||||
if ($result) {
|
||||
Display::addFlash(
|
||||
Display::return_message(get_lang('CourseCategoryStored'))
|
||||
);
|
||||
} else {
|
||||
Display::addFlash(
|
||||
Display::return_message(
|
||||
get_lang('ACourseCategoryWithThisNameAlreadyExists'),
|
||||
'error'
|
||||
)
|
||||
);
|
||||
}
|
||||
header('Location: '.api_get_self());
|
||||
exit;
|
||||
}
|
||||
|
||||
// We are moving a course or category of the user up/down the list (=Sort My Courses).
|
||||
if (isset($_GET['move'])) {
|
||||
$getCourse = isset($_GET['course']) ? Security::remove_XSS($_GET['course']) : '';
|
||||
$getMove = Security::remove_XSS($_GET['move']);
|
||||
$getCategory = isset($_GET['category']) ? Security::remove_XSS($_GET['category']) : '';
|
||||
if (!empty($getCourse)) {
|
||||
$result = $auth->move_course($getMove, $getCourse, $getCategory);
|
||||
if ($result) {
|
||||
Display::addFlash(
|
||||
Display::return_message(get_lang('CourseSortingDone'))
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!empty($getCategory) && empty($getCourse)) {
|
||||
$result = $auth->move_category($getMove, $getCategory);
|
||||
if ($result) {
|
||||
Display::addFlash(
|
||||
Display::return_message(get_lang('CategorySortingDone'))
|
||||
);
|
||||
}
|
||||
}
|
||||
header('Location: '.api_get_self());
|
||||
exit;
|
||||
}
|
||||
|
||||
switch ($action) {
|
||||
case 'edit_category':
|
||||
$categoryId = isset($_GET['category_id']) ? (int) $_GET['category_id'] : 0;
|
||||
$categoryInfo = $auth->getUserCourseCategory($categoryId);
|
||||
if ($categoryInfo) {
|
||||
$categoryName = $categoryInfo['title'];
|
||||
$form = new FormValidator(
|
||||
'edit_course_category',
|
||||
'post',
|
||||
$currentUrl.'?action=edit_category'
|
||||
);
|
||||
$form->addText('title_course_category', get_lang('Name'));
|
||||
$form->addHidden('category_id', $categoryId);
|
||||
$form->addButtonSave(get_lang('Edit'), 'submit_edit_course_category');
|
||||
$form->setDefaults(['title_course_category' => $categoryName]);
|
||||
$form->display();
|
||||
}
|
||||
exit;
|
||||
break;
|
||||
case 'edit_course_category':
|
||||
$edit_course = (int) $_GET['course_id'];
|
||||
$defaultCategoryId = isset($_GET['category_id']) ? (int) $_GET['category_id'] : 0;
|
||||
$courseInfo = api_get_course_info_by_id($edit_course);
|
||||
|
||||
if (empty($courseInfo)) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$form = new FormValidator(
|
||||
'edit_course_category',
|
||||
'post',
|
||||
$currentUrl.'?action=edit_course_category'
|
||||
);
|
||||
|
||||
$form->addHeader($courseInfo['title']);
|
||||
|
||||
$options = [];
|
||||
foreach ($user_course_categories as $row) {
|
||||
$options[$row['id']] = $row['title'];
|
||||
}
|
||||
asort($options);
|
||||
|
||||
$form->addSelect(
|
||||
'course_categories',
|
||||
get_lang('Categories'),
|
||||
$options,
|
||||
['disable_js' => true, 'placeholder' => get_lang('SelectAnOption')]
|
||||
);
|
||||
$form->addHidden('course_2_edit_category', $edit_course);
|
||||
|
||||
if (!empty($defaultCategoryId)) {
|
||||
$form->setDefaults(['course_categories' => $defaultCategoryId]);
|
||||
}
|
||||
$form->addButtonSave(get_lang('Save'), 'submit_change_course_category');
|
||||
$form->display();
|
||||
exit;
|
||||
break;
|
||||
case 'deletecoursecategory':
|
||||
// we are deleting a course category
|
||||
if (isset($_GET['id'])) {
|
||||
if (Security::check_token('get')) {
|
||||
$getId = Security::remove_XSS($_GET['id']);
|
||||
$result = $auth->delete_course_category($getId);
|
||||
if ($result) {
|
||||
Display::addFlash(
|
||||
Display::return_message(get_lang('CourseCategoryDeleted'))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
header('Location: '.api_get_self());
|
||||
exit;
|
||||
break;
|
||||
case 'createcoursecategory':
|
||||
$form = new FormValidator(
|
||||
'create_course_category',
|
||||
'post',
|
||||
$currentUrl.'?action=createcoursecategory'
|
||||
);
|
||||
$form->addText('title_course_category', get_lang('Name'));
|
||||
$form->addButtonSave(get_lang('AddCategory'), 'create_course_category');
|
||||
$form->display();
|
||||
exit;
|
||||
break;
|
||||
case 'set_collapsable':
|
||||
if (!api_get_configuration_value('allow_user_course_category_collapsable')) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$userId = api_get_user_id();
|
||||
$categoryId = isset($_REQUEST['categoryid']) ? (int) $_REQUEST['categoryid'] : 0;
|
||||
$option = isset($_REQUEST['option']) ? (int) $_REQUEST['option'] : 0;
|
||||
$redirect = isset($_REQUEST['redirect']) ? Security::remove_XSS($_REQUEST['redirect']) : 0;
|
||||
|
||||
if (empty($userId) || empty($categoryId)) {
|
||||
api_not_allowed(true);
|
||||
}
|
||||
|
||||
$table = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
|
||||
$sql = "UPDATE $table
|
||||
SET collapsed = $option
|
||||
WHERE user_id = $userId AND id = $categoryId";
|
||||
Database::query($sql);
|
||||
Display::addFlash(Display::return_message(get_lang('Updated')));
|
||||
|
||||
if ($redirect === 'home') {
|
||||
$url = api_get_path(WEB_PATH).'user_portal.php';
|
||||
header('Location: '.$url);
|
||||
exit;
|
||||
}
|
||||
|
||||
$url = api_get_self();
|
||||
header('Location: '.$url);
|
||||
exit;
|
||||
break;
|
||||
}
|
||||
|
||||
function generateUnsubscribeForm(string $courseCode, string $secToken): string
|
||||
{
|
||||
$alertMessage = api_htmlentities(get_lang("ConfirmUnsubscribeFromCourse"), ENT_QUOTES);
|
||||
|
||||
$form = new FormValidator(
|
||||
'frm_unsubscribe',
|
||||
'get',
|
||||
api_get_path(WEB_CODE_PATH).'auth/courses.php',
|
||||
'',
|
||||
[
|
||||
'onsubmit' => 'javascript: if (!confirm(\''.addslashes($alertMessage).'\')) return false;',
|
||||
],
|
||||
FormValidator::LAYOUT_INLINE
|
||||
);
|
||||
$form->addHidden('action', 'unsubscribe');
|
||||
$form->addHidden('sec_token', $secToken);
|
||||
$form->addHidden('course_code', $courseCode);
|
||||
$form->addButton('unsub', get_lang('Unsubscribe'));
|
||||
|
||||
return $form->returnForm();
|
||||
}
|
||||
|
||||
Display::display_header();
|
||||
|
||||
$stok = Security::get_token();
|
||||
$courses_without_category = isset($courses_in_category[0]) ? $courses_in_category[0] : null;
|
||||
echo '<div id="actions" class="actions">';
|
||||
if ($action != 'createcoursecategory') {
|
||||
echo '<a class="ajax" href="'.$currentUrl.'?action=createcoursecategory">';
|
||||
echo Display::return_icon('new_folder.png', get_lang('CreateCourseCategory'), '', '32');
|
||||
echo '</a>';
|
||||
}
|
||||
echo '</div>';
|
||||
|
||||
if (!empty($message)) {
|
||||
echo Display::return_message($message, 'confirm', false);
|
||||
}
|
||||
|
||||
$allowCollapsable = api_get_configuration_value('allow_user_course_category_collapsable');
|
||||
$teachersIcon = Display::return_icon('teacher.png', get_lang('Teachers'), null, ICON_SIZE_TINY);
|
||||
|
||||
// COURSES WITH CATEGORIES
|
||||
if (!empty($user_course_categories)) {
|
||||
$counter = 0;
|
||||
$last = end($user_course_categories);
|
||||
foreach ($user_course_categories as $row) {
|
||||
echo Display::page_subheader($row['title']);
|
||||
echo '<a name="category'.$row['id'].'"></a>';
|
||||
$url = $currentUrl.'?categoryid='.$row['id'].'&sec_token='.$stok;
|
||||
if ($allowCollapsable) {
|
||||
if (isset($row['collapsed']) && $row['collapsed'] == 0) {
|
||||
echo Display::url(
|
||||
'<i class="fa fa-folder-open"></i>',
|
||||
$url.'&action=set_collapsable&option=1'
|
||||
);
|
||||
} else {
|
||||
echo Display::url(
|
||||
'<i class="fa fa-folder"></i>',
|
||||
$url.'&action=set_collapsable&option=0'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
echo Display::url(
|
||||
Display::return_icon('edit.png', get_lang('Edit'), '', 22),
|
||||
$currentUrl.'?action=edit_category&category_id='.$row['id'].'&sec_token='.$stok,
|
||||
['class' => 'ajax']
|
||||
);
|
||||
|
||||
if (0 != $counter) {
|
||||
echo Display::url(
|
||||
Display::return_icon('up.png', get_lang('Up'), '', 22),
|
||||
$currentUrl.'?move=up&category='.$row['id'].'&sec_token='.$stok
|
||||
);
|
||||
} else {
|
||||
echo Display::return_icon('up_na.png', get_lang('Up'), '', 22);
|
||||
}
|
||||
if ($row['id'] != $last['id']) {
|
||||
echo Display::url(
|
||||
Display::return_icon('down.png', get_lang('Down'), '', 22),
|
||||
$currentUrl.'?move=down&category='.$row['id'].'&sec_token='.$stok
|
||||
);
|
||||
} else {
|
||||
echo Display::return_icon('down_na.png', get_lang('Down'), '', 22);
|
||||
}
|
||||
|
||||
echo Display::url(
|
||||
Display::return_icon(
|
||||
'delete.png',
|
||||
get_lang('Delete'),
|
||||
[
|
||||
'onclick' => "javascript: if (!confirm('".addslashes(
|
||||
api_htmlentities(
|
||||
get_lang('CourseCategoryAbout2bedeleted'),
|
||||
ENT_QUOTES,
|
||||
api_get_system_encoding()
|
||||
)
|
||||
)."')) return false;",
|
||||
],
|
||||
22
|
||||
),
|
||||
$currentUrl.'?action=deletecoursecategory&id='.$row['id'].'&sec_token='.$stok
|
||||
);
|
||||
|
||||
$counter++;
|
||||
echo '<br /><br />';
|
||||
// Show the courses inside this category
|
||||
echo '<table class="table table-hover table-striped data_table">';
|
||||
$number_of_courses = isset($courses_in_category[$row['id']]) ? count($courses_in_category[$row['id']]) : 0;
|
||||
$key = 0;
|
||||
if (!empty($courses_in_category[$row['id']])) {
|
||||
foreach ($courses_in_category[$row['id']] as $course) {
|
||||
echo '<tr><td>';
|
||||
echo '<a name="course'.$course['code'].'"></a>';
|
||||
echo '<strong>'.$course['title'].'</strong>';
|
||||
echo ' ('.$course['visual_code'].')';
|
||||
echo '<br />';
|
||||
echo $teachersIcon;
|
||||
echo ' ';
|
||||
echo CourseManager::getTeacherListFromCourseCodeToString($course['code']);
|
||||
echo '<br />';
|
||||
if (api_get_setting('display_teacher_in_courselist') === 'true') {
|
||||
echo $course['tutor'];
|
||||
}
|
||||
echo '</td><td class="text-right">';
|
||||
if (api_get_setting('show_courses_descriptions_in_catalog') === 'true') {
|
||||
$icon_title = get_lang('CourseDetails').' - '.$course['title'];
|
||||
$url = api_get_path(
|
||||
WEB_CODE_PATH
|
||||
).'inc/ajax/course_home.ajax.php?a=show_course_information&code='.$course['code'];
|
||||
echo Security::remove_XSS(
|
||||
Display::url(
|
||||
Display::return_icon('info.png', $icon_title, '', '22'),
|
||||
$url,
|
||||
['class' => 'ajax', 'data-title' => $icon_title, 'title' => $icon_title]
|
||||
)
|
||||
);
|
||||
echo Display::url(
|
||||
Display::return_icon('edit.png', get_lang('Edit'), '', 22),
|
||||
$currentUrl.'?action=edit_course_category&category_id='.$row['id'].'&course_id='.$course['real_id'].'&sec_token='.$stok,
|
||||
['class' => 'ajax']
|
||||
);
|
||||
}
|
||||
if ($key > 0) {
|
||||
?>
|
||||
<a href="<?php echo $currentUrl; ?>?action=<?php echo $action; ?>&move=up&course=<?php echo $course['code']; ?>&category=<?php echo $course['user_course_cat']; ?>&sec_token=<?php echo $stok; ?>">
|
||||
<?php echo Display::display_icon('up.png', get_lang('Up'), '', 22); ?>
|
||||
</a>
|
||||
<?php
|
||||
} else {
|
||||
echo Display::display_icon('up_na.png', get_lang('Up'), '', 22);
|
||||
}
|
||||
if ($key < $number_of_courses - 1) {
|
||||
?>
|
||||
<a href="<?php echo $currentUrl; ?>?action=<?php echo $action; ?>&move=down&course=<?php echo $course['code']; ?>&category=<?php echo $course['user_course_cat']; ?>&sec_token=<?php echo $stok; ?>">
|
||||
<?php echo Display::return_icon('down.png', get_lang('Down'), '', 22); ?>
|
||||
</a>
|
||||
<?php
|
||||
} else {
|
||||
echo Display::return_icon('down_na.png', get_lang('Down'), '', 22);
|
||||
}
|
||||
if ($course['status'] != 1 && $course['unsubscr'] == 1) {
|
||||
echo generateUnsubscribeForm($course['code'], $stok);
|
||||
}
|
||||
$key++;
|
||||
echo '</td></tr>';
|
||||
}
|
||||
echo '</table>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo Display::page_subheader(get_lang('NoCourseCategory'));
|
||||
echo '<table class="table table-hover table-striped data_table">';
|
||||
// COURSES WITHOUT CATEGORY
|
||||
if (!empty($courses_without_category)) {
|
||||
$number_of_courses = count($courses_without_category);
|
||||
$key = 0;
|
||||
foreach ($courses_without_category as $course) {
|
||||
echo '<tr><td>';
|
||||
echo '<a name="course'.$course['code'].'"></a>';
|
||||
echo '<strong>'.$course['title'].'</strong>';
|
||||
echo ' ('.$course['visual_code'].')';
|
||||
echo '<br />';
|
||||
echo $teachersIcon;
|
||||
echo ' ';
|
||||
echo CourseManager::getTeacherListFromCourseCodeToString($course['code']);
|
||||
echo '<br />';
|
||||
|
||||
if (api_get_setting('display_teacher_in_courselist') === 'true') {
|
||||
echo $course['tutor'];
|
||||
}
|
||||
echo '</td><td class="text-right">';
|
||||
if (api_get_setting('show_courses_descriptions_in_catalog') === 'true') {
|
||||
$icon_title = get_lang('CourseDetails').' - '.$course['title'];
|
||||
$url = api_get_path(WEB_CODE_PATH).'inc/ajax/course_home.ajax.php?a=show_course_information&code='.$course['code'];
|
||||
echo Security::remove_XSS(
|
||||
Display::url(
|
||||
Display::return_icon('info.png', $icon_title, '', '22'),
|
||||
$url,
|
||||
['class' => 'ajax', 'data-title' => $icon_title, 'title' => $icon_title]
|
||||
)
|
||||
);
|
||||
}
|
||||
echo '';
|
||||
if (isset($_GET['edit']) && $course['code'] == $_GET['edit']) {
|
||||
echo Display::return_icon('edit_na.png', get_lang('Edit'), '', 22);
|
||||
} else {
|
||||
echo Display::url(
|
||||
Display::return_icon('edit.png', get_lang('Edit'), '', 22),
|
||||
$currentUrl.'?action=edit_course_category&course_id='.$course['real_id'].'&'.$stok,
|
||||
['class' => 'ajax']
|
||||
);
|
||||
}
|
||||
if ($key > 0) {
|
||||
?>
|
||||
<a
|
||||
href="<?php echo $currentUrl; ?>?action=<?php echo $action; ?>&move=up&course=<?php echo $course['code']; ?>&category=<?php echo $course['user_course_cat']; ?>&sec_token=<?php echo $stok; ?>">
|
||||
<?php echo Display::display_icon('up.png', get_lang('Up'), '', 22); ?>
|
||||
</a>
|
||||
<?php
|
||||
} else {
|
||||
echo Display::return_icon('up_na.png', get_lang('Up'), '', 22);
|
||||
}
|
||||
if ($key < $number_of_courses - 1) {
|
||||
?>
|
||||
<a
|
||||
href="<?php echo $currentUrl; ?>?action=<?php echo $action; ?>&move=down&course=<?php echo $course['code']; ?>&category=<?php echo $course['user_course_cat']; ?>&sec_token=<?php echo $stok; ?>">
|
||||
<?php echo Display::display_icon('down.png', get_lang('Down'), '', 22); ?>
|
||||
</a>
|
||||
<?php
|
||||
} else {
|
||||
echo Display::return_icon('down_na.png', get_lang('Down'), '', 22);
|
||||
}
|
||||
if ($course['status'] != 1) {
|
||||
if ($course['unsubscr'] == 1) {
|
||||
echo generateUnsubscribeForm($course['code'], $stok);
|
||||
}
|
||||
}
|
||||
echo '</td></tr>';
|
||||
|
||||
$key++;
|
||||
}
|
||||
}
|
||||
?>
|
||||
</table>
|
||||
<?php
|
||||
Display::display_footer();
|
||||
60
main/auth/sso/SsoServer.php
Normal file
60
main/auth/sso/SsoServer.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
/**
|
||||
* This file contains the necessary elements to implement a Single Sign On
|
||||
* using chamilo as a SSO server.
|
||||
*
|
||||
* @package chamilo.auth.sso
|
||||
*/
|
||||
class SsoServer
|
||||
{
|
||||
/**
|
||||
* This is used to get the url with the SSO params.
|
||||
*
|
||||
* @param string $refererSso
|
||||
* @param array $additionalParams
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUrl($refererSso, $additionalParams = [])
|
||||
{
|
||||
if (empty($refererSso)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$getParams = parse_url($refererSso, PHP_URL_QUERY);
|
||||
$userInfo = api_get_user_info(api_get_user_id(), false, true);
|
||||
$chamiloUrl = api_get_path(WEB_PATH);
|
||||
$sso = [
|
||||
'username' => $userInfo['username'],
|
||||
'secret' => sha1($userInfo['password']),
|
||||
'master_domain' => $chamiloUrl,
|
||||
'master_auth_uri' => $chamiloUrl.'?submitAuth=true',
|
||||
'lifetime' => time() + 3600,
|
||||
'target' => $refererSso,
|
||||
];
|
||||
|
||||
if (!empty($additionalParams)) {
|
||||
foreach ($additionalParams as $key => $value) {
|
||||
if (!empty($key)) {
|
||||
$sso[$key] = $value;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$sso[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$cookie = base64_encode(serialize($sso));
|
||||
|
||||
return $refererSso
|
||||
.($getParams ? '&' : '?')
|
||||
.http_build_query([
|
||||
'loginFailed' => 0,
|
||||
'sso_referer' => $refererSso,
|
||||
'sso_cookie' => $cookie,
|
||||
]);
|
||||
}
|
||||
}
|
||||
301
main/auth/sso/sso.Drupal.class.php
Normal file
301
main/auth/sso/sso.Drupal.class.php
Normal file
@@ -0,0 +1,301 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
use ChamiloSession as Session;
|
||||
|
||||
/**
|
||||
* This file contains the necessary elements to implement a Single Sign On
|
||||
* mechanism with an external Drupal application (on which the Chamilo module
|
||||
* 7.x-1.0-alpha3 or above must be implemented).
|
||||
*
|
||||
* To use this class, set variable "sso_authentication_subclass" to "Drupal"
|
||||
* in Chamilo settings. If not yet available in the "Security" tab, execute the
|
||||
* following on the Chamilo database:
|
||||
* INSERT INTO `settings_current` (`variable`, `type`, `category`, `selected_value`, `title`, `comment`, `access_url`)
|
||||
* VALUES ('sso_authentication_subclass', 'textfield', 'Security', 'Drupal', 'SSOSubclass', 'SSOSubclassComment', 1);
|
||||
*
|
||||
* @package chamilo.auth.sso
|
||||
*/
|
||||
|
||||
/**
|
||||
* The SSO class allows for management of remote Single Sign On resources.
|
||||
*/
|
||||
class ssoDrupal
|
||||
{
|
||||
public $protocol; // 'http://',
|
||||
public $domain; // 'localhost/project/drupal',
|
||||
public $auth_uri; // '/?q=user',
|
||||
public $deauth_uri; // '/?q=logout',
|
||||
public $referer; // http://my.chamilo.com/main/auth/profile.php
|
||||
|
||||
/**
|
||||
* Instanciates the object, initializing all relevant URL strings.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->protocol = api_get_setting('sso_authentication_protocol');
|
||||
// There can be multiple domains, so make sure to take only the first
|
||||
// This might be later extended with a decision process
|
||||
$domains = preg_split('/,/', api_get_setting('sso_authentication_domain'));
|
||||
$this->domain = trim($domains[0]);
|
||||
$this->auth_uri = api_get_setting('sso_authentication_auth_uri');
|
||||
$this->deauth_uri = api_get_setting('sso_authentication_unauth_uri');
|
||||
//cut the string to avoid recursive URL construction in case of failure
|
||||
$this->referer = $this->protocol.$_SERVER['HTTP_HOST'].substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], 'sso'));
|
||||
$this->deauth_url = $this->protocol.$this->domain.$this->deauth_uri;
|
||||
$this->master_url = $this->protocol.$this->domain.$this->auth_uri;
|
||||
$this->referrer_uri = base64_encode($_SERVER['REQUEST_URI']);
|
||||
$this->target = api_get_path(WEB_PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlogs the user from the remote server.
|
||||
*/
|
||||
public function logout()
|
||||
{
|
||||
// no_redirect means Drupal sent the signal to logout. When redirecting to Drupal, the $_GET['stop'] param is
|
||||
// set to 1, to allow Drupal to know that this is it, the logout is already done in Chamilo and there's no
|
||||
// need to do it again
|
||||
if (empty($_GET['no_redirect'])) {
|
||||
header('Location: '.$this->deauth_url.'&stop=1');
|
||||
} else {
|
||||
header('Location: '.$this->protocol.$this->domain);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the user to the master URL for a check of active connection.
|
||||
*/
|
||||
public function ask_master()
|
||||
{
|
||||
// Generate a single usage token that must be encoded by the master
|
||||
$_SESSION['sso_challenge'] = api_generate_password(48);
|
||||
// Redirect browser to the master URL
|
||||
$params = '';
|
||||
if (empty($_GET['no_redirect'])) {
|
||||
$params = 'sso_referer='.urlencode($this->referer).
|
||||
'&sso_target='.urlencode($this->target).
|
||||
'&sso_challenge='.urlencode($_SESSION['sso_challenge']).
|
||||
'&sso_ruri='.urlencode($this->referrer_uri);
|
||||
if (strpos($this->master_url, "?") === false) {
|
||||
$params = "?{$params}";
|
||||
} else {
|
||||
$params = "&{$params}";
|
||||
}
|
||||
}
|
||||
header('Location: '.$this->master_url.$params);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the received active connection data with the database.
|
||||
*
|
||||
* @return false|null Return the loginFailed variable value to local.inc.php
|
||||
*/
|
||||
public function check_user()
|
||||
{
|
||||
global $_user;
|
||||
$loginFailed = false;
|
||||
|
||||
//change the way we recover the cookie depending on how it is formed
|
||||
$sso = $this->decode_cookie($_GET['sso_cookie']);
|
||||
|
||||
//get token that should have been used and delete it
|
||||
//from session since it can only be used once
|
||||
$sso_challenge = '';
|
||||
if (isset($_SESSION['sso_challenge'])) {
|
||||
$sso_challenge = $_SESSION['sso_challenge'];
|
||||
unset($_SESSION['sso_challenge']);
|
||||
}
|
||||
|
||||
//lookup the user in the main database
|
||||
$user_table = Database::get_main_table(TABLE_MAIN_USER);
|
||||
$sql = "SELECT id, username, password, auth_source, active, expiration_date, status
|
||||
FROM $user_table
|
||||
WHERE username = '".trim(Database::escape_string($sso['username']))."'";
|
||||
$result = Database::query($sql);
|
||||
if (Database::num_rows($result) > 0) {
|
||||
$uData = Database::fetch_array($result);
|
||||
//Check the user's password
|
||||
if ($uData['auth_source'] == PLATFORM_AUTH_SOURCE) {
|
||||
if ($sso['secret'] === sha1($uData['username'].$sso_challenge.api_get_security_key())
|
||||
&& ($sso['username'] == $uData['username'])) {
|
||||
//Check if the account is active (not locked)
|
||||
if ($uData['active'] == '1') {
|
||||
// check if the expiration date has not been reached
|
||||
if (empty($uData['expiration_date']) or $uData['expiration_date'] > date('Y-m-d H:i:s') or $uData['expiration_date'] == '0000-00-00 00:00:00') {
|
||||
//If Multiple URL is enabled
|
||||
if (api_get_multiple_access_url()) {
|
||||
//Check the access_url configuration setting if the user is registered in the access_url_rel_user table
|
||||
//Getting the current access_url_id of the platform
|
||||
$current_access_url_id = api_get_current_access_url_id();
|
||||
// my user is subscribed in these
|
||||
//sites: $my_url_list
|
||||
$my_url_list = api_get_access_url_from_user($uData['id']);
|
||||
} else {
|
||||
$current_access_url_id = 1;
|
||||
$my_url_list = [1];
|
||||
}
|
||||
|
||||
$my_user_is_admin = UserManager::is_admin($uData['id']);
|
||||
|
||||
if ($my_user_is_admin === false) {
|
||||
if (is_array($my_url_list) && count($my_url_list) > 0) {
|
||||
if (in_array($current_access_url_id, $my_url_list)) {
|
||||
// the user has permission to enter at this site
|
||||
$_user['user_id'] = $uData['id'];
|
||||
$_user = api_get_user_info($_user['user_id']);
|
||||
$_user['uidReset'] = true;
|
||||
Session::write('_user', $_user);
|
||||
Event::eventLogin($_user['user_id']);
|
||||
// Redirect to homepage
|
||||
$sso_target = '';
|
||||
if (!empty($sso['ruri'])) {
|
||||
//The referrer URI is *only* used if
|
||||
// the user credentials are OK, which
|
||||
// should be protection enough
|
||||
// against evil URL spoofing...
|
||||
$sso_target = api_get_path(WEB_PATH).base64_decode($sso['ruri']);
|
||||
} else {
|
||||
$sso_target = isset($sso['target']) ? $sso['target'] : api_get_path(WEB_PATH).'index.php';
|
||||
}
|
||||
header('Location: '.$sso_target);
|
||||
exit;
|
||||
} else {
|
||||
// user does not have permission for this site
|
||||
$loginFailed = true;
|
||||
Session::erase('_uid');
|
||||
header('Location: '.api_get_path(WEB_PATH).'index.php?loginFailed=1&error=access_url_inactive');
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
// there is no URL in the multiple
|
||||
// urls list for this user
|
||||
$loginFailed = true;
|
||||
Session::erase('_uid');
|
||||
header('Location: '.api_get_path(WEB_PATH).'index.php?loginFailed=1&error=access_url_inactive');
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
//Only admins of the "main" (first) Chamilo
|
||||
// portal can login wherever they want
|
||||
if (in_array(1, $my_url_list)) {
|
||||
//Check if this admin is admin on the
|
||||
// principal portal
|
||||
$_user['user_id'] = $uData['id'];
|
||||
$_user = api_get_user_info($_user['user_id']);
|
||||
$is_platformAdmin = $uData['status'] == COURSEMANAGER;
|
||||
Session::write('is_platformAdmin', $is_platformAdmin);
|
||||
Session::write('_user', $_user);
|
||||
Event::eventLogin($_user['user_id']);
|
||||
} else {
|
||||
//Secondary URL admin wants to login
|
||||
// so we check as a normal user
|
||||
if (in_array($current_access_url_id, $my_url_list)) {
|
||||
$_user['user_id'] = $uData['user_id'];
|
||||
$_user = api_get_user_info($_user['user_id']);
|
||||
Session::write('_user', $_user);
|
||||
Event::eventLogin($_user['user_id']);
|
||||
} else {
|
||||
$loginFailed = true;
|
||||
Session::erase('_uid');
|
||||
header('Location: '.api_get_path(WEB_PATH).'index.php?loginFailed=1&error=access_url_inactive');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// user account expired
|
||||
$loginFailed = true;
|
||||
Session::erase('_uid');
|
||||
header('Location: '.api_get_path(WEB_PATH).'index.php?loginFailed=1&error=account_expired');
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
//User not active
|
||||
$loginFailed = true;
|
||||
Session::erase('_uid');
|
||||
header('Location: '.api_get_path(WEB_PATH).'index.php?loginFailed=1&error=account_inactive');
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
//SHA1 of password is wrong
|
||||
$loginFailed = true;
|
||||
Session::erase('_uid');
|
||||
header('Location: '.api_get_path(WEB_PATH).'index.php?loginFailed=1&error=wrong_password');
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
//Auth_source is wrong
|
||||
$loginFailed = true;
|
||||
Session::erase('_uid');
|
||||
header('Location: '.api_get_path(WEB_PATH).'index.php?loginFailed=1&error=wrong_authentication_source');
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
//No user by that login
|
||||
$loginFailed = true;
|
||||
Session::erase('_uid');
|
||||
header('Location: '.api_get_path(WEB_PATH).'index.php?loginFailed=1&error=user_not_found');
|
||||
exit;
|
||||
}
|
||||
|
||||
return $loginFailed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the URL for profile editing for a any user or the current user.
|
||||
*
|
||||
* @param int $userId Optional. The user id
|
||||
* @param bool $asAdmin Optional. Whether get the URL for the platform admin
|
||||
*
|
||||
* @return string If the URL is obtained return the drupal_user_id. Otherwise return false
|
||||
*/
|
||||
public function generateProfileEditingURL($userId = 0, $asAdmin = false)
|
||||
{
|
||||
$userId = intval($userId);
|
||||
|
||||
if (empty($userId)) {
|
||||
$userId = api_get_user_id();
|
||||
}
|
||||
|
||||
$userExtraFieldValue = new ExtraFieldValue('user');
|
||||
$drupalUserIdData = $userExtraFieldValue->get_values_by_handler_and_field_variable(
|
||||
$userId,
|
||||
'drupal_user_id'
|
||||
);
|
||||
|
||||
// If this is an administrator, allow him to make some changes in
|
||||
// the Chamilo profile
|
||||
if ($asAdmin && api_is_platform_admin(true)) {
|
||||
return api_get_path(WEB_CODE_PATH)."admin/user_edit.php?user_id=$userId";
|
||||
}
|
||||
// If the user doesn't match a Drupal user, give the normal profile
|
||||
// link
|
||||
if ($drupalUserIdData === false) {
|
||||
return api_get_path(WEB_CODE_PATH).'auth/profile.php';
|
||||
}
|
||||
// In all other cases, generate a link to the Drupal profile edition
|
||||
$drupalUserId = $drupalUserIdData['value'];
|
||||
$url = "{$this->protocol}{$this->domain}/user/{$drupalUserId}/edit";
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the cookie (this function may vary depending on the
|
||||
* Single Sign On implementation.
|
||||
*
|
||||
* @param string Encoded cookie
|
||||
*
|
||||
* @return array Parsed and unencoded cookie
|
||||
*/
|
||||
private function decode_cookie($cookie)
|
||||
{
|
||||
return UnserializeApi::unserialize(
|
||||
'not_allowed_classes',
|
||||
base64_decode($cookie)
|
||||
);
|
||||
}
|
||||
}
|
||||
304
main/auth/sso/sso.class.php
Normal file
304
main/auth/sso/sso.class.php
Normal file
@@ -0,0 +1,304 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
use ChamiloSession as Session;
|
||||
|
||||
/**
|
||||
* This file contains the necessary elements to implement a Single Sign On
|
||||
* mechanism with an arbitrary external web application (given some light
|
||||
* development there) and is based on the Drupal-Chamilo module implementation.
|
||||
* To develop a new authentication mechanism, please extend this class and
|
||||
* overwrite its method, then modify the corresponding calling code in
|
||||
* main/inc/local.inc.php.
|
||||
*
|
||||
* @package chamilo.auth.sso
|
||||
*/
|
||||
/**
|
||||
* The SSO class allows for management or remote Single Sign On resources.
|
||||
*/
|
||||
class sso
|
||||
{
|
||||
public $protocol; // 'http://',
|
||||
public $domain; // 'localhost/project/drupal5',
|
||||
public $auth_uri; // '/?q=user',
|
||||
public $deauth_uri; // '/?q=logout',
|
||||
public $referer; // http://my.chamilo.com/main/auth/profile.php
|
||||
|
||||
/*
|
||||
* referrer_uri: [some/path/inside/Chamilo], might be used by module to
|
||||
* redirect the user to where he wanted to go initially in Chamilo
|
||||
*/
|
||||
public $referrer_uri;
|
||||
|
||||
/**
|
||||
* Instanciates the object, initializing all relevant URL strings.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->protocol = api_get_setting('sso_authentication_protocol');
|
||||
// There can be multiple domains, so make sure to take only the first
|
||||
// This might be later extended with a decision process
|
||||
$domains = explode(',', api_get_setting('sso_authentication_domain'));
|
||||
$this->domain = trim($domains[0]);
|
||||
$this->auth_uri = api_get_setting('sso_authentication_auth_uri');
|
||||
$this->deauth_uri = api_get_setting('sso_authentication_unauth_uri');
|
||||
//cut the string to avoid recursive URL construction in case of failure
|
||||
$this->referer = $this->protocol.$_SERVER['HTTP_HOST'].substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], 'sso'));
|
||||
$this->deauth_url = $this->protocol.$this->domain.$this->deauth_uri;
|
||||
$this->master_url = $this->protocol.$this->domain.$this->auth_uri;
|
||||
$this->referrer_uri = base64_encode($_SERVER['REQUEST_URI']);
|
||||
$this->target = api_get_path(WEB_PATH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlogs the user from the remote server.
|
||||
*/
|
||||
public function logout()
|
||||
{
|
||||
header('Location: '.$this->deauth_url);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the user to the master URL for a check of active connection.
|
||||
*/
|
||||
public function ask_master()
|
||||
{
|
||||
$tempKey = api_generate_password(32);
|
||||
$params = 'sso_referer='.urlencode($this->referer).
|
||||
'&sso_target='.urlencode($this->target).
|
||||
'&sso_challenge='.$tempKey.
|
||||
'&sso_ruri='.urlencode($this->referrer_uri);
|
||||
Session::write('tempkey', $tempKey);
|
||||
if (strpos($this->master_url, "?") === false) {
|
||||
$params = "?$params";
|
||||
} else {
|
||||
$params = "&$params";
|
||||
}
|
||||
header('Location: '.$this->master_url.$params);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the received active connection data with the database.
|
||||
*
|
||||
* @return bool Return the loginFailed variable value to local.inc.php
|
||||
*/
|
||||
public function check_user()
|
||||
{
|
||||
global $_user;
|
||||
$loginFailed = false;
|
||||
//change the way we recover the cookie depending on how it is formed
|
||||
$sso = $this->decode_cookie($_GET['sso_cookie']);
|
||||
|
||||
//error_log('check_user');
|
||||
//error_log('sso decode cookie: '.print_r($sso,1));
|
||||
|
||||
//lookup the user in the main database
|
||||
$user_table = Database::get_main_table(TABLE_MAIN_USER);
|
||||
$sql = "SELECT user_id, username, password, auth_source, active, expiration_date, status
|
||||
FROM $user_table
|
||||
WHERE username = '".trim(Database::escape_string($sso['username']))."'";
|
||||
$result = Database::query($sql);
|
||||
if (Database::num_rows($result) > 0) {
|
||||
//error_log('user exists');
|
||||
$uData = Database::fetch_array($result);
|
||||
//Check the user's password
|
||||
if ($uData['auth_source'] == PLATFORM_AUTH_SOURCE) {
|
||||
//This user's authentification is managed by Chamilo itself
|
||||
// check the user's password
|
||||
// password hash comes already parsed in sha1, md5 or none
|
||||
|
||||
/*
|
||||
error_log($sso['secret']);
|
||||
error_log($uData['password']);
|
||||
error_log($sso['username']);
|
||||
error_log($uData['username']);
|
||||
*/
|
||||
global $_configuration;
|
||||
// Two possible authentication methods here: legacy using password
|
||||
// and new using a temporary, session-fixed, tempkey
|
||||
if ((
|
||||
$sso['username'] == $uData['username']
|
||||
&& $sso['secret'] === sha1(
|
||||
$uData['username'].
|
||||
Session::read('tempkey').
|
||||
$_configuration['security_key']
|
||||
)
|
||||
)
|
||||
or (
|
||||
($sso['secret'] === sha1($uData['password']))
|
||||
&& ($sso['username'] == $uData['username'])
|
||||
)
|
||||
) {
|
||||
//error_log('user n password are ok');
|
||||
//Check if the account is active (not locked)
|
||||
if ($uData['active'] == '1') {
|
||||
// check if the expiration date has not been reached
|
||||
if (empty($uData['expiration_date'])
|
||||
or $uData['expiration_date'] > date('Y-m-d H:i:s')
|
||||
or $uData['expiration_date'] == '0000-00-00 00:00:00') {
|
||||
//If Multiple URL is enabled
|
||||
if (api_get_multiple_access_url()) {
|
||||
//Check the access_url configuration setting if
|
||||
// the user is registered in the access_url_rel_user table
|
||||
//Getting the current access_url_id of the platform
|
||||
$current_access_url_id = api_get_current_access_url_id();
|
||||
// my user is subscribed in these
|
||||
//sites: $my_url_list
|
||||
$my_url_list = api_get_access_url_from_user($uData['user_id']);
|
||||
} else {
|
||||
$current_access_url_id = 1;
|
||||
$my_url_list = [1];
|
||||
}
|
||||
|
||||
$my_user_is_admin = UserManager::is_admin($uData['user_id']);
|
||||
|
||||
if ($my_user_is_admin === false) {
|
||||
if (is_array($my_url_list) && count($my_url_list) > 0) {
|
||||
if (in_array($current_access_url_id, $my_url_list)) {
|
||||
// the user has permission to enter at this site
|
||||
$_user['user_id'] = $uData['user_id'];
|
||||
$_user = api_get_user_info($_user['user_id']);
|
||||
$_user['uidReset'] = true;
|
||||
Session::write('_user', $_user);
|
||||
Event::eventLogin($_user['user_id']);
|
||||
// Redirect to homepage
|
||||
$sso_target = '';
|
||||
if (!empty($sso['ruri'])) {
|
||||
//The referrer URI is *only* used if
|
||||
// the user credentials are OK, which
|
||||
// should be protection enough
|
||||
// against evil URL spoofing...
|
||||
$sso_target = api_get_path(WEB_PATH).base64_decode($sso['ruri']);
|
||||
} else {
|
||||
$sso_target = isset($sso['target']) ? $sso['target'] : api_get_path(WEB_PATH).'index.php';
|
||||
}
|
||||
header('Location: '.$sso_target);
|
||||
exit;
|
||||
} else {
|
||||
// user does not have permission for this site
|
||||
$loginFailed = true;
|
||||
Session::erase('_uid');
|
||||
header('Location: '.api_get_path(WEB_PATH).'index.php?loginFailed=1&error=access_url_inactive');
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
// there is no URL in the multiple
|
||||
// urls list for this user
|
||||
$loginFailed = true;
|
||||
Session::erase('_uid');
|
||||
header('Location: '.api_get_path(WEB_PATH).'index.php?loginFailed=1&error=access_url_inactive');
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
//Only admins of the "main" (first) Chamilo
|
||||
// portal can login wherever they want
|
||||
if (in_array(1, $my_url_list)) {
|
||||
//Check if this admin is admin on the
|
||||
// principal portal
|
||||
$_user['user_id'] = $uData['user_id'];
|
||||
$_user = api_get_user_info($_user['user_id']);
|
||||
$is_platformAdmin = $uData['status'] == COURSEMANAGER;
|
||||
Session::write('is_platformAdmin', $is_platformAdmin);
|
||||
Session::write('_user', $_user);
|
||||
Event::eventLogin($_user['user_id']);
|
||||
} else {
|
||||
//Secondary URL admin wants to login
|
||||
// so we check as a normal user
|
||||
if (in_array($current_access_url_id, $my_url_list)) {
|
||||
$_user['user_id'] = $uData['user_id'];
|
||||
$_user = api_get_user_info($_user['user_id']);
|
||||
Session::write('_user', $_user);
|
||||
Event::eventLogin($_user['user_id']);
|
||||
} else {
|
||||
$loginFailed = true;
|
||||
Session::erase('_uid');
|
||||
header(
|
||||
'Location: '.api_get_path(WEB_PATH)
|
||||
.'index.php?loginFailed=1&error=access_url_inactive'
|
||||
);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// user account expired
|
||||
$loginFailed = true;
|
||||
Session::erase('_uid');
|
||||
header(
|
||||
'Location: '.api_get_path(WEB_PATH)
|
||||
.'index.php?loginFailed=1&error=account_expired'
|
||||
);
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
//User not active
|
||||
$loginFailed = true;
|
||||
Session::erase('_uid');
|
||||
header('Location: '.api_get_path(WEB_PATH).'index.php?loginFailed=1&error=account_inactive');
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
//SHA1 of password is wrong
|
||||
$loginFailed = true;
|
||||
Session::erase('_uid');
|
||||
header('Location: '.api_get_path(WEB_PATH).'index.php?loginFailed=1&error=wrong_password');
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
//Auth_source is wrong
|
||||
$loginFailed = true;
|
||||
Session::erase('_uid');
|
||||
header(
|
||||
'Location: '.api_get_path(WEB_PATH)
|
||||
.'index.php?loginFailed=1&error=wrong_authentication_source'
|
||||
);
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
//No user by that login
|
||||
$loginFailed = true;
|
||||
Session::erase('_uid');
|
||||
header('Location: '.api_get_path(WEB_PATH).'index.php?loginFailed=1&error=user_not_found');
|
||||
exit;
|
||||
}
|
||||
|
||||
return $loginFailed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the URL for profile editing for a any user or the current user.
|
||||
*
|
||||
* @param int $userId Optional. The user id
|
||||
* @param bool $asAdmin Optional. Whether get the URL for the platform admin
|
||||
*
|
||||
* @return string The SSO URL
|
||||
*/
|
||||
public function generateProfileEditingURL($userId = 0, $asAdmin = false)
|
||||
{
|
||||
$userId = intval($userId);
|
||||
|
||||
if ($asAdmin && api_is_platform_admin(true)) {
|
||||
return api_get_path(WEB_CODE_PATH)."admin/user_edit.php?user_id=$userId";
|
||||
}
|
||||
|
||||
return api_get_path(WEB_CODE_PATH).'auth/profile.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the cookie (this function may vary depending on the
|
||||
* Single Sign On implementation.
|
||||
*
|
||||
* @param string Encoded cookie
|
||||
*
|
||||
* @return array Parsed and unencoded cookie
|
||||
*/
|
||||
private function decode_cookie($cookie)
|
||||
{
|
||||
return UnserializeApi::unserialize(
|
||||
'not_allowed_classes',
|
||||
base64_decode($cookie)
|
||||
);
|
||||
}
|
||||
}
|
||||
105
main/auth/sso/sso_server_test.php
Normal file
105
main/auth/sso/sso_server_test.php
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
/*
|
||||
SSO sample
|
||||
|
||||
This is the "server" of my institution/university authentification "code"
|
||||
|
||||
1. Active all the SSO option in your Chamilo installation: main/admin/settings.php?category=Security
|
||||
2. Copy the main/auth/sso/sso.class.php file to something else representing your remote system, like
|
||||
sso.Remote.class.php and modify the class name in soo.Remote.class.php to "ssoRemote"
|
||||
3. Insert the following setting manually in your database (change the selected_value from 'Remote'
|
||||
to the name of your system (used in the filename and classname above).
|
||||
INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext)
|
||||
VALUES ('sso_authentication_subclass',NULL,'textfield','Security','Remote','SSOAuthSubClassTitle','SSOAuthSubClassComment',NULL,NULL);
|
||||
4. Make sure this script is located in the index page of the server you fill in the "Domain of the Single Sign On server" Chamilo setting
|
||||
For example this script must be located in example.com/index.php if you set the "Domain of the Single Sign On server" = example.com
|
||||
5. Create a user in chamilo and in your external system with login = "joe" and password = "doe"
|
||||
6. Remember this is just a sample! Check the chamilo drupal extension for more information:
|
||||
http://drupal.org/node/817682
|
||||
7. When activating the settings in step 1, the principal Chamilo file main/inc/local.inc.php will load the class main/auth/sso.[class.php library
|
||||
* that will redirect to this field with some parameters.
|
||||
*
|
||||
*/
|
||||
|
||||
exit; //Uncomment this to execute the page
|
||||
|
||||
//After you located this file in you new domain and you set the settings in step 2,
|
||||
//this page will be loaded when entering to the Chamilo site if the SSO option was set in step 1.
|
||||
|
||||
//Getting the chamilo server
|
||||
$my_chamilo_server = filter_xss($_SERVER['HTTP_HOST']);
|
||||
|
||||
$account = [];
|
||||
|
||||
if (isset($_SESSION['my_server_user_session'])) {
|
||||
//validate if the user is already logged in my external system in order to redirect to chamilo
|
||||
}
|
||||
|
||||
//Login process
|
||||
|
||||
if (isset($_POST['user']) && isset($_POST['password'])) {
|
||||
//1. Your Server validations
|
||||
$validate = validate_user($_POST['user'], $_POST['password']);
|
||||
|
||||
if ($validate) {
|
||||
/* 2.Get the chamilo username and password from your system or from webservices */
|
||||
|
||||
$account['username'] = 'jbrion525'; //username in Chamilo
|
||||
$account['password'] = sha1(sha1('jbrion525')); //encrypted password with assuming that the first encrypted method is sha1 in chamilo
|
||||
|
||||
$master_auth_uri = $my_chamilo_server.'/?q=user';
|
||||
|
||||
// Creating an array cookie that will be sent to Chamilo
|
||||
$sso = [
|
||||
'username' => $account['username'],
|
||||
'secret' => $account['password'],
|
||||
'master_domain' => $my_chamilo_server,
|
||||
'master_auth_uri' => $master_auth_uri,
|
||||
'lifetime' => time() + 3600,
|
||||
'target' => filter_xss($_GET['sso_target']),
|
||||
];
|
||||
|
||||
$cookie = base64_encode(serialize($sso));
|
||||
$url = chamilo_sso_protocol().$master_auth_uri;
|
||||
$params = 'sso_referer='.urlencode($url).'&sso_cookie='.urlencode($cookie);
|
||||
$final_url = filter_xss($_GET['sso_referer']).'?'.$params;
|
||||
|
||||
//If your user exists redirect to chamilo and set the account in a session to check it later
|
||||
$_SESSION['my_server_user_session'] = $account;
|
||||
|
||||
//3. After validating the user in the server and getting and setting the user data of chamilo in the sso_cookie variable:
|
||||
// Redirect to this URL
|
||||
header('Location: '.$final_url);
|
||||
exit;
|
||||
} else {
|
||||
echo '<h2>Wrong parameters</h2>';
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['logout'])) {
|
||||
//echo do something to logout
|
||||
}
|
||||
|
||||
function validate_user($user, $pass)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
function filter_xss($val)
|
||||
{
|
||||
//do some cleaning
|
||||
return $val;
|
||||
}
|
||||
|
||||
function chamilo_sso_protocol()
|
||||
{
|
||||
//get the sso_protocol from chamilo using webservices
|
||||
return 'http://';
|
||||
}
|
||||
?>
|
||||
<html>
|
||||
<form method="post">
|
||||
User <input name="user"/>
|
||||
Pass <input name="password" />
|
||||
<input type="submit" value="Login">
|
||||
</form>
|
||||
</html>
|
||||
44
main/auth/unsubscribe_account.php
Normal file
44
main/auth/unsubscribe_account.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
require_once __DIR__.'/../inc/global.inc.php';
|
||||
|
||||
if (api_get_setting('platform_unsubscribe_allowed') != 'true') {
|
||||
api_not_allowed();
|
||||
}
|
||||
|
||||
$tool_name = get_lang('Unsubscribe');
|
||||
|
||||
$message = Display::return_message(get_lang('UnsubscribeFromPlatform'), 'warning');
|
||||
|
||||
$form = new FormValidator('user_add');
|
||||
$form->addElement(
|
||||
'button',
|
||||
'submit',
|
||||
get_lang('Unsubscribe'),
|
||||
[
|
||||
'onclick' => "javascript:if(!confirm('".addslashes(api_htmlentities(get_lang("UnsubscribeFromPlatformConfirm")))."')) return false;",
|
||||
]
|
||||
);
|
||||
$content = $form->returnForm();
|
||||
|
||||
if ($form->validate()) {
|
||||
$user_info = api_get_user_info();
|
||||
$result = UserManager::delete_user($user_info['user_id']);
|
||||
if ($result) {
|
||||
$message = Display::return_message(
|
||||
sprintf(
|
||||
get_lang('UnsubscribeFromPlatformSuccess'),
|
||||
$user_info['username']
|
||||
)
|
||||
);
|
||||
$content = null;
|
||||
online_logout($user_info['user_id'], false);
|
||||
api_not_allowed(true, $message);
|
||||
}
|
||||
}
|
||||
|
||||
$tpl = new Template($tool_name);
|
||||
$tpl->assign('message', $message);
|
||||
$tpl->assign('content', $content);
|
||||
$tpl->display_one_col_template();
|
||||
56
main/auth/user_mail_confirmation.php
Normal file
56
main/auth/user_mail_confirmation.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
/* For license terms, see /license.txt */
|
||||
|
||||
require_once __DIR__.'/../inc/global.inc.php';
|
||||
|
||||
$token = isset($_GET['token']) ? $_GET['token'] : '';
|
||||
|
||||
if (!ctype_alnum($token)) {
|
||||
$token = '';
|
||||
}
|
||||
|
||||
/** @var \Chamilo\UserBundle\Entity\User $user */
|
||||
$user = UserManager::getManager()->findUserByConfirmationToken($token);
|
||||
|
||||
if ($user) {
|
||||
$user->setActive(1); // Set to 1 to activate the user
|
||||
$user->setConfirmationToken(null);
|
||||
|
||||
Database::getManager()->persist($user);
|
||||
Database::getManager()->flush();
|
||||
|
||||
// See where to redirect the user to, if any redirection has been set
|
||||
$url = api_get_path(WEB_PATH);
|
||||
|
||||
if (!empty($_GET['c'])) {
|
||||
$courseCode = Security::remove_XSS($_GET['c']);
|
||||
}
|
||||
if (!empty($_GET['s'])) {
|
||||
$sessionId = (int) $_GET['s'];
|
||||
}
|
||||
|
||||
// Get URL to a course, to a session, or an empty string
|
||||
$courseUrl = api_get_course_url($courseCode, $sessionId);
|
||||
if (!empty($courseUrl)) {
|
||||
$url = $courseUrl;
|
||||
}
|
||||
|
||||
Event::addEvent(
|
||||
LOG_USER_CONFIRMED_EMAIL,
|
||||
LOG_USER_OBJECT,
|
||||
api_get_user_info($user->getId()),
|
||||
api_get_utc_datetime()
|
||||
);
|
||||
|
||||
Display::addFlash(
|
||||
Display::return_message(get_lang('UserConfirmedNowYouCanLogInThePlatform'), 'success')
|
||||
);
|
||||
header('Location: '.$url);
|
||||
exit;
|
||||
} else {
|
||||
Display::addFlash(
|
||||
Display::return_message(get_lang('LinkExpired'))
|
||||
);
|
||||
header('Location: '.api_get_path(WEB_PATH));
|
||||
exit;
|
||||
}
|
||||
Reference in New Issue
Block a user