From 9e2b76ffdf36ca0c271a6f443eae935a5264c304 Mon Sep 17 00:00:00 2001 From: MatteoPistorello Date: Fri, 26 Jan 2024 17:00:02 +0100 Subject: [PATCH] Gestione login tramite Microsoft --- index.php | 15 +++- modules/emails/src/OAuth2/Google.php | 10 +++ modules/emails/src/OAuth2/Microsoft.php | 2 + modules/emails/src/OAuth2/MicrosoftLogin.php | 54 ++++++++++++++ modules/oauth/actions.php | 34 +++++++++ modules/oauth/edit.php | 67 +++++++++++++++++ modules/oauth/init.php | 29 ++++++++ oauth2.php | 6 +- oauth2_login.php | 76 ++++++++++++++++++++ src/Auth.php | 12 +++- src/Models/OAuth2.php | 8 +-- update/2_4_54.sql | 14 ++++ 12 files changed, 318 insertions(+), 9 deletions(-) create mode 100644 modules/emails/src/OAuth2/MicrosoftLogin.php create mode 100644 modules/oauth/actions.php create mode 100644 modules/oauth/edit.php create mode 100644 modules/oauth/init.php create mode 100644 oauth2_login.php diff --git a/index.php b/index.php index d37fb6646..dc82d9a3d 100755 --- a/index.php +++ b/index.php @@ -161,6 +161,9 @@ echo ' if (isset($username)) { echo ' value="'.$username.'"'; } + +$microsoft = $dbo->selectOne('zz_oauth2', '*', ['nome' => 'Microsoft', 'enabled' => 1, 'is_login' => 1]); + echo ' required> @@ -171,7 +174,17 @@ echo ' required>
-

'.tr('Password dimenticata?').'

+

'.tr('Password dimenticata?').'

