Ver Fonte

WIP Login with Google

Laurent Destailleur há 3 anos atrás
pai
commit
d38784f45a

+ 17 - 6
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 = '<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
 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') {

+ 0 - 1
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
 	 *

+ 26 - 15
htdocs/core/modules/oauth/google_oauthcallback.php

@@ -16,6 +16,9 @@
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
  */
 
+// 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='<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
-	//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 '<table>';
 
 	// 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);
+
+		// Note: The token contains a lot of information about the user.
 
-		setEventMessages($langs->trans('NewTokenStored'), null, 'mesgs'); // Stored into object managed by class DoliStorage so into table oauth_token
+		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();

+ 33 - 0
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 '</div>';
 }
 
+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 '<br>';
+	echo '<div class="center" style="margin-top: 4px;">';
+
+	$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"').'<a class="alogin" href="'.$url.'">'.$langs->trans("LoginWith", "Google").'</a>';
+	/*} else {
+		$langs->load("errors");
+		print '<span class="warning">'.$langs->trans("ErrorOpenIDSetupNotComplete", 'MAIN_AUTHENTICATION_OPENID_URL').'</span>';
+	}*/
+
+	echo '</div>';
+}
 
 ?>
 

+ 2 - 1
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.<br>Use a space to enter different ranges.<br>Example: 8-12 14-18
 SuffixSessionName=Suffix for session name
-
+LoginWith=Login with %s
+ 
 ##### Export #####
 ExportsArea=Exports area
 AvailableFormats=Available formats