Workaround for #1645

This commit is contained in:
the-djmaze 2024-07-01 15:41:33 +02:00
parent dcfe7d3f2d
commit 47d18cafa3
4 changed files with 24 additions and 21 deletions

View file

@ -1,16 +1,16 @@
#<FilesMatch "index\.php"> <FilesMatch "index\.php">
# allow from all allow from all
# AcceptPathInfo On AcceptPathInfo On
#</FilesMatch> </FilesMatch>
<IfModule mod_rewrite.c> <IfModule mod_rewrite.c>
RewriteEngine On RewriteEngine On
# Redirect cPanel # Redirect cPanel
RewriteRule cpsess.* https://%{HTTP_HOST}/ [L,R=301] RewriteRule cpsess.* https://%{HTTP_HOST}/ [L,R=301]
# RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-f
# RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-d
# RewriteRule ^(.+)$ index.php/$1 [L,QSA] RewriteRule ^(.+)$ index.php/$1 [L,QSA]
</IfModule> </IfModule>
<IfModule mod_expires.c> <IfModule mod_expires.c>

View file

@ -1,7 +1,8 @@
(rl => { (rl => {
const client_id = rl.pluginSettingsGet('login-o365', 'client_id'), const client_id = rl.pluginSettingsGet('login-o365', 'client_id'),
tenant = rl.pluginSettingsGet('login-o365', 'tenant'),
login = () => { login = () => {
document.location = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize?' + (new URLSearchParams({ document.location = 'https://login.microsoftonline.com/'+tenant+'/oauth2/v2.0/authorize?' + (new URLSearchParams({
response_type: 'code', response_type: 'code',
client_id: client_id, client_id: client_id,
redirect_uri: document.location.href + '?LoginO365', redirect_uri: document.location.href + '?LoginO365',

View file

@ -8,6 +8,7 @@
* https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/RegisteredApps * https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/RegisteredApps
* *
* redirect_uri=https://{DOMAIN}/?LoginO365 * redirect_uri=https://{DOMAIN}/?LoginO365
* redirect_uri=https://{DOMAIN}/LoginO365
*/ */
use RainLoop\Model\MainAccount; use RainLoop\Model\MainAccount;
@ -23,10 +24,10 @@ class LoginO365Plugin extends \RainLoop\Plugins\AbstractPlugin
CATEGORY = 'Login', CATEGORY = 'Login',
DESCRIPTION = 'Office365/Outlook IMAP, Sieve & SMTP login using RFC 7628 OAuth2'; DESCRIPTION = 'Office365/Outlook IMAP, Sieve & SMTP login using RFC 7628 OAuth2';
// Microsoft make up your mind! documentation has "/oauth2/v2.0/" or "/v2.0/oauth2/" ??? // https://login.microsoftonline.com/{{tenant}}/v2.0/.well-known/openid-configuration
const const
LOGIN_URI = 'https://login.microsoftonline.com/common/oauth2/v2.0/auth', LOGIN_URI = 'https://login.microsoftonline.com/{{tenant}}/oauth2/v2.0/auth',
TOKEN_URI = 'https://login.microsoftonline.com/common/oauth2/v2.0/token'; TOKEN_URI = 'https://login.microsoftonline.com/{{tenant}}/oauth2/v2.0/token';
private static ?array $auth = null; private static ?array $auth = null;
@ -63,7 +64,7 @@ class LoginO365Plugin extends \RainLoop\Plugins\AbstractPlugin
try try
{ {
if (isset($_GET['error'])) { if (isset($_GET['error'])) {
throw new \RuntimeException($_GET['error']); throw new \RuntimeException("{$_GET['error']}: {$_GET['error_description']}");
} }
if (!isset($_GET['code']) || empty($_GET['state']) || 'o365' !== $_GET['state']) { if (!isset($_GET['code']) || empty($_GET['state']) || 'o365' !== $_GET['state']) {
$oActions->Location(\RainLoop\Utils::WebPath()); $oActions->Location(\RainLoop\Utils::WebPath());
@ -77,7 +78,7 @@ class LoginO365Plugin extends \RainLoop\Plugins\AbstractPlugin
$iExpires = \time(); $iExpires = \time();
$aResponse = $oO365->getAccessToken( $aResponse = $oO365->getAccessToken(
static::TOKEN_URI, \str_replace('{{tenant}}', $this->Config()->Get('plugin', 'tenant', 'common'), static::TOKEN_URI),
'authorization_code', 'authorization_code',
array( array(
'code' => $_GET['code'], 'code' => $_GET['code'],
@ -108,7 +109,7 @@ class LoginO365Plugin extends \RainLoop\Plugins\AbstractPlugin
$iExpires += $aResponse['expires_in']; $iExpires += $aResponse['expires_in'];
$oO365->setAccessToken($sAccessToken); $oO365->setAccessToken($sAccessToken);
$aUserInfo = $oO365->fetch('https://www.googleapis.com/oauth2/v2/userinfo'); $aUserInfo = $oO365->fetch('https://graph.microsoft.com/oidc/userinfo"');
if (200 != $aUserInfo['code']) { if (200 != $aUserInfo['code']) {
throw new \RuntimeException("HTTP: {$aResponse['code']}"); throw new \RuntimeException("HTTP: {$aResponse['code']}");
} }
@ -160,13 +161,17 @@ class LoginO365Plugin extends \RainLoop\Plugins\AbstractPlugin
->SetEncrypted(), ->SetEncrypted(),
\RainLoop\Plugins\Property::NewInstance('tenant_id') \RainLoop\Plugins\Property::NewInstance('tenant_id')
->SetLabel('Tenant ID') ->SetLabel('Tenant ID')
->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING) ->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING),
\RainLoop\Plugins\Property::NewInstance('tenant')->SetLabel('Tenant')
->SetType(\RainLoop\Enumerations\PluginPropertyType::SELECTION)
->SetDefaultValue(['common','consumers','organizations'])
->SetAllowedInJs()
]; ];
} }
public function clientLogin(\RainLoop\Model\Account $oAccount, \MailSo\Net\NetClient $oClient, \MailSo\Net\ConnectSettings $oSettings) : void public function clientLogin(\RainLoop\Model\Account $oAccount, \MailSo\Net\NetClient $oClient, \MailSo\Net\ConnectSettings $oSettings) : void
{ {
if ($oAccount instanceof MainAccount && \str_ends_with($oAccount->Email(), '@o365.com')) { if ($oAccount instanceof MainAccount && \str_ends_with($oAccount->Email(), '@hotmail.com')) {
$oActions = \RainLoop\Api::Actions(); $oActions = \RainLoop\Api::Actions();
try { try {
$aData = static::$auth ?: \SnappyMail\Crypt::DecryptFromJSON( $aData = static::$auth ?: \SnappyMail\Crypt::DecryptFromJSON(
@ -183,7 +188,7 @@ class LoginO365Plugin extends \RainLoop\Plugins\AbstractPlugin
$oO365 = $this->o365Connector(); $oO365 = $this->o365Connector();
if ($oO365) { if ($oO365) {
$aRefreshTokenResponse = $oO365->getAccessToken( $aRefreshTokenResponse = $oO365->getAccessToken(
static::TOKEN_URI, \str_replace('{{tenant}}', $this->Config()->Get('plugin', 'tenant', 'common'), static::TOKEN_URI),
'refresh_token', 'refresh_token',
array('refresh_token' => $aData['refresh_token']) array('refresh_token' => $aData['refresh_token'])
); );

View file

@ -66,12 +66,9 @@ abstract class Service
} }
$sQuery = \trim($_SERVER['QUERY_STRING'] ?? ''); $sQuery = \trim($_SERVER['QUERY_STRING'] ?? '');
/*
if (!empty($_SERVER['PATH_INFO'])) { if (!empty($_SERVER['PATH_INFO'])) {
$sQuery = "{$_SERVER['PATH_INFO']}&{$sQuery}"; $sQuery = \ltrim($_SERVER['PATH_INFO'],'/') . '&' . $sQuery;
$_SERVER['REQUEST_URI'] = \substr($_SERVER['REQUEST_URI'],0, -\strlen($_SERVER['REQUEST_URI']));
} }
*/
$iPos = \strpos($sQuery, '&'); $iPos = \strpos($sQuery, '&');
if (0 < $iPos) { if (0 < $iPos) {
$sQuery = \substr($sQuery, 0, $iPos); $sQuery = \substr($sQuery, 0, $iPos);