Actualización

This commit is contained in:
Xes
2025-04-10 12:36:07 +02:00
parent 1da7c3f3b9
commit 4aff98e77b
3147 changed files with 320647 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
# Azure Active Directory Changelog
## 2.4 - 2024-08-28
* Added a new user extra field to save the unique Azure ID (internal UID).
This requires manually doing the following changes to your database if you are upgrading from v2.3
```sql
INSERT INTO extra_field (extra_field_type, field_type, variable, display_text, default_value, field_order, visible_to_self, visible_to_others, changeable, filter, created_at) VALUES (1, 1, 'azure_uid', 'Azure UID (internal ID)', '', 1, null, null, null, null, '2024-08-28 00:00:00');
```
* Added a new option to set the order to verify the existing user in Chamilo
```sql
INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url, access_url_changeable, access_url_locked) VALUES ('azure_active_directory_existing_user_verification_order', 'azure_active_directory', 'setting', 'Plugins', '', 'azure_active_directory', '', '', '', 1, 1, 0);
```
* Added a new option to update user info during the login proccess.
```sql
INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url, access_url_changeable, access_url_locked) VALUES ('azure_active_directory_update_users', 'azure_active_directory', 'setting', 'Plugins', '', 'azure_active_directory', '', '', '', 1, 1, 0);
```
* Added new scripts to syncronize users and groups with users and usergroups (classes). And an option to deactivate accounts in Chamilo that do not exist in Azure.
```sql
INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url, access_url_changeable, access_url_locked) VALUES ('azure_active_directory_tenant_id', 'azure_active_directory', 'setting', 'Plugins', '', 'azure_active_directory', '', '', '', 1, 1, 0);
INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url, access_url_changeable, access_url_locked) VALUES ('azure_active_directory_deactivate_nonexisting_users', 'azure_active_directory', 'setting', 'Plugins', '', 'azure_active_directory', '', '', '', 1, 1, 0);
```
## 2.3 - 2021-03-30
* Added admin, session admin and teacher groups. This requires adding the following fields to your database if
upgrading from a previous version of the plugin manually:
```
INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url, access_url_changeable, access_url_locked) VALUES ('azure_active_directory_group_id_admin', 'azure_active_directory', 'setting', 'Plugins', '', 'azure_active_directory', '', null, null, 1, 1, 0);
INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url, access_url_changeable, access_url_locked) VALUES ('azure_active_directory_group_id_session_admin', 'azure_active_directory', 'setting', 'Plugins', '', 'azure_active_directory', '', null, null, 1, 1, 0);
INSERT INTO settings_current (variable, subkey, type, category, selected_value, title, comment, scope, subkeytext, access_url, access_url_changeable, access_url_locked) VALUES ('azure_active_directory_group_id_teacher', 'azure_active_directory', 'setting', 'Plugins', '', 'azure_active_directory', '', null, null, 1, 1, 0);
```
## 2.2 - 2021-03-02
* Added provisioning setting
## 2.1 - 2020
* Initial tested implementation of Azure Active Directory single sign on

View File

