diff --git a/htdocs/admin/oauthlogintokens.php b/htdocs/admin/oauthlogintokens.php index 680a5f1f02f..820ce847030 100644 --- a/htdocs/admin/oauthlogintokens.php +++ b/htdocs/admin/oauthlogintokens.php @@ -122,7 +122,7 @@ $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domai $form = new Form($db); -llxHeader('', $langs->trans("PrintingSetup")); +llxHeader('', $langs->trans("TokenManager")); $linkback = ''.$langs->trans("BackToModuleList").''; print load_fiche_titre($langs->trans('ConfigOAuth'), $linkback, 'title_setup'); @@ -163,13 +163,24 @@ if ($mode == 'setup' && $user->admin) { $urltocheckperms = 'https://github.com/settings/applications/'; } elseif ($keyforsupportedoauth2array == 'OAUTH_GOOGLE_NAME') { // List of keys that will be converted into scopes (from constants 'SCOPE_state_in_uppercase' in file of service). - // We pass this param list in to 'state' because we need it before and after the redirect. - $shortscope = 'userinfo_email,userinfo_profile,cloud_print'; - if (!empty($conf->global->OAUTH_GSUITE)) { + // List of scopes for Google are here: https://developers.google.com/identity/protocols/oauth2/scopes + // We pass this key list into the param 'state' because we need it before and after the redirect. + $shortscope = 'userinfo_email,userinfo_profile'; + $shortscope .= ',openid,email,profile'; // For openid connect + if (!empty($conf->printing->enabled)) { + $shortscope .= ',cloud_print'; + } + if (!empty($conf->global->OAUTH_GOOGLE_GSUITE)) { $shortscope .= ',admin_directory_user'; } - //$scope.=',gmail_full'; - $urltorenew = $urlwithroot.'/core/modules/oauth/google_oauthcallback.php?shortscope='.$shortscope.'&state='.$shortscope.'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php'); + if (!empty($conf->global->OAUTH_GOOGLE_GMAIL)) { + $shortscope.=',gmail_full'; + } + + $oauthstateanticsrf = bin2hex(random_bytes(128/8)); + $_SESSION['oauthstateanticsrf'] = $shortscope.'-'.$oauthstateanticsrf; + + $urltorenew = $urlwithroot.'/core/modules/oauth/google_oauthcallback.php?shortscope='.$shortscope.'&state='.$shortscope.$oauthstateanticsrf.'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php'); $urltodelete = $urlwithroot.'/core/modules/oauth/google_oauthcallback.php?action=delete&token='.newToken().'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php'); $urltocheckperms = 'https://security.google.com/settings/security/permissions'; } elseif ($keyforsupportedoauth2array == 'OAUTH_STRIPE_TEST_NAME') { diff --git a/htdocs/core/modules/modPrinting.class.php b/htdocs/core/modules/modPrinting.class.php index 4c104b30ecf..c9e99b3d933 100644 --- a/htdocs/core/modules/modPrinting.class.php +++ b/htdocs/core/modules/modPrinting.class.php @@ -34,7 +34,6 @@ include_once DOL_DOCUMENT_ROOT.'/core/modules/DolibarrModules.class.php'; */ class modPrinting extends DolibarrModules { - /** * Constructor * diff --git a/htdocs/core/modules/oauth/google_oauthcallback.php b/htdocs/core/modules/oauth/google_oauthcallback.php index 4f9fded878f..520da0881e9 100644 --- a/htdocs/core/modules/oauth/google_oauthcallback.php +++ b/htdocs/core/modules/oauth/google_oauthcallback.php @@ -16,6 +16,9 @@ * along with this program. If not, see . */ +// This page should make the process to login and get token as described here: +// https://developers.google.com/identity/protocols/oauth2/openid-connect#server-flow + /** * \file htdocs/core/modules/oauth/google_oauthcallback.php * \ingroup oauth @@ -70,9 +73,13 @@ $credentials = new Credentials( $currentUri->getAbsoluteUri() ); +$state = GETPOST('state'); + $requestedpermissionsarray = array(); -if (GETPOST('state')) { - $requestedpermissionsarray = explode(',', GETPOST('state')); // Example: 'userinfo_email,userinfo_profile,cloud_print'. 'state' parameter is standard to store a hash value and can be used to retrieve some parameters back +if ($state) { + // 'state' parameter is standard to store a hash value and can be used to retrieve some parameters back + $statewithscopeonly = preg_replace('/\-.*$/', '', $state); + $requestedpermissionsarray = explode(',', $statewithscopeonly); // Example: 'userinfo_email,userinfo_profile,openid,email,profile,cloud_print'. } if ($action != 'delete' && empty($requestedpermissionsarray)) { print 'Error, parameter state is not defined'; @@ -80,6 +87,8 @@ if ($action != 'delete' && empty($requestedpermissionsarray)) { } //var_dump($requestedpermissionsarray);exit; + + // Instantiate the Api service using the credentials, http client and storage mechanism for the token // $requestedpermissionsarray contains list of scopes. // Conversion into URL is done by Reflection on constant with name SCOPE_scope_in_uppercase @@ -91,6 +100,8 @@ $apiService->setAccessType('offline'); $apiService->setApprouvalPrompt('force'); +//$apiService->setLoginHint(email); // If we know the email of Google account, we can set it to have it correctly selected on login prompt on multiaccount + $langs->load("oauth"); @@ -108,17 +119,12 @@ if ($action == 'delete') { exit(); } -if (!empty($_GET['code'])) { // We are coming from oauth provider page +if (GETPOST('code')) { // We are coming from oauth provider page. dol_syslog("We are coming from the oauth provider page"); - //llxHeader('',$langs->trans("OAuthSetup")); - //$linkback=''.$langs->trans("BackToModuleList").''; - //print load_fiche_titre($langs->trans("OAuthSetup"),$linkback,'title_setup'); + // TODO + // We should validate that the $sate is same than the one into $_SESSION['oauthstateanticsrf'], return error if not. - //print dol_get_fiche_head(); - // retrieve the CSRF state parameter - $state = isset($_GET['state']) ? $_GET['state'] : null; - //print ''; // This was a callback request from service, get the token try { @@ -126,9 +132,13 @@ if (!empty($_GET['code'])) { // We are coming from oauth provider page //var_dump($state); //var_dump($apiService); // OAuth\OAuth2\Service\Google - $token = $apiService->requestAccessToken($_GET['code'], $state); + // This request the token + // Result is stored into object managed by class DoliStorage into includes/OAuth/Common/Storage/DoliStorage.php, so into table llx_oauth_token + $token = $apiService->requestAccessToken(GETPOST('code'), $state); - setEventMessages($langs->trans('NewTokenStored'), null, 'mesgs'); // Stored into object managed by class DoliStorage so into table oauth_token + // Note: The token contains a lot of information about the user. + + setEventMessages($langs->trans('NewTokenStored'), null, 'mesgs'); $backtourl = $_SESSION["backtourlsavedbeforeoauthjump"]; unset($_SESSION["backtourlsavedbeforeoauthjump"]); @@ -138,8 +148,9 @@ if (!empty($_GET['code'])) { // We are coming from oauth provider page } catch (Exception $e) { print $e->getMessage(); } -} else // If entry on page with no parameter, we arrive here -{ +} 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; // This may create record into oauth_state before the header redirect. @@ -160,6 +171,6 @@ if (!empty($_GET['code'])) { // We are coming from oauth provider page * View */ -// No view at all, just actions +// No view at all, just actions, so we never reach this line, except on error. $db->close(); diff --git a/htdocs/core/tpl/login.tpl.php b/htdocs/core/tpl/login.tpl.php index 338d2bd1a19..2645a76a8ab 100644 --- a/htdocs/core/tpl/login.tpl.php +++ b/htdocs/core/tpl/login.tpl.php @@ -33,6 +33,8 @@ if (empty($conf) || !is_object($conf)) { require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; + + header('Cache-Control: Public, must-revalidate'); header("Content-type: text/html; charset=".$conf->file->character_set_client); @@ -316,6 +318,37 @@ if (isset($conf->file->main_authentication) && preg_match('/openid/', $conf->fil echo ''; } +if (isset($conf->file->main_authentication) && preg_match('/google/', $conf->file->main_authentication)) { + $langs->load("users"); + + global $dolibarr_main_url_root; + + // 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 + //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current + + echo '
'; + echo '
'; + + $shortscope = 'userinfo_email,userinfo_profile'; + $shortscope .= ',openid,email,profile'; // For openid connect + + $oauthstateanticsrf = bin2hex(random_bytes(128/8)); + $_SESSION['oauthstateanticsrf'] = $shortscope.'-'.$oauthstateanticsrf; + $urltorenew = $urlwithroot.'/core/modules/oauth/google_oauthcallback.php?shortscope='.$shortscope.'&state='.$shortscope.$oauthstateanticsrf.'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php'); + + $url = $urltorenew; + + //if (!empty($url)) { + print img_picto('', 'google', 'class="pictofixedwidth"').''.$langs->trans("LoginWith", "Google").''; + /*} else { + $langs->load("errors"); + print ''.$langs->trans("ErrorOpenIDSetupNotComplete", 'MAIN_AUTHENTICATION_OPENID_URL').''; + }*/ + + echo '
'; +} ?> diff --git a/htdocs/langs/en_US/other.lang b/htdocs/langs/en_US/other.lang index 91dd5ba4509..a43e97c1a02 100644 --- a/htdocs/langs/en_US/other.lang +++ b/htdocs/langs/en_US/other.lang @@ -272,7 +272,8 @@ ProjectCreatedByEmailCollector=Project created by email collector from email MSG TicketCreatedByEmailCollector=Ticket created by email collector from email MSGID %s OpeningHoursFormatDesc=Use a - to separate opening and closing hours.
Use a space to enter different ranges.
Example: 8-12 14-18 SuffixSessionName=Suffix for session name - +LoginWith=Login with %s + ##### Export ##### ExportsArea=Exports area AvailableFormats=Available formats