* Copyright (C) 2015-2024 Frédéric France * Copyright (C) 2024 MDW * Copyright (C) 2026 Vidal Nicolas * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /** * \file htdocs/core/modules/oauth/microsoft3_oauthcallback.php * \ingroup oauth * \brief Page to get oauth callback for Microsoft Exchange Online (SMTP/IMAP) * * Uses Exchange Online OAuth2 scopes for SMTP/IMAP: * - offline_access * - https://outlook.office.com/SMTP.Send * - https://outlook.office.com/IMAP.AccessAsUser.All */ // Load Dolibarr environment require '../../../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/includes/OAuth/bootstrap.php'; /** * @var Conf $conf * @var DoliDB $db * @var Translate $langs * @var User $user * * @var string $dolibarr_main_url_root */ use OAuth\Common\Storage\DoliStorage; use OAuth\Common\Consumer\Credentials; // Define $urlwithroot $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root)); $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file $action = GETPOST('action', 'aZ09'); $backtourl = GETPOST('backtourl', 'alpha'); $keyforprovider = GETPOST('keyforprovider', 'aZ09'); if (empty($keyforprovider) && !empty($_SESSION["oauthkeyforproviderbeforeoauthjump"]) && (GETPOST('code') || $action == 'delete')) { $keyforprovider = $_SESSION["oauthkeyforproviderbeforeoauthjump"]; } $genericstring = 'MICROSOFT3'; /** * Create a new instance of the URI class with the current URI, stripping the query string */ $uriFactory = new \OAuth\Common\Http\Uri\UriFactory(); $currentUri = $uriFactory->createFromAbsolute($urlwithroot.'/core/modules/oauth/microsoft3_oauthcallback.php'); /** * Load the credential for the service */ /** @var \OAuth\ServiceFactory $serviceFactory An OAuth service factory. */ $serviceFactory = new \OAuth\ServiceFactory(); $httpClient = new \OAuth\Common\Http\Client\CurlClient(); $serviceFactory->setHttpClient($httpClient); // Setup the credentials for the requests $keyforparamid = 'OAUTH_'.$genericstring.($keyforprovider ? '-'.$keyforprovider : '').'_ID'; $keyforparamsecret = 'OAUTH_'.$genericstring.($keyforprovider ? '-'.$keyforprovider : '').'_SECRET'; $keyforparamtenant = 'OAUTH_'.$genericstring.($keyforprovider ? '-'.$keyforprovider : '').'_TENANT'; // Dolibarr storage $storage = new DoliStorage($db, $conf, $keyforprovider, getDolGlobalString($keyforparamtenant)); $credentials = new Credentials( getDolGlobalString($keyforparamid), getDolGlobalString($keyforparamsecret), $currentUri->getAbsoluteUri() ); $state = GETPOST('state'); $requestedpermissionsarray = array(); if ($state) { $requestedpermissionsarray = explode(',', $state); // Example: 'user'. 'state' parameter is standard to retrieve some parameters back } if ($action != 'delete' && empty($requestedpermissionsarray)) { print 'Error, parameter state is not defined'; exit; } try { $nameofservice = ucfirst(strtolower($genericstring)); $apiService = $serviceFactory->createService($nameofservice, $credentials, $storage, $requestedpermissionsarray); '@phan-var-force OAuth\OAuth2\Service\AbstractService|OAuth\OAuth1\Service\AbstractService $apiService'; // createService is only ServiceInterface } catch (Exception $e) { print $e->getMessage(); exit; } if (empty($apiService)) { print 'Error, failed to create serviceFactory'; exit; } $langs->load("oauth"); if (!getDolGlobalString($keyforparamid)) { accessforbidden('Setup of service is not complete. Customer ID is missing'); } if (!getDolGlobalString($keyforparamsecret)) { accessforbidden('Setup of service is not complete. Secret key is missing'); } if (!getDolGlobalString($keyforparamtenant)) { accessforbidden('Setup of service is not complete. Tenant/Annuary ID key is missing'); } /* * Actions */ if ($action == 'delete' && (!empty($user->admin) || $user->id == GETPOSTINT('userid'))) { $storage->userid = GETPOSTINT('userid'); $storage->clearToken($genericstring); setEventMessages($langs->trans('TokenDeleted'), null, 'mesgs'); if (empty($backtourl)) { $backtourl = DOL_URL_ROOT.'/'; } header('Location: '.$backtourl); exit(); } if (GETPOST('code') || GETPOST('error')) { // We are coming from oauth provider page // We should have dol_syslog(basename(__FILE__)." We are coming from the oauth provider page code=".dol_trunc(GETPOST('code'), 5)." error=".GETPOST('error')); // We must validate that the $state is the same than the one into $_SESSION['oauthstateanticsrf'], return error if not. if (isset($_SESSION['oauthstateanticsrf']) && $state != $_SESSION['oauthstateanticsrf']) { print $langs->trans("OAuthErrorStateDiffers", dol_escape_htmltag($state)); unset($_SESSION['oauthstateanticsrf']); exit; } // This was a callback request from service, get the token try { if (GETPOST('error')) { setEventMessages(GETPOST('error').' '.GETPOST('error_description'), null, 'errors'); } else { $token = $apiService->requestAccessToken(GETPOST('code')); setEventMessages($langs->trans('NewTokenStored'), null, 'mesgs'); // Stored into object managed by class DoliStorage so into table oauth_token } $backtourl = $_SESSION["backtourlsavedbeforeoauthjump"]; unset($_SESSION["backtourlsavedbeforeoauthjump"]); header('Location: '.$backtourl); exit(); } catch (Exception $e) { print $e->getMessage(); } } else { // If we enter this page without 'code' parameter, we arrive here. This is the case when we want to get the redirect // to the OAuth provider login page. $_SESSION["backtourlsavedbeforeoauthjump"] = $backtourl; $_SESSION["oauthkeyforproviderbeforeoauthjump"] = $keyforprovider; $_SESSION['oauthstateanticsrf'] = $state; // This may create record into oauth_state before the header redirect. // Creation of record with state in this tables depend on the Provider used (see its constructor). $params = array('prompt' => 'consent'); if ($state) { $params['state'] = $state; } $url = $apiService->getAuthorizationUri($params); // Show url to get authorization dol_syslog("Redirect to url=".$url); // we go on oauth provider authorization page header('Location: '.$url); exit(); } /* * View */ // No view at all, just actions $db->close();