@@ -0,0 +1,46 @@
# The Azure Active Directory Plugin
This plugin allows users to authenticate (with OAuth2) through Microsoft's Azure Active Directory.
This will modify the login form to either substitute the default login form or add another option to connect through
Azure.
An option allows you to automatically provision/create users in Chamilo from their account on Azure if they don't exist
in Chamilo yet.
This plugin adds two extra fields for users:
* `organisationemail`, the email registered in Azure Active Directory for each user (under _Email_ in the _Contact info_ section).
* `azure_id`, to save the internal ID for each user in Azure (which is also the prefix before the _@_ sign in the _User Principal Name_).
### Prerequisites
This plugin will *not* work if you do not use HTTPS.
Make sure your portal is in HTTPS before you configure this plugin.
### To configure Azure Active Directory
* Create and configure an application in your Azure panel (Azure Active Directory -> Applications registration -> New registration)).
* In the _Authentication_ section, set an _Reply URL_ (or _Redirect URIs_) of `https://{CHAMILO_URL}/plugin/azure_active_directory/src/callback.php`.
* In the _Front-channel logout URL_, use `https://{CHAMILO_URL}/index.php?logout=logout`.
* Leave the rest of the _Authentication_ section unchanged.
* In _Certificates & secrets_, create a secret string (or application password). Keep the _Value_ field at hand. If you don't copy it somewhere at this point, it will later be hidden, so take a copy, seriously!
* Make sure you actually have users.
### To configure this plugin
* _Enable_: You can enable the plugin once everything is configured correctly. Disabling it will return to the normal Chamilo login procedure.
* _Application ID_: Enter the _Application (client) ID_ assigned to your app when you created it in your Azure Active Directory interface, under _App registrations_.
* _Application secret_: Enter the client secret _value_ created in _Certificate & secrets_ above.
* _Block name_: (Optional) The name to show above the login button.
* _Force logout button_: (Optional) Add a button to force logout from Azure.
* _Management login_: (Optional) Disable the chamilo login and enable an alternative login page for users.
You will need copy the `/plugin/azure_active_directory/layout/login_form.tpl` file to `/main/template/overrides/layout/` directory.
* _Name for the management login_: A name for the manager login. By default, it is set to "Management Login".
* _Automated provisioning_: Enable if you want users to be created automatically in Chamilo (as students) when they don't exist yet.
* Assign a region in which the login option will appear. Preferably `login_bottom`.
### Enable through the normal login form
You can configure the external login procedure to work with the classic Chamilo form login.
To do it, make sure users have _azure_ in their auth_source field, then add this line in `configuration.php` file
```php
$extAuthSource["azure"]["login"] = $_configuration['root_sys']."main/auth/external_login/login.azure.php";
```
### Dependencies
> This plugin uses the [`thenetworg/oauth2-azure`](https://github.com/TheNetworg/oauth2-azure) package.

View File

@@ -0,0 +1,38 @@
<?php
/* For licensing terms, see /license.txt */
/**
* @author Angel Fernando Quiroz Campos <angel.quiroz@beeznest.com>
*
* @package chamilo.plugin.azure_active_directory
*/
// Check if AzureActiveDirectory exists, since this is not loaded as a page.
// index.php is shown as a block when showing the region to which the plugin is assigned
if (class_exists(AzureActiveDirectory::class)) {
/** @var AzureActiveDirectory $activeDirectoryPlugin */
$activeDirectoryPlugin = AzureActiveDirectory::create();
if ($activeDirectoryPlugin->get(AzureActiveDirectory::SETTING_ENABLE) === 'true') {
$_template['block_title'] = $activeDirectoryPlugin->get(AzureActiveDirectory::SETTING_BLOCK_NAME);
$_template['signin_url'] = $activeDirectoryPlugin->getUrl(AzureActiveDirectory::URL_TYPE_AUTHORIZE);
if ('true' === $activeDirectoryPlugin->get(AzureActiveDirectory::SETTING_FORCE_LOGOUT_BUTTON)) {
$_template['signout_url'] = $activeDirectoryPlugin->getUrl(AzureActiveDirectory::URL_TYPE_LOGOUT);
}
$managementLoginEnabled = 'true' === $activeDirectoryPlugin->get(AzureActiveDirectory::SETTING_MANAGEMENT_LOGIN_ENABLE);
$_template['management_login_enabled'] = $managementLoginEnabled;
if ($managementLoginEnabled) {
$managementLoginName = $activeDirectoryPlugin->get(AzureActiveDirectory::SETTING_MANAGEMENT_LOGIN_NAME);
if (empty($managementLoginName)) {
$managementLoginName = $activeDirectoryPlugin->get_lang('ManagementLogin');
}
$_template['management_login_name'] = $managementLoginName;
}
}
}

View File

@@ -0,0 +1,8 @@
<?php
/* For licensing terms, see /license.txt */
if (!api_is_platform_admin()) {
exit('You must have admin permissions to install plugins');
}
AzureActiveDirectory::create()->install();

View File

@@ -0,0 +1,48 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Strings to Dutch L10n.
*
* @author Yannick Warnier <yannick.warnier@beeznest.com>
*
* @package chamilo.plugin.azure_active_directory
*/
$strings['plugin_title'] = 'Azure Active Directory';
$strings['plugin_comment'] = 'Sta authenticatie met Microsoft\'s Azure Active Directory toe';
$strings['enable'] = 'Inschakelen';
$strings['app_id'] = 'Applicatie ID';
$strings['app_id_help'] = 'Voeg de Applicatie Id toegewezen aan uw app bij de Azure portal, b.v. 580e250c-8f26-49d0-bee8-1c078add1609';
$strings['app_secret'] = 'Applicatie gehem';
$strings['force_logout'] = 'Forceer uitlogknop';
$strings['force_logout_help'] = 'Toon een knop om afmeldingssessie van Azure af te dwingen.';
$strings['block_name'] = 'Blok naam';
$strings['management_login_enable'] = 'Beheer login';
$strings['management_login_enable_help'] = 'Schakel de chamilo-login uit en schakel een alternatieve inlogpagina in voor gebruikers.<br>'
.'U zult moeten kopiëren de <code>/plugin/azure_active_directory/layout/login_form.tpl</code> bestand in het <code>/main/template/overrides/layout/</code> dossier.';
$strings['management_login_name'] = 'Naam voor de beheeraanmelding';
$strings['management_login_name_help'] = 'De standaardinstelling is "Beheer login".';
$strings['existing_user_verification_order'] = 'Existing user verification order';
$strings['existing_user_verification_order_help'] = 'This value indicates the order in which the user will be searched in Chamilo to verify its existence. '
.'By default is <code>1, 2, 3</code>.'
.'<ol><li>EXTRA_FIELD_ORGANISATION_EMAIL (<code>mail</code>)</li><li>EXTRA_FIELD_AZURE_ID (<code>mailNickname</code>)</li><li>EXTRA_FIELD_AZURE_UID (<code>id</code> of <code>objectId</code>)</li></ol>';
$strings['OrganisationEmail'] = 'Organisatie e-mail';
$strings['AzureId'] = 'Azure ID (mailNickname)';
$strings['AzureUid'] = 'Azure UID (internal ID)';
$strings['ManagementLogin'] = 'Beheer Login';
$strings['InvalidId'] = 'Deze identificatie is niet geldig (verkeerde log-in of wachtwoord). Errocode: AZMNF';
$strings['provisioning'] = 'Geautomatiseerde inrichting';
$strings['update_users'] = 'Update users';
$strings['update_users_help'] = 'Allow user data to be updated at the start of the session.';
$strings['provisioning_help'] = 'Maak automatisch nieuwe gebruikers (als studenten) vanuit Azure wanneer ze niet in Chamilo zijn.';
$strings['group_id_admin'] = 'Groeps-ID voor platformbeheerders';
$strings['group_id_admin_help'] = 'De groeps-ID is te vinden in de details van de gebruikersgroep en ziet er ongeveer zo uit: ae134eef-cbd4-4a32-ba99-49898a1314b6. Indien leeg, wordt er automatisch geen gebruiker aangemaakt als admin.';
$strings['group_id_session_admin'] = 'Groeps-ID voor sessiebeheerders';
$strings['group_id_session_admin_help'] = 'De groeps-ID voor sessiebeheerders. Indien leeg, wordt er automatisch geen gebruiker aangemaakt als sessiebeheerder.';
$strings['group_id_teacher'] = 'Groeps-ID voor docenten';
$strings['group_id_teacher_help'] = 'De groeps-ID voor docenten. Indien leeg, wordt er automatisch geen gebruiker aangemaakt als docent.';
$strings['additional_interaction_required'] = 'Er is aanvullende interactie vereist om u te authenticeren. Log rechtstreeks in via <a href="https://login.microsoftonline.com" target="_blank">uw authenticatiesysteem</a> en kom dan terug naar deze pagina om in te loggen.';
$strings['tenant_id'] = 'Mandanten-ID';
$strings['tenant_id_help'] = 'Required to run scripts.';
$strings['deactivate_nonexisting_users'] = 'Deactivate non-existing users';
$strings['deactivate_nonexisting_users_help'] = 'Compare registered users in Chamilo with those in Azure and deactivate accounts in Chamilo that do not exist in Azure.';

View File

@@ -0,0 +1,48 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Strings to English L10n.
*
* @author Angel Fernando Quiroz Campos <angel.quiroz@beeznest.com>
*
* @package chamilo.plugin.azure_active_directory
*/
$strings['plugin_title'] = 'Azure Active Directory';
$strings['plugin_comment'] = 'Allow authentication with Microsoft\'s Azure Active Directory';
$strings['enable'] = 'Enable';
$strings['app_id'] = 'Application ID';
$strings['app_id_help'] = 'Enter the Application Id assigned to your app by the Azure portal, e.g. 580e250c-8f26-49d0-bee8-1c078add1609';
$strings['app_secret'] = 'Application secret';
$strings['force_logout'] = 'Force logout button';
$strings['force_logout_help'] = 'Show a button to force logout session from Azure.';
$strings['block_name'] = 'Block name';
$strings['management_login_enable'] = 'Management login';
$strings['management_login_enable_help'] = 'Disable the chamilo login and enable an alternative login page for admin users.<br>'
.'You will need to copy the <code>/plugin/azure_active_directory/layout/login_form.tpl</code> file to <code>/main/template/overrides/layout/</code> directory.';
$strings['management_login_name'] = 'Name for the management login';
$strings['management_login_name_help'] = 'The default is "Management Login".';
$strings['existing_user_verification_order'] = 'Existing user verification order';
$strings['existing_user_verification_order_help'] = 'This value indicates the order in which the user will be searched in Chamilo to verify its existence. '
.'By default is <code>1, 2, 3</code>.'
.'<ol><li>EXTRA_FIELD_ORGANISATION_EMAIL (<code>mail</code>)</li><li>EXTRA_FIELD_AZURE_ID (<code>mailNickname</code>)</li><li>EXTRA_FIELD_AZURE_UID (<code>id</code> or <code>objectId</code>)</li></ol>';
$strings['OrganisationEmail'] = 'Organisation e-mail';
$strings['AzureId'] = 'Azure ID (mailNickname)';
$strings['AzureUid'] = 'Azure UID (internal ID)';
$strings['ManagementLogin'] = 'Management Login';
$strings['InvalidId'] = 'Login failed - incorrect login or password. Errocode: AZMNF';
$strings['provisioning'] = 'Automated provisioning';
$strings['provisioning_help'] = 'Automatically create new users (as students) from Azure when they are not in Chamilo.';
$strings['update_users'] = 'Update users';
$strings['update_users_help'] = 'Allow user data to be updated at the start of the session.';
$strings['group_id_admin'] = 'Group ID for platform admins';
$strings['group_id_admin_help'] = 'The group ID can be found in the user group details, looking similar to this: ae134eef-cbd4-4a32-ba99-49898a1314b6. If empty, no user will be automatically created as admin.';
$strings['group_id_session_admin'] = 'Group ID for session admins';
$strings['group_id_session_admin_help'] = 'The group ID for session admins. If empty, no user will be automatically created as session admin.';
$strings['group_id_teacher'] = 'Group ID for teachers';
$strings['group_id_teacher_help'] = 'The group ID for teachers. If empty, no user will be automatically created as teacher.';
$strings['additional_interaction_required'] = 'Some additional interaction is required to authenticate you. Please login directly through <a href="https://login.microsoftonline.com" target="_blank">your authentication system</a>, then come back to this page to login.';
$strings['tenant_id'] = 'Tenant ID';
$strings['tenant_id_help'] = 'Required to run scripts.';
$strings['deactivate_nonexisting_users'] = 'Deactivate non-existing users';
$strings['deactivate_nonexisting_users_help'] = 'Compare registered users in Chamilo with those in Azure and deactivate accounts in Chamilo that do not exist in Azure.';

View File

@@ -0,0 +1,48 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Strings to French L10n.
*
* @author Yannick Warnier <yannick.warnier@beeznest.com>
*
* @package chamilo.plugin.azure_active_directory
*/
$strings['plugin_title'] = 'Azure Active Directory';
$strings['plugin_comment'] = 'Permet l\'authentification des utilisateurs via Azure Active Directory de Microsoft';
$strings['enable'] = 'Activer';
$strings['app_id'] = 'ID de l\'application';
$strings['app_id_help'] = 'Introduisez l\'ID de l\'application assigné à votre app par le portail d\'Azure, p.ex. 580e250c-8f26-49d0-bee8-1c078add1609';
$strings['app_secret'] = 'Clef secrète de l\'application';
$strings['force_logout'] = 'Bouton de logout';
$strings['force_logout_help'] = 'Affiche un bouton pour se délogger d\'Azure.';
$strings['block_name'] = 'Nom du bloc';
$strings['management_login_enable'] = 'Login de gestion';
$strings['management_login_enable_help'] = 'Désactiver le login de Chamilo et permettre une page de login alternative pour les utilisateurs administrateurs.<br>'
.'Vous devez, pour cela, copier le fichier <code>/plugin/azure_active_directory/layout/login_form.tpl</code> dans le répertoire <code>/main/template/overrides/layout/</code>.';
$strings['management_login_name'] = 'Nom du login de gestion';
$strings['management_login_name_help'] = 'Le nom par défaut est "Login de gestion".';
$strings['existing_user_verification_order'] = 'Existing user verification order';
$strings['existing_user_verification_order_help'] = 'This value indicates the order in which the user will be searched in Chamilo to verify its existence. '
.'By default is <code>1, 2, 3</code>.'
.'<ol><li>EXTRA_FIELD_ORGANISATION_EMAIL (<code>mail</code>)</li><li>EXTRA_FIELD_AZURE_ID (<code>mailNickname</code>)</li><li>EXTRA_FIELD_AZURE_UID (<code>id</code> ou <code>objectId</code>)</li></ol>';
$strings['OrganisationEmail'] = 'E-mail professionnel';
$strings['AzureId'] = 'ID Azure (mailNickname)';
$strings['AzureUid'] = 'Azure UID (internal ID)';
$strings['ManagementLogin'] = 'Login de gestion';
$strings['InvalidId'] = 'Échec du login - nom d\'utilisateur ou mot de passe incorrect. Errocode: AZMNF';
$strings['provisioning'] = 'Création automatisée';
$strings['provisioning_help'] = 'Créer les utilisateurs automatiquement (en tant qu\'apprenants) depuis Azure s\'ils n\'existent pas encore dans Chamilo.';
$strings['update_users'] = 'Actualiser les utilisateurs';
$strings['update_users_help'] = 'Permettre d\'actualiser les données de l\'utilisateur lors du démarrage de la session.';
$strings['group_id_admin'] = 'ID du groupe administrateur';
$strings['group_id_admin_help'] = 'L\'id du groupe peut être trouvé dans les détails du groupe, et ressemble à ceci : ae134eef-cbd4-4a32-ba99-49898a1314b6. Si ce champ est laissé vide, aucun utilisateur ne sera créé en tant qu\'administrateur.';
$strings['group_id_session_admin'] = 'ID du groupe administrateur de sessions';
$strings['group_id_session_admin_help'] = 'The group ID for session admins. Si ce champ est laissé vide, aucun utilisateur ne sera créé en tant qu\'administrateur de sessions.';
$strings['group_id_teacher'] = 'ID du groupe enseignant';
$strings['group_id_teacher_help'] = 'The group ID for teachers. Si ce champ est laissé vide, aucun utilisateur ne sera créé en tant qu\'enseignant.';
$strings['additional_interaction_required'] = 'Une interaction supplémentaire est nécessaire pour vous authentifier. Veuillez vous connecter directement auprès de <a href="https://login.microsoftonline.com" target="_blank">votre système d\'authentification</a>, puis revenir ici pour vous connecter.';
$strings['tenant_id'] = 'ID du client';
$strings['tenant_id_help'] = 'Nécessaire pour exécuter des scripts.';
$strings['deactivate_nonexisting_users'] = 'Deactivate non-existing users';
$strings['deactivate_nonexisting_users_help'] = 'Compare registered users in Chamilo with those in Azure and deactivate accounts in Chamilo that do not exist in Azure.';

View File

@@ -0,0 +1,48 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Strings to Spanish L10n.
*
* @author Yannick Warnier <yannick.warnier@beeznest.com>
*
* @package chamilo.plugin.azure_active_directory
*/
$strings['plugin_title'] = 'Azure Active Directory';
$strings['plugin_comment'] = 'Permite la autenticación de usuarios por Azure Active Directory de Microsoft';
$strings['enable'] = 'Activar';
$strings['app_id'] = 'ID de la aplicación';
$strings['app_id_help'] = 'Introduzca el ID de la aplicación asignado a su app en el portal de Azure, p.ej. 580e250c-8f26-49d0-bee8-1c078add1609';
$strings['app_secret'] = 'Clave secreta de la aplicación';
$strings['force_logout'] = 'Botón de logout';
$strings['force_logout_help'] = 'Muestra un botón para hacer logout de Azure.';
$strings['block_name'] = 'Nombre del bloque';
$strings['management_login_enable'] = 'Login de gestión';
$strings['management_login_enable_help'] = 'Desactivar el login de Chamilo y activar una página de login alternativa para los usuarios de administración.<br>'
.'Para ello, tendrá que copiar el archivo <code>/plugin/azure_active_directory/layout/login_form.tpl</code> en la carpeta <code>/main/template/overrides/layout/</code>.';
$strings['management_login_name'] = 'Nombre del bloque de login de gestión';
$strings['management_login_name_help'] = 'El nombre por defecto es "Login de gestión".';
$strings['existing_user_verification_order'] = 'Orden de verificación de usuario existente';
$strings['existing_user_verification_order_help'] = 'Este valor indica el orden en que el usuario serña buscado en Chamilo para verificar su existencia. '
.'Por defecto es <code>1, 2, 3</code>.'
.'<ol><li>EXTRA_FIELD_ORGANISATION_EMAIL (<code>mail</code>)</li><li>EXTRA_FIELD_AZURE_ID (<code>mailNickname</code>)</li><li>EXTRA_FIELD_AZURE_UID (<code>id</code> o <code>objectId</code>)</li></ol>';
$strings['OrganisationEmail'] = 'E-mail profesional';
$strings['AzureId'] = 'ID Azure (mailNickname)';
$strings['AzureUid'] = 'UID Azure (ID interno)';
$strings['ManagementLogin'] = 'Login de gestión';
$strings['InvalidId'] = 'Problema en el login - nombre de usuario o contraseña incorrecto. Errocode: AZMNF';
$strings['provisioning'] = 'Creación automatizada';
$strings['provisioning_help'] = 'Crear usuarios automáticamente (como alumnos) desde Azure si no existen en Chamilo todavía.';
$strings['update_users'] = 'Actualizar los usuarios';
$strings['update_users_help'] = 'Permite actualizar los datos del usuario al iniciar sesión.';
$strings['group_id_admin'] = 'ID de grupo administrador';
$strings['group_id_admin_help'] = 'El ID de grupo se encuentra en los detalles del grupo en Azure, y parece a: ae134eef-cbd4-4a32-ba99-49898a1314b6. Si deja este campo vacío, ningún usuario será creado como administrador.';
$strings['group_id_session_admin'] = 'ID de grupo admin de sesiones';
$strings['group_id_session_admin_help'] = 'El ID de grupo para administradores de sesiones. Si deja este campo vacío, ningún usuario será creado como administrador de sesiones.';
$strings['group_id_teacher'] = 'ID de grupo profesor';
$strings['group_id_teacher_help'] = 'El ID de grupo para profesores. Si deja este campo vacío, ningún usuario será creado como profesor.';
$strings['additional_interaction_required'] = 'Alguna interacción adicional es necesaria para identificarlo/a. Por favor conéctese primero a través de su <a href="https://login.microsoftonline.com" target="_blank">sistema de autenticación</a>, luego regrese aquí para logearse.';
$strings['tenant_id'] = 'Id. del inquilino';
$strings['tenant_id_help'] = 'Necesario para ejecutar scripts.';
$strings['deactivate_nonexisting_users'] = 'Desactivar usuarios no existentes';
$strings['deactivate_nonexisting_users_help'] = 'Compara los usuarios registrados en Chamilo con los de Azure y desactiva las cuentas en Chamilo que no existan en Azure.';

View File

@@ -0,0 +1,51 @@
{% if _u.logged == 0 %}
{% if login_form %}
<div id="login-block" class="panel panel-default">
<div class="panel-body">
{{ login_language_form }}
{% if plugin_login_top is not null %}
<div id="plugin_login_top">
{{ plugin_login_top }}
</div>
{% endif %}
{{ login_failed }}
{% set azure_plugin_enabled = 'azure_active_directory'|api_get_plugin_setting('enable') %}
{% set azure_plugin_manage_login = 'azure_active_directory'|api_get_plugin_setting('manage_login_enable') %}
{% if 'false' == azure_plugin_enabled or 'false' == azure_plugin_manage_login %}
{{ login_form }}
{% if "allow_lostpassword" | api_get_setting == 'true' or "allow_registration"|api_get_setting == 'true' %}
<ul class="nav nav-pills nav-stacked">
{% if "allow_registration"|api_get_setting != 'false' %}
<li><a href="{{ _p.web_main }}auth/inscription.php"> {{ 'SignUp'|get_lang }} </a></li>
{% endif %}
{% if "allow_lostpassword" | api_get_setting == 'true' %}
{% set pass_reminder_link = 'pass_reminder_custom_link'|api_get_configuration_value %}
{% set lost_password_link = _p.web_main ~ 'auth/lostPassword.php' %}
{% if not pass_reminder_link is empty %}
{% set lost_password_link = pass_reminder_link %}
{% endif %}
<li>
<a href="{{ lost_password_link }}"> {{ 'LostPassword' | get_lang }} </a>
</li>
{% endif %}
</ul>
{% endif %}
{% endif %}
{% if plugin_login_bottom is not null %}
<div id="plugin_login_bottom">
{{ plugin_login_bottom }}
</div>
{% endif %}
</div>
</div>
{% endif %}
{% endif %}

View File

@@ -0,0 +1,35 @@
<?php
/* For license terms, see /license.txt */
require __DIR__.'/../../main/inc/global.inc.php';
$plugin = AzureActiveDirectory::create();
$pluginEnabled = $plugin->get(AzureActiveDirectory::SETTING_ENABLE);
$managementLoginEnabled = $plugin->get(AzureActiveDirectory::SETTING_MANAGEMENT_LOGIN_ENABLE);
if ('true' !== $pluginEnabled || 'true' !== $managementLoginEnabled) {
header('Location: '.api_get_path(WEB_PATH));
exit;
}
$userId = api_get_user_id();
if (!($userId) || api_is_anonymous($userId)) {
$managementLoginName = $plugin->get(AzureActiveDirectory::SETTING_MANAGEMENT_LOGIN_NAME);
if (empty($managementLoginName)) {
$managementLoginName = $plugin->get_lang('ManagementLogin');
}
$template = new Template($managementLoginName);
// Only display if the user isn't logged in.
$template->assign('login_language_form', api_display_language_form(true, true));
$template->assign('login_form', $template->displayLoginForm());
$content = $template->fetch('azure_active_directory/view/login.tpl');
$template->assign('content', $content);
$template->display_one_col_template();
}

View File

@@ -0,0 +1,10 @@
<?php
/* For licensing terms, see /license.txt */
/**
* @author Angel Fernando Quiroz Campos <angel.quiroz@beeznest.com>
*
* @package chamilo.plugin.azure_active_directory
*/
$plugin_info = AzureActiveDirectory::create()->get_info();
$plugin_info['templates'] = ['view/block.tpl'];

View File

@@ -0,0 +1,388 @@
<?php
/* For license terms, see /license.txt */
use Chamilo\UserBundle\Entity\User;
use TheNetworg\OAuth2\Client\Provider\Azure;
/**
* AzureActiveDirectory plugin class.
*
* @author Angel Fernando Quiroz Campos <angel.quiroz@beeznest.com>
*
* @package chamilo.plugin.azure_active_directory
*/
class AzureActiveDirectory extends Plugin
{
public const SETTING_ENABLE = 'enable';
public const SETTING_APP_ID = 'app_id';
public const SETTING_APP_SECRET = 'app_secret';
public const SETTING_BLOCK_NAME = 'block_name';
public const SETTING_FORCE_LOGOUT_BUTTON = 'force_logout';
public const SETTING_MANAGEMENT_LOGIN_ENABLE = 'management_login_enable';
public const SETTING_MANAGEMENT_LOGIN_NAME = 'management_login_name';
public const SETTING_PROVISION_USERS = 'provisioning';
public const SETTING_UPDATE_USERS = 'update_users';
public const SETTING_GROUP_ID_ADMIN = 'group_id_admin';
public const SETTING_GROUP_ID_SESSION_ADMIN = 'group_id_session_admin';
public const SETTING_GROUP_ID_TEACHER = 'group_id_teacher';
public const SETTING_EXISTING_USER_VERIFICATION_ORDER = 'existing_user_verification_order';
public const SETTING_TENANT_ID = 'tenant_id';
public const SETTING_DEACTIVATE_NONEXISTING_USERS = 'deactivate_nonexisting_users';
public const URL_TYPE_AUTHORIZE = 'login';
public const URL_TYPE_LOGOUT = 'logout';
public const EXTRA_FIELD_ORGANISATION_EMAIL = 'organisationemail';
public const EXTRA_FIELD_AZURE_ID = 'azure_id';
public const EXTRA_FIELD_AZURE_UID = 'azure_uid';
public const API_PAGE_SIZE = 999;
/**
* AzureActiveDirectory constructor.
*/
protected function __construct()
{
$settings = [
self::SETTING_ENABLE => 'boolean',
self::SETTING_APP_ID => 'text',
self::SETTING_APP_SECRET => 'text',
self::SETTING_BLOCK_NAME => 'text',
self::SETTING_FORCE_LOGOUT_BUTTON => 'boolean',
self::SETTING_MANAGEMENT_LOGIN_ENABLE => 'boolean',
self::SETTING_MANAGEMENT_LOGIN_NAME => 'text',
self::SETTING_PROVISION_USERS => 'boolean',
self::SETTING_UPDATE_USERS => 'boolean',
self::SETTING_GROUP_ID_ADMIN => 'text',
self::SETTING_GROUP_ID_SESSION_ADMIN => 'text',
self::SETTING_GROUP_ID_TEACHER => 'text',
self::SETTING_EXISTING_USER_VERIFICATION_ORDER => 'text',
self::SETTING_TENANT_ID => 'text',
self::SETTING_DEACTIVATE_NONEXISTING_USERS => 'boolean',
];
parent::__construct('2.4', 'Angel Fernando Quiroz Campos, Yannick Warnier', $settings);
}
/**
* Instance the plugin.
*
* @staticvar null $result
*
* @return $this
*/
public static function create()
{
static $result = null;
return $result ? $result : $result = new self();
}
/**
* @return string
*/
public function get_name()
{
return 'azure_active_directory';
}
/**
* @return Azure
*/
public function getProvider()
{
$provider = new Azure([
'clientId' => $this->get(self::SETTING_APP_ID),
'clientSecret' => $this->get(self::SETTING_APP_SECRET),
'redirectUri' => api_get_path(WEB_PLUGIN_PATH).'azure_active_directory/src/callback.php',
]);
return $provider;
}
public function getProviderForApiGraph(): Azure
{
$provider = $this->getProvider();
$provider->urlAPI = "https://graph.microsoft.com/v1.0/";
$provider->resource = "https://graph.microsoft.com/";
$provider->tenant = $this->get(AzureActiveDirectory::SETTING_TENANT_ID);
$provider->authWithResource = false;
return $provider;
}
/**
* @param string $urlType Type of URL to generate
*
* @return string
*/
public function getUrl($urlType)
{
if (self::URL_TYPE_LOGOUT === $urlType) {
$provider = $this->getProvider();
return $provider->getLogoutUrl(
api_get_path(WEB_PATH)
);
}
return api_get_path(WEB_PLUGIN_PATH).$this->get_name().'/src/callback.php';
}
/**
* Create extra fields for user when installing.
*/
public function install()
{
UserManager::create_extra_field(
self::EXTRA_FIELD_ORGANISATION_EMAIL,
ExtraField::FIELD_TYPE_TEXT,
$this->get_lang('OrganisationEmail'),
''
);
UserManager::create_extra_field(
self::EXTRA_FIELD_AZURE_ID,
ExtraField::FIELD_TYPE_TEXT,
$this->get_lang('AzureId'),
''
);
UserManager::create_extra_field(
self::EXTRA_FIELD_AZURE_UID,
ExtraField::FIELD_TYPE_TEXT,
$this->get_lang('AzureUid'),
''
);
}
public function getExistingUserVerificationOrder(): array
{
$defaultOrder = [1, 2, 3];
$settingValue = $this->get(self::SETTING_EXISTING_USER_VERIFICATION_ORDER);
$selectedOrder = array_filter(
array_map(
'trim',
explode(',', $settingValue)
)
);
$selectedOrder = array_map('intval', $selectedOrder);
$selectedOrder = array_filter(
$selectedOrder,
function ($position) use ($defaultOrder): bool {
return in_array($position, $defaultOrder);
}
);
if ($selectedOrder) {
return $selectedOrder;
}
return $defaultOrder;
}
public function getUserIdByVerificationOrder(array $azureUserData, string $azureUidKey = 'objectId'): ?int
{
$selectedOrder = $this->getExistingUserVerificationOrder();
$extraFieldValue = new ExtraFieldValue('user');
$positionsAndFields = [
1 => $extraFieldValue->get_item_id_from_field_variable_and_field_value(
AzureActiveDirectory::EXTRA_FIELD_ORGANISATION_EMAIL,
$azureUserData['mail']
),
2 => $extraFieldValue->get_item_id_from_field_variable_and_field_value(
AzureActiveDirectory::EXTRA_FIELD_AZURE_ID,
$azureUserData['mailNickname']
),
3 => $extraFieldValue->get_item_id_from_field_variable_and_field_value(
AzureActiveDirectory::EXTRA_FIELD_AZURE_UID,
$azureUserData[$azureUidKey]
),
];
foreach ($selectedOrder as $position) {
if (!empty($positionsAndFields[$position]) && isset($positionsAndFields[$position]['item_id'])) {
return (int) $positionsAndFields[$position]['item_id'];
}
}
return null;
}
/**
* @throws Exception
*/
public function registerUser(
array $azureUserInfo,
string $azureUidKey = 'objectId'
) {
if (empty($azureUserInfo)) {
throw new Exception('Groups info not found.');
}
$userId = $this->getUserIdByVerificationOrder($azureUserInfo, $azureUidKey);
if (empty($userId)) {
// If we didn't find the user
if ($this->get(self::SETTING_PROVISION_USERS) !== 'true') {
throw new Exception('User not found when checking the extra fields from '.$azureUserInfo['mail'].' or '.$azureUserInfo['mailNickname'].' or '.$azureUserInfo[$azureUidKey].'.');
}
[
$firstNme,
$lastName,
$username,
$email,
$phone,
$authSource,
$active,
$extra,
] = $this->formatUserData($azureUserInfo, $azureUidKey);
// If the option is set to create users, create it
$userId = UserManager::create_user(
$firstNme,
$lastName,
STUDENT,
$email,
$username,
'',
null,
null,
$phone,
null,
$authSource,
null,
$active,
null,
$extra,
null,
null
);
if (!$userId) {
throw new Exception(get_lang('UserNotAdded').' '.$azureUserInfo['userPrincipalName']);
}
return $userId;
}
if ($this->get(self::SETTING_UPDATE_USERS) === 'true') {
[
$firstNme,
$lastName,
$username,
$email,
$phone,
$authSource,
$active,
$extra,
] = $this->formatUserData($azureUserInfo, $azureUidKey);
$userId = UserManager::update_user(
$userId,
$firstNme,
$lastName,
$username,
'',
$authSource,
$email,
STUDENT,
null,
$phone,
null,
null,
$active,
null,
0,
$extra
);
if (!$userId) {
throw new Exception(get_lang('CouldNotUpdateUser').' '.$azureUserInfo['userPrincipalName']);
}
}
return $userId;
}
/**
* @return array<string, string|false>
*/
public function getGroupUidByRole(): array
{
$groupUidList = [
'admin' => $this->get(self::SETTING_GROUP_ID_ADMIN),
'sessionAdmin' => $this->get(self::SETTING_GROUP_ID_SESSION_ADMIN),
'teacher' => $this->get(self::SETTING_GROUP_ID_TEACHER),
];
return array_filter($groupUidList);
}
/**
* @return array<string, callable>
*/
public function getUpdateActionByRole(): array
{
return [
'admin' => function (User $user) {
$user->setStatus(COURSEMANAGER);
UserManager::addUserAsAdmin($user, false);
},
'sessionAdmin' => function (User $user) {
$user->setStatus(SESSIONADMIN);
UserManager::removeUserAdmin($user, false);
},
'teacher' => function (User $user) {
$user->setStatus(COURSEMANAGER);
UserManager::removeUserAdmin($user, false);
},
];
}
/**
* @throws Exception
*/
private function formatUserData(
array $azureUserInfo,
string $azureUidKey
): array {
$phone = null;
if (isset($azureUserInfo['telephoneNumber'])) {
$phone = $azureUserInfo['telephoneNumber'];
} elseif (isset($azureUserInfo['businessPhones'][0])) {
$phone = $azureUserInfo['businessPhones'][0];
} elseif (isset($azureUserInfo['mobilePhone'])) {
$phone = $azureUserInfo['mobilePhone'];
}
// If the option is set to create users, create it
$firstNme = $azureUserInfo['givenName'];
$lastName = $azureUserInfo['surname'];
$email = $azureUserInfo['mail'];
$username = $azureUserInfo['userPrincipalName'];
$authSource = 'azure';
$active = ($azureUserInfo['accountEnabled'] ? 1 : 0);
$extra = [
'extra_'.self::EXTRA_FIELD_ORGANISATION_EMAIL => $azureUserInfo['mail'],
'extra_'.self::EXTRA_FIELD_AZURE_ID => $azureUserInfo['mailNickname'],
'extra_'.self::EXTRA_FIELD_AZURE_UID => $azureUserInfo[$azureUidKey],
];
return [
$firstNme,
$lastName,
$username,
$email,
$phone,
$authSource,
$active,
$extra,
];
}
}

View File

@@ -0,0 +1,188 @@
<?php
/* For license terms, see /license.txt */
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use League\OAuth2\Client\Token\AccessTokenInterface;
use TheNetworg\OAuth2\Client\Provider\Azure;
abstract class AzureCommand
{
/**
* @var AzureActiveDirectory
*/
protected $plugin;
/**
* @var Azure
*/
protected $provider;
public function __construct()
{
$this->plugin = AzureActiveDirectory::create();
$this->plugin->get_settings(true);
$this->provider = $this->plugin->getProviderForApiGraph();
}
/**
* @throws IdentityProviderException
*/
protected function generateOrRefreshToken(?AccessTokenInterface &$token)
{
if (!$token || ($token->getExpires() && !$token->getRefreshToken())) {
$token = $this->provider->getAccessToken(
'client_credentials',
['resource' => $this->provider->resource]
);
}
}
/**
* @throws Exception
*
* @return Generator<int, array<string, string>>
*/
protected function getAzureUsers(): Generator
{
$userFields = [
'givenName',
'surname',
'mail',
'userPrincipalName',
'businessPhones',
'mobilePhone',
'accountEnabled',
'mailNickname',
'id',
];
$query = sprintf(
'$top=%d&$select=%s',
AzureActiveDirectory::API_PAGE_SIZE,
implode(',', $userFields)
);
$token = null;
do {
$this->generateOrRefreshToken($token);
try {
$azureUsersRequest = $this->provider->request(
'get',
"users?$query",
$token
);
} catch (Exception $e) {
throw new Exception('Exception when requesting users from Azure: '.$e->getMessage());
}
$azureUsersInfo = $azureUsersRequest['value'] ?? [];
foreach ($azureUsersInfo as $azureUserInfo) {
yield $azureUserInfo;
}
$hasNextLink = false;
if (!empty($azureUsersRequest['@odata.nextLink'])) {
$hasNextLink = true;
$query = parse_url($azureUsersRequest['@odata.nextLink'], PHP_URL_QUERY);
}
} while ($hasNextLink);
}
/**
* @throws Exception
*
* @return Generator<int, array<string, string>>
*/
protected function getAzureGroups(): Generator
{
$groupFields = [
'id',
'displayName',
'description',
];
$query = sprintf(
'$top=%d&$select=%s',
AzureActiveDirectory::API_PAGE_SIZE,
implode(',', $groupFields)
);
$token = null;
do {
$this->generateOrRefreshToken($token);
try {
$azureGroupsRequest = $this->provider->request('get', "groups?$query", $token);
} catch (Exception $e) {
throw new Exception('Exception when requesting groups from Azure: '.$e->getMessage());
}
$azureGroupsInfo = $azureGroupsRequest['value'] ?? [];
foreach ($azureGroupsInfo as $azureGroupInfo) {
yield $azureGroupInfo;
}
$hasNextLink = false;
if (!empty($azureGroupsRequest['@odata.nextLink'])) {
$hasNextLink = true;
$query = parse_url($azureGroupsRequest['@odata.nextLink'], PHP_URL_QUERY);
}
} while ($hasNextLink);
}
/**
* @throws Exception
*
* @return Generator<int, array<string, string>>
*/
protected function getAzureGroupMembers(string $groupUid): Generator
{
$userFields = [
'mail',
'mailNickname',
'id',
];
$query = sprintf(
'$top=%d&$select=%s',
AzureActiveDirectory::API_PAGE_SIZE,
implode(',', $userFields)
);
$token = null;
do {
$this->generateOrRefreshToken($token);
try {
$azureGroupMembersRequest = $this->provider->request(
'get',
"groups/$groupUid/members?$query",
$token
);
} catch (Exception $e) {
throw new Exception('Exception when requesting group members from Azure: '.$e->getMessage());
}
$azureGroupMembers = $azureGroupMembersRequest['value'] ?? [];
foreach ($azureGroupMembers as $azureGroupMember) {
yield $azureGroupMember;
}
$hasNextLink = false;
if (!empty($azureGroupMembersRequest['@odata.nextLink'])) {
$hasNextLink = true;
$query = parse_url($azureGroupMembersRequest['@odata.nextLink'], PHP_URL_QUERY);
}
} while ($hasNextLink);
}
}

View File

@@ -0,0 +1,74 @@
<?php
/* For license terms, see /license.txt */
class AzureSyncUsergroupsCommand extends AzureCommand
{
/**
* @throws Exception
*
* @return Generator<int, string>
*/
public function __invoke(): Generator
{
yield 'Synchronizing groups from Azure.';
$usergroup = new UserGroup();
$groupIdByUid = [];
foreach ($this->getAzureGroups() as $azureGroupInfo) {
if ($usergroup->usergroup_exists($azureGroupInfo['displayName'])) {
$groupId = $usergroup->getIdByName($azureGroupInfo['displayName']);
if ($groupId) {
$usergroup->subscribe_users_to_usergroup($groupId, []);
yield sprintf('Class exists, all users unsubscribed: %s', $azureGroupInfo['displayName']);
}
} else {
$groupId = $usergroup->save([
'name' => $azureGroupInfo['displayName'],
'description' => $azureGroupInfo['description'],
]);
if ($groupId) {
yield sprintf('Class created: %s', $azureGroupInfo['displayName']);
}
}
$groupIdByUid[$azureGroupInfo['id']] = $groupId;
}
yield '----------------';
yield 'Subscribing users to groups';
foreach ($groupIdByUid as $azureGroupUid => $groupId) {
$newGroupMembers = [];
yield sprintf('Obtaining members for group (ID %d)', $groupId);
try {
foreach ($this->getAzureGroupMembers($azureGroupUid) as $azureGroupMember) {
if ($userId = $this->plugin->getUserIdByVerificationOrder($azureGroupMember, 'id')) {
$newGroupMembers[] = $userId;
}
}
} catch (Exception $e) {
yield $e->getMessage();
continue;
}
if ($newGroupMembers) {
$usergroup->subscribe_users_to_usergroup($groupId, $newGroupMembers);
yield sprintf(
'User IDs subscribed in class (ID %d): %s',
$groupId,
implode(', ', $newGroupMembers)
);
}
}
}
}

View File

@@ -0,0 +1,98 @@
<?php
/* For license terms, see /license.txt */
use Chamilo\UserBundle\Entity\User;
class AzureSyncUsersCommand extends AzureCommand
{
/**
* @throws Exception
*
* @return Generator<int, string>
*/
public function __invoke(): Generator
{
yield 'Synchronizing users from Azure.';
/** @var array<string, int> $existingUsers */
$existingUsers = [];
foreach ($this->getAzureUsers() as $azureUserInfo) {
try {
$userId = $this->plugin->registerUser($azureUserInfo, 'id');
} catch (Exception $e) {
yield $e->getMessage();
continue;
}
$existingUsers[$azureUserInfo['id']] = $userId;
yield sprintf('User (ID %d) with received info: %s ', $userId, serialize($azureUserInfo));
}
yield '----------------';
yield 'Updating users status';
$roleGroups = $this->plugin->getGroupUidByRole();
$roleActions = $this->plugin->getUpdateActionByRole();
$userManager = UserManager::getManager();
$em = Database::getManager();
foreach ($roleGroups as $userRole => $groupUid) {
try {
$azureGroupMembersInfo = iterator_to_array($this->getAzureGroupMembers($groupUid));
} catch (Exception $e) {
yield $e->getMessage();
continue;
}
$azureGroupMembersUids = array_column($azureGroupMembersInfo, 'id');
foreach ($azureGroupMembersUids as $azureGroupMembersUid) {
$userId = $existingUsers[$azureGroupMembersUid] ?? null;
if (!$userId) {
continue;
}
if (isset($roleActions[$userRole])) {
/** @var User $user */
$user = $userManager->find($userId);
$roleActions[$userRole]($user);
yield sprintf('User (ID %d) status %s', $userId, $userRole);
}
}
$em->flush();
}
if ('true' === $this->plugin->get(AzureActiveDirectory::SETTING_DEACTIVATE_NONEXISTING_USERS)) {
yield '----------------';
yield 'Trying deactivate non-existing users in Azure';
$users = UserManager::getRepository()->findByAuthSource('azure');
$userIdList = array_map(
function ($user) {
return $user->getId();
},
$users
);
$nonExistingUsers = array_diff($userIdList, $existingUsers);
UserManager::deactivate_users($nonExistingUsers);
yield sprintf(
'Deactivated users IDs: %s',
implode(', ', $nonExistingUsers)
);
}
}
}

View File

@@ -0,0 +1,145 @@
<?php
/* For license terms, see /license.txt */
/**
* Callback script for Azure. The URL of this file is sent to Azure as a
* point of contact to send particular signals.
*/
use Chamilo\UserBundle\Entity\User;
require __DIR__.'/../../../main/inc/global.inc.php';
if (!empty($_GET['error']) && !empty($_GET['state'])) {
if ($_GET['state'] === ChamiloSession::read('oauth2state')) {
api_not_allowed(
true,
Display::return_message(
$_GET['error_description'] ?? $_GET['error'],
'warning'
)
);
} else {
ChamiloSession::erase('oauth2state');
exit('Invalid state');
}
}
$plugin = AzureActiveDirectory::create();
if ('true' !== $plugin->get(AzureActiveDirectory::SETTING_ENABLE)) {
api_not_allowed(true);
}
$provider = $plugin->getProvider();
if (!isset($_GET['code'])) {
// If we don't have an authorization code then get one by redirecting
// users to Azure (with the callback URL information)
$authUrl = $provider->getAuthorizationUrl();
ChamiloSession::write('oauth2state', $provider->getState());
header('Location: '.$authUrl);
exit;
}
// Check given state against previously stored one to mitigate CSRF attack
if (empty($_GET['state']) || ($_GET['state'] !== ChamiloSession::read('oauth2state'))) {
ChamiloSession::erase('oauth2state');
exit;
}
// Try to get an access token (using the authorization code grant)
try {
$token = $provider->getAccessToken('authorization_code', [
'code' => $_GET['code'],
'resource' => 'https://graph.windows.net',
]);
} catch (Exception $exception) {
if ($exception->getMessage() == 'interaction_required') {
$message = Display::return_message($plugin->get_lang('additional_interaction_required'), 'error', false);
} else {
$message = Display::return_message($exception->getMessage(), 'error');
}
Display::addFlash($message);
header('Location: '.api_get_path(WEB_PATH));
exit;
}
$me = null;
try {
$me = $provider->get('me', $token);
if (empty($me)) {
throw new Exception('Token not found.');
}
// We use the e-mail to authenticate the user, so check that at least one
// e-mail source exists
if (empty($me['mail'])) {
throw new Exception('The mail field is empty in Azure AD and is needed to set the organisation email for this user.');
}
if (empty($me['mailNickname'])) {
throw new Exception('The mailNickname field is empty in Azure AD and is needed to set the unique username for this user.');
}
if (empty($me['objectId'])) {
throw new Exception('The id field is empty in Azure AD and is needed to set the unique Azure ID for this user.');
}
$userId = $plugin->registerUser($me);
if ($roleGroups = $plugin->getGroupUidByRole()) {
$roleActions = $plugin->getUpdateActionByRole();
/** @var User $user */
$user = UserManager::getManager()->find($userId);
$azureGroups = $provider->get('me/memberOf', $token);
foreach ($roleGroups as $userRole => $groupUid) {
foreach ($azureGroups as $azureGroup) {
$azureGroupUid = $azureGroup['objectId'];
if ($azureGroupUid === $groupUid) {
$roleActions[$userRole]($user);
break 2;
}
}
}
Database::getManager()->flush();
}
$userInfo = api_get_user_info($userId);
/* @TODO add support if user exists in another URL but is validated in this one, add the user to access_url_rel_user */
if (empty($userInfo)) {
throw new Exception('User '.$userId.' not found.');
}
if ($userInfo['active'] != '1') {
throw new Exception(get_lang('AccountInactive'));
}
} catch (Exception $exception) {
$message = Display::return_message($exception->getMessage(), 'error');
Display::addFlash($message);
header('Location: '.api_get_path(WEB_PATH));
exit;
}
$userInfo['uidReset'] = true;
$_GET['redirect_after_not_allow_page'] = 1;
$redirectAfterNotAllowPage = ChamiloSession::read('redirect_after_not_allow_page');
ChamiloSession::clear();
ChamiloSession::write('redirect_after_not_allow_page', $redirectAfterNotAllowPage);
ChamiloSession::write('_user', $userInfo);
ChamiloSession::write('_user_auth_source', 'azure_active_directory');
Event::eventLogin($userInfo['user_id']);
Redirect::session_request_uri(true, $userInfo['user_id']);

View File

@@ -0,0 +1,21 @@
<?php
/* For license terms, see /license.txt */
require __DIR__.'/../../../../main/inc/global.inc.php';
if (PHP_SAPI !== 'cli') {
exit('Run this script through the command line or comment this line in the code');
}
// Uncomment to indicate the access url to get the plugin settings when using multi-url
//$_configuration['access_url'] = 1;
$command = new AzureSyncUsergroupsCommand();
try {
foreach ($command() as $str) {
printf("%d - %s".PHP_EOL, time(), $str);
}
} catch (Exception $e) {
printf('%s - Exception: %s'.PHP_EOL, time(), $e->getMessage());
}

View File

@@ -0,0 +1,21 @@
<?php
/* For license terms, see /license.txt */
require __DIR__.'/../../../../main/inc/global.inc.php';
if (PHP_SAPI !== 'cli') {
exit('Run this script through the command line or comment this line in the code');
}
// Uncomment to indicate the access url to get the plugin settings when using multi-url
//$_configuration['access_url'] = 1;
$command = new AzureSyncUsersCommand();
try {
foreach ($command() as $str) {
printf("%d - %s".PHP_EOL, time(), $str);
}
} catch (Exception $e) {
printf('%s - Exception: %s'.PHP_EOL, time(), $e->getMessage());
}

View File

@@ -0,0 +1,22 @@
{% if not _u.logged %}
<div id="azure-active-directory-login">
{% if not azure_active_directory.block_title is empty %}
<h4>{{ azure_active_directory.block_title }}</h4>
{% endif %}
{% if not azure_active_directory.signin_url is empty %}
<a href="{{ azure_active_directory.signin_url }}" class="btn btn-default">{{ 'SignIn'|get_lang }}</a>
{% endif %}
{% if not azure_active_directory.signout_url is empty %}
<a href="{{ azure_active_directory.signout_url }}" class="btn btn-danger">{{ 'Logout'|get_lang }}</a>
{% endif %}
{% if azure_active_directory.management_login_enabled %}
<hr>
<a href="{{ _p.web_plugin ~ 'azure_active_directory/login.php' }}">
{{ azure_active_directory.management_login_name }}
</a>
{% endif %}
</div>
{% endif %}

View File

@@ -0,0 +1,26 @@
<div class="row">
<div class="col-sm-4 col-sm-offset-4">
{{ login_language_form }}
{{ login_form }}
{% if "allow_lostpassword"|api_get_setting == 'true' or "allow_registration"|api_get_setting == 'true' %}
<ul class="nav nav-pills nav-stacked">
{% if "allow_registration"|api_get_setting != 'false' %}
<li><a href="{{ _p.web_main }}auth/inscription.php">{{ 'SignUp'|get_lang }}</a></li>
{% endif %}
{% if "allow_lostpassword" | api_get_setting == 'true' %}
{% set pass_reminder_link = 'pass_reminder_custom_link'|api_get_configuration_value %}
{% set lost_password_link = _p.web_main ~ 'auth/lostPassword.php' %}
{% if not pass_reminder_link is empty %}
{% set lost_password_link = pass_reminder_link %}
{% endif %}
<li><a href="{{ lost_password_link }}"> {{ 'LostPassword' | get_lang }} </a></li>
{% endif %}
</ul>
{% endif %}
</div>
</div>