'; + if ($microsoft) { + echo ' + '; + } + echo ' + diff --git a/modules/emails/src/OAuth2/Google.php b/modules/emails/src/OAuth2/Google.php index b38e210db..13d02f1df 100644 --- a/modules/emails/src/OAuth2/Google.php +++ b/modules/emails/src/OAuth2/Google.php @@ -11,6 +11,16 @@ class Google extends OriginalProvider implements ProviderInterface 'accessType' => 'offline', ]; + public function __construct(array $options = [], array $collaborators = []) + { + // Configurazioni specifiche per il provider di Microsoft Azure + $config = array_merge($options, [ + 'redirectUri' => base_url().'/oauth2.php', + ]); + + parent::__construct($config, $collaborators); + } + public function getOptions() { return self::$options; diff --git a/modules/emails/src/OAuth2/Microsoft.php b/modules/emails/src/OAuth2/Microsoft.php index 24885e7ac..feb9b8374 100644 --- a/modules/emails/src/OAuth2/Microsoft.php +++ b/modules/emails/src/OAuth2/Microsoft.php @@ -21,6 +21,7 @@ class Microsoft extends Azure implements ProviderInterface 'https://outlook.office.com/SMTP.Send', // 'https://outlook.office.com/IMAP.AccessAsUser.All' ], + 'accessType' => 'offline' ]; public function __construct(array $options = [], array $collaborators = []) @@ -29,6 +30,7 @@ class Microsoft extends Azure implements ProviderInterface $config = array_merge($options, [ 'defaultEndPointVersion' => parent::ENDPOINT_VERSION_2_0, 'tenant' => $options['tenant_id'], + 'redirectUri' => base_url().'/oauth2.php', ]); parent::__construct($config, $collaborators); diff --git a/modules/emails/src/OAuth2/MicrosoftLogin.php b/modules/emails/src/OAuth2/MicrosoftLogin.php new file mode 100644 index 000000000..98a33be28 --- /dev/null +++ b/modules/emails/src/OAuth2/MicrosoftLogin.php @@ -0,0 +1,54 @@ + [ + 'https://graph.microsoft.com/User.Read', + ], + ]; + + public function __construct(array $options = [], array $collaborators = []) + { + // Configurazioni specifiche per il provider di Microsoft Azure + $config = array_merge($options, [ + 'defaultEndPointVersion' => parent::ENDPOINT_VERSION_2_0, + 'tenant' => $options['tenant_id'], + 'redirectUri' => base_url().'/oauth2_login.php', + ]); + + parent::__construct($config, $collaborators); + } + + public function getOptions() + { + return self::$options; + } + + public static function getConfigInputs() + { + return [ + 'tenant_id' => [ + 'label' => 'Tenant ID', + 'type' => 'text', + ], + ]; + } + + public function getUser($access_token) + { + $me = $this->get('https://graph.microsoft.com/v1.0/me', $access_token); + + return $me['mail']; + } +} diff --git a/modules/oauth/actions.php b/modules/oauth/actions.php new file mode 100644 index 000000000..e343404e4 --- /dev/null +++ b/modules/oauth/actions.php @@ -0,0 +1,34 @@ +. + */ + +include_once __DIR__.'/../../core.php'; + +switch (filter('op')) { + case 'update': + $dbo->update('zz_oauth2', [ + 'client_id' => post('client_id'), + 'client_secret' => post('client_secret'), + 'config' => post('config'), + 'enabled' => post('enabled'), + ], ['id' => $id_record]); + + flash()->info(tr('Salvataggio completato!')); + + break; +} diff --git a/modules/oauth/edit.php b/modules/oauth/edit.php new file mode 100644 index 000000000..faa7b52e4 --- /dev/null +++ b/modules/oauth/edit.php @@ -0,0 +1,67 @@ +. + */ + +include_once __DIR__.'/../../core.php'; + +?>
+ + + + +
+
+

+
+ +
+
+
+ {[ "type": "text", "label": "", "name": "nome", "value": "$nome$", "disabled": "1" ]} +
+ +
+ {[ "type": "checkbox", "label": "", "name": "enabled", "value": "$enabled$" ]} +
+
+ +
+
+ {[ "type": "text", "label": "", "name": "client_id", "value": "$client_id$" ]} +
+ +
+ {[ "type": "text", "label": "", "name": "client_secret", "value": "$client_secret$" ]} +
+ $field) { + $field['name'] = 'config['.$name.']'; + $field['value'] = $oauth2->config[$name]; + + echo ' +
+ '.input($field).' +
'; + } +?> +
+
+
+ +
\ No newline at end of file diff --git a/modules/oauth/init.php b/modules/oauth/init.php new file mode 100644 index 000000000..38491336f --- /dev/null +++ b/modules/oauth/init.php @@ -0,0 +1,29 @@ +. + */ + +use Models\OAuth2; + +include_once __DIR__.'/../../core.php'; + + +if (isset($id_record)) { + $record = $dbo->fetchOne('SELECT * FROM `zz_oauth2` WHERE id='.prepare($id_record)); + $oauth2 = OAuth2::find($id_record); + $a=0; +} diff --git a/oauth2.php b/oauth2.php index 47567ae67..79c37cea1 100644 --- a/oauth2.php +++ b/oauth2.php @@ -47,11 +47,13 @@ if (empty($account)) { } // Redirect all'URL di autorizzazione del servizio esterno -$redirect = $account->configure($code, $state); +$response = $account->configure($code, $state); // Redirect automatico al record -if (empty($redirect)) { +if (empty($response['authorization_url'])) { $redirect = $account->after_configuration; +} else { + $redirect = $response['authorization_url']; } if (empty($_GET['error'])) { diff --git a/oauth2_login.php b/oauth2_login.php new file mode 100644 index 000000000..3c7b15c5d --- /dev/null +++ b/oauth2_login.php @@ -0,0 +1,76 @@ +. + */ + +use Models\OAuth2; + +$skip_permissions = true; +include_once __DIR__.'/core.php'; + +// Authorization information +$state = $_GET['state']; +$code = $_GET['code']; + +// Account individuato via state +if (!empty($state)) { + $account = OAuth2::where('state', '=', $state) + ->first(); +} else { + $account = OAuth2::find(get('id')); + + // Impostazione access token a null per reimpostare la configurazione + $account->access_token = null; + $account->refresh_token = null; + $account->save(); +} + +if (empty($account)) { + echo tr('Errore durante il completamento della configurazione: account non trovato'); + + return; +} + +// Redirect all'URL di autorizzazione del servizio esterno +$response = $account->configure($code, $state); + +// Redirect automatico al record +if (empty($response['authorization_url'])) { + $redirect = $account->after_configuration; +} else { + $redirect = $response['authorization_url']; +} + +if (empty($_GET['error'])) { + if ($response['access_token']) { + $username = $account->getProvider()->getUser($response['access_token']); + + if (!auth()->attempt($username, null, true)) { + flash()->error(tr('Autenticazione fallita!')); + } + redirect(base_path()); + } else { + redirect($redirect); + } + + + exit; +} else { + echo strip_tags($_GET['error']).'
'.strip_tags($_GET['error_description']).' +

+'.tr('Riprova').''; +} diff --git a/src/Auth.php b/src/Auth.php index 7e0a43441..562ac0935 100755 --- a/src/Auth.php +++ b/src/Auth.php @@ -101,10 +101,11 @@ class Auth extends Util\Singleton * * @param string $username * @param string $password + * @param bool $force Forza il login solo tramite username (serve per l'autenticazione con Oauth2) * * @return bool */ - public function attempt($username, $password) + public function attempt($username, $password, $force = false) { session_regenerate_id(); @@ -134,7 +135,14 @@ class Auth extends Util\Singleton $module = $gruppo['id_module_start']; $module = $this->getFirstModule($module); - if ( + if ($force) { + // Accesso completato + $log['id_utente'] = $this->user->id; + $status = 'success'; + + // Salvataggio nella sessione + $this->saveToSession(); + } elseif ( $this->isAuthenticated() && $this->password_check($password, $user['password'], $user['id']) && !empty($module) diff --git a/src/Models/OAuth2.php b/src/Models/OAuth2.php index b5ed738e8..12f53d71b 100644 --- a/src/Models/OAuth2.php +++ b/src/Models/OAuth2.php @@ -47,9 +47,7 @@ class OAuth2 extends Model $config = $this->config ?? []; $config = array_merge($config, [ 'clientId' => $this->client_id, - 'clientSecret' => $this->client_secret, - 'redirectUri' => base_url().'/oauth2.php', - 'accessType' => 'offline', + 'clientSecret' => $this->client_secret ]); $class = $this->class; @@ -106,7 +104,7 @@ class OAuth2 extends Model $this->save(); // Redirect the user to the authorization URL. - return $authorization_url; + return ['authorization_url' => $authorization_url]; } elseif (!empty($this->state) && $this->state !== $state) { $this->state = null; $this->save(); @@ -123,6 +121,8 @@ class OAuth2 extends Model $refresh_token = $access_token->getRefreshToken(); $this->updateTokens($access_token, $refresh_token); + + return ['access_token' => $access_token]; } return null; diff --git a/update/2_4_54.sql b/update/2_4_54.sql index efd5c2ccf..3bc8ff650 100644 --- a/update/2_4_54.sql +++ b/update/2_4_54.sql @@ -11,3 +11,17 @@ INSERT INTO `zz_views` (`id_module`, `name`, `query`, `order`, `search`, `slow`, INSERT INTO `zz_views` (`id`, `id_module`, `name`, `query`, `order`, `search`, `slow`, `format`, `html_format`, `search_inside`, `order_by`, `visible`, `summable`, `default`) VALUES (NULL, (SELECT `id` FROM `zz_modules` WHERE `name` = 'Utenti e permessi'), 'Tema', '`zz_groups`.`theme`', '4', '1', '0', '0', '0', '', '', '1', '0', '0'); +-- Creazione modulo Login +INSERT INTO `zz_modules` (`id`, `name`, `title`, `directory`, `options`, `options2`, `icon`, `version`, `compatibility`, `order`, `parent`, `default`, `enabled`, `use_notes`, `use_checklists`) VALUES (NULL, 'Accesso con OAuth', 'Accesso con OAuth', 'oauth', 'SELECT |select| FROM zz_oauth2 WHERE 1=1 AND is_login=1 HAVING 2=2', '', 'fa fa-angle-right', '1.0', '2.4.54', '100', (SELECT `t`.`id` FROM `zz_modules` AS `t` WHERE `t`.`name` = 'Tabelle'), '1', '1', '0', '0'); + +ALTER TABLE `zz_oauth2` ADD `nome` VARCHAR(255) NOT NULL AFTER `id`; +ALTER TABLE `zz_oauth2` ADD `is_login` BOOLEAN NOT NULL AFTER `after_configuration`; +ALTER TABLE `zz_oauth2` ADD `enabled` BOOLEAN NOT NULL DEFAULT TRUE AFTER `is_login`; + +-- Viste modulo Oauth +INSERT INTO `zz_views` (`id_module`, `name`, `query`, `order`, `search`, `slow`, `format`, `search_inside`, `order_by`, `visible`, `summable`, `default`) VALUES +((SELECT `id` FROM `zz_modules` WHERE name='Accesso con OAuth'), 'id', 'id', 0, 1, 0, 0, '', '', 0, 0, 0), +((SELECT `id` FROM `zz_modules` WHERE name='Accesso con OAuth'), 'Nome', 'nome', 1, 1, 0, 0, '', '', 1, 0, 0); + +INSERT INTO `zz_oauth2` (`nome`, `class`, `client_id`, `client_secret`, `config`, `state`, `access_token`, `refresh_token`, `after_configuration`, `is_login`, `enabled`) VALUES +('Microsoft', 'Modules\\Emails\\OAuth2\\MicrosoftLogin', '', '', '{\"tenant_id\":\"consumers\"}', '', NULL, NULL, '', 1, 0); \ No newline at end of file