Maxi debug of OAuth module. Solve tons of problems.

This commit is contained in:
Laurent Destailleur 2022-06-27 22:35:58 +02:00
parent 3eec5f0e69
commit 34464ac92b
13 changed files with 468 additions and 295 deletions

View File

@ -43,6 +43,8 @@ if (!$user->admin) {
}
$action = GETPOST('action', 'aZ09');
$provider = GETPOST('provider', 'aZ09');
$label = GETPOST('label', 'aZ09');
/*
@ -52,21 +54,28 @@ $action = GETPOST('action', 'aZ09');
if ($action == 'update') {
$error = 0;
foreach ($list as $constname) {
$constvalue = GETPOST($constname[1], 'alpha');
if (!dolibarr_set_const($db, $constname[1], $constvalue, 'chaine', 0, '', $conf->entity)) {
$error++;
}
$constvalue = GETPOST($constname[2], 'alpha');
if (!dolibarr_set_const($db, $constname[2], $constvalue, 'chaine', 0, '', $conf->entity)) {
$error++;
}
}
if (!$error) {
setEventMessages($langs->trans("SetupSaved"), null);
if (GETPOST('add') && $provider && $provider != '-1') { // $provider is OAUTH_XXX
$constname = strtoupper($provider).($label ? '-'.$label : '').'_ID';
dolibarr_set_const($db, $constname, 'ToComplete', 'chaine', 0, '', $conf->entity);
} else {
setEventMessages($langs->trans("Error"), null, 'errors');
foreach ($conf->global as $key => $val) {
if (!empty($val) && preg_match('/^OAUTH_.+_ID$/', $key)) {
$constvalue = str_replace('_ID', '', $key);
if (!dolibarr_set_const($db, $constvalue.'_ID', GETPOST($constvalue.'_ID'), 'chaine', 0, '', $conf->entity)) {
$error++;
}
// If we reset this provider, we also remove the secret
if (!dolibarr_set_const($db, $constvalue.'_SECRET', GETPOST($constvalue.'_ID') ? GETPOST($constvalue.'_SECRET') : '', 'chaine', 0, '', $conf->entity)) {
$error++;
}
}
}
if (!$error) {
setEventMessages($langs->trans("SetupSaved"), null);
} else {
setEventMessages($langs->trans("Error"), null, 'errors');
}
}
}
@ -92,15 +101,57 @@ print dol_get_fiche_head($head, 'services', '', -1, 'technic');
print '<span class="opacitymedium">'.$langs->trans("ListOfSupportedOauthProviders").'</span><br><br>';
print '<select name="provider" id="provider">';
print '<option name="-1" value="-1">'.$langs->trans("Type").'</option>';
foreach ($list as $key) {
$supported = 0;
$keyforsupportedoauth2array = $key[0];
if (in_array($keyforsupportedoauth2array, array_keys($supportedoauth2array))) {
$supported = 1;
}
if (!$supported) {
continue; // show only supported
}
$i++;
print '<option name="'.$keyforsupportedoauth2array.'" value="'.str_replace('_NAME', '', $keyforsupportedoauth2array).'">'.$supportedoauth2array[$keyforsupportedoauth2array]['name'].'</option>'."\n";
}
print '</select>';
print ajax_combobox('provider');
print ' <input type="text" name="label" value="" placeholder="'.$langs->trans("Name").'">';
print ' <input type="submit" class="button small" name="add" value="'.$langs->trans("Add").'">';
print '<br>';
print '<br>';
print '<div class="div-table-responsive">';
print '<table class="noborder centpercent">';
$i = 0;
//var_dump($list);
foreach ($conf->global as $key => $val) {
if (!empty($val) && preg_match('/^OAUTH_.*_ID$/', $key)) {
$provider = preg_replace('/_ID$/', '', $key);
$listinsetup[] = array($provider.'_NAME', $provider.'_ID', $provider.'_SECRET', 'OAUTH Provider '.str_replace('OAUTH_', '', $provider));
}
}
// $list is defined into oauth.lib.php to the list of supporter OAuth providers.
foreach ($list as $key) {
foreach ($listinsetup as $key) {
$supported = 0;
$keyforsupportedoauth2array = $key[0];
$keyforsupportedoauth2array = $key[0]; // May be OAUTH_GOOGLE_NAME or OAUTH_GOOGLE_xxx_NAME
$keyforsupportedoauth2array = preg_replace('/^OAUTH_/', '', $keyforsupportedoauth2array);
$keyforsupportedoauth2array = preg_replace('/_NAME$/', '', $keyforsupportedoauth2array);
if (preg_match('/^.*-/', $keyforsupportedoauth2array)) {
$keyforprovider = preg_replace('/^.*-/', '', $keyforsupportedoauth2array);
} else {
$keyforprovider = '';
}
$keyforsupportedoauth2array = preg_replace('/-.*$/', '', $keyforsupportedoauth2array);
$keyforsupportedoauth2array = 'OAUTH_'.$keyforsupportedoauth2array.'_NAME';
if (in_array($keyforsupportedoauth2array, array_keys($supportedoauth2array))) {
$supported = 1;
@ -117,10 +168,15 @@ foreach ($list as $key) {
print '<td>';
print img_picto('', $supportedoauth2array[$keyforsupportedoauth2array]['picto'], 'class="pictofixedwidth"');
print $label;
if ($keyforprovider) {
print ' (<b>'.$keyforprovider.'</b>)';
} else {
print ' (<b>'.$langs->trans("NoName").'</b>)';
}
print '</td>';
print '<td>';
if (!empty($supportedoauth2array[$keyforsupportedoauth2array]['urlforapp'])) {
print $langs->trans($supportedoauth2array[$keyforsupportedoauth2array]['urlforapp']);
if (!empty($supportedoauth2array[$keyforsupportedoauth2array]['urlforcredentials'])) {
print $langs->trans("OAUTH_URL_FOR_CREDENTIAL", $supportedoauth2array[$keyforsupportedoauth2array]['urlforcredentials']);
}
print '</td>';
print '</tr>';
@ -140,13 +196,13 @@ foreach ($list as $key) {
// Api Id
print '<tr class="oddeven value">';
print '<td><label for="'.$key[1].'">'.$langs->trans($key[1]).'</label></td>';
print '<td><label for="'.$key[1].'">'.$langs->trans("OAUTH_ID").'</label></td>';
print '<td><input type="text" size="100" id="'.$key[1].'" name="'.$key[1].'" value="'.$conf->global->{$key[1]}.'">';
print '</td></tr>';
// Api Secret
print '<tr class="oddeven value">';
print '<td><label for="'.$key[2].'">'.$langs->trans($key[2]).'</label></td>';
print '<td><label for="'.$key[2].'">'.$langs->trans("OAUTH_SECRET").'</label></td>';
print '<td><input type="password" size="100" id="'.$key[2].'" name="'.$key[2].'" value="'.$conf->global->{$key[2]}.'">';
print '</td></tr>';
}

View File

@ -138,19 +138,32 @@ if (GETPOST('error')) {
if ($mode == 'setup' && $user->admin) {
print '<span class="opacitymedium">'.$langs->trans("OAuthSetupForLogin")."</span><br><br>\n";
foreach ($list as $key) {
//var_dump($list);
foreach ($conf->global as $key => $val) {
if (!empty($val) && preg_match('/^OAUTH_.*_ID$/', $key)) {
$provider = preg_replace('/_ID$/', '', $key);
$listinsetup[] = array($provider.'_NAME', $provider.'_ID', $provider.'_SECRET', 'OAUTH Provider '.str_replace('OAUTH_', '', $provider));
}
}
$oauthstateanticsrf = bin2hex(random_bytes(128/8));
// $list is defined into oauth.lib.php to the list of supporter OAuth providers.
foreach ($listinsetup as $key) {
$supported = 0;
$keyforsupportedoauth2array = $key[0];
if (in_array($keyforsupportedoauth2array, array_keys($supportedoauth2array))) {
$supported = 1;
}
if (!$supported) {
continue; // show only supported
$keyforsupportedoauth2array = $key[0]; // May be OAUTH_GOOGLE_NAME or OAUTH_GOOGLE_xxx_NAME
$keyforsupportedoauth2array = preg_replace('/^OAUTH_/', '', $keyforsupportedoauth2array);
$keyforsupportedoauth2array = preg_replace('/_NAME$/', '', $keyforsupportedoauth2array);
if (preg_match('/^.*-/', $keyforsupportedoauth2array)) {
$keyforprovider = preg_replace('/^.*-/', '', $keyforsupportedoauth2array);
} else {
$keyforprovider = '';
}
$keyforsupportedoauth2array = preg_replace('/-.*$/', '', $keyforsupportedoauth2array);
$keyforsupportedoauth2array = 'OAUTH_'.$keyforsupportedoauth2array.'_NAME';
$OAUTH_SERVICENAME = empty($supportedoauth2array[$keyforsupportedoauth2array]['name']) ? 'Unknown' : $supportedoauth2array[$keyforsupportedoauth2array]['name'];
$OAUTH_SERVICENAME = (empty($supportedoauth2array[$keyforsupportedoauth2array]['name']) ? 'Unknown' : $supportedoauth2array[$keyforsupportedoauth2array]['name'].($keyforprovider ? '-'.$keyforprovider : ''));
// Define $shortscope, $urltorenew, $urltodelete, $urltocheckperms
// TODO Use array $supportedoauth2array
@ -158,6 +171,8 @@ if ($mode == 'setup' && $user->admin) {
// 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 = 'user,public_repo';
// Note: github does not accept csrf key inside the state parameter (only know values)
$urltorenew = $urlwithroot.'/core/modules/oauth/github_oauthcallback.php?shortscope='.$shortscope.'&state='.$shortscope.'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
$urltodelete = $urlwithroot.'/core/modules/oauth/github_oauthcallback.php?action=delete&token='.newToken().'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
$urltocheckperms = 'https://github.com/settings/applications/';
@ -177,17 +192,18 @@ if ($mode == 'setup' && $user->admin) {
$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') {
$shortscope = 'none';
$urltorenew = $urlwithroot.'/core/modules/oauth/stripetest_oauthcallback.php?backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
$urltodelete = '';
$urltocheckperms = '';
} elseif ($keyforsupportedoauth2array == 'OAUTH_STRIPE_LIVE_NAME') {
$shortscope = 'none';
$urltorenew = $urlwithroot.'/core/modules/oauth/stripelive_oauthcallback.php?backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
$urltodelete = '';
$urltocheckperms = '';
@ -196,7 +212,7 @@ if ($mode == 'setup' && $user->admin) {
$urltodelete = '';
$urltocheckperms = '';
}
$urltorenew .= '&keyforprovider='.$keyforprovider;
// Show value of token
$tokenobj = null;
@ -220,7 +236,6 @@ if ($mode == 'setup' && $user->admin) {
if (is_object($tokenobj)) {
$expire = ($tokenobj->getEndOfLife() !== $tokenobj::EOL_NEVER_EXPIRES && $tokenobj->getEndOfLife() !== $tokenobj::EOL_UNKNOWN && time() > ($tokenobj->getEndOfLife() - 30));
}
if ($key[1] != '' && $key[2] != '') {
if (is_object($tokenobj)) {
$refreshtoken = $tokenobj->getRefreshToken();
@ -249,6 +264,11 @@ if ($mode == 'setup' && $user->admin) {
print '<th class="titlefieldcreate">';
print img_picto('', $supportedoauth2array[$keyforsupportedoauth2array]['picto'], 'class="pictofixedwidth"');
print $langs->trans($keyforsupportedoauth2array);
if ($keyforprovider) {
print ' (<b>'.$keyforprovider.'</b>)';
} else {
print ' (<b>'.$langs->trans("NoName").'</b>)';
}
print '</th>';
print '<th></th>';
print '<th></th>';
@ -299,9 +319,11 @@ if ($mode == 'setup' && $user->admin) {
//var_dump($key);
print $langs->trans("Token").'</td>';
print '<td colspan="2">';
if (is_object($tokenobj)) {
//var_dump($tokenobj);
print $tokenobj->getAccessToken().'<br>';
$tokentoshow = $tokenobj->getAccessToken();
print '<span class="" title="'.dol_escape_htmltag($tokentoshow).'">'.showValueWithClipboardCPButton($tokentoshow, 1, dol_trunc($tokentoshow, 32)).'<br>';
//print 'Refresh: '.$tokenobj->getRefreshToken().'<br>';
//print 'EndOfLife: '.$tokenobj->getEndOfLife().'<br>';
//var_dump($tokenobj->getExtraParams());
@ -317,9 +339,10 @@ if ($mode == 'setup' && $user->admin) {
print '<tr class="oddeven">';
print '<td'.($key['required'] ? ' class="required"' : '').'>';
//var_dump($key);
print $langs->trans("TOKEN_REFRESH").'</td>';
print $langs->trans("TOKEN_REFRESH");
print '</td>';
print '<td colspan="2">';
print yn($refreshtoken);
print '<span class="" title="'.dol_escape_htmltag($refreshtoken).'">'.showValueWithClipboardCPButton($refreshtoken, 1, dol_trunc($refreshtoken, 32)).'</span>';
print '</td>';
print '</tr>';
@ -327,7 +350,8 @@ if ($mode == 'setup' && $user->admin) {
print '<tr class="oddeven">';
print '<td'.($key['required'] ? ' class="required"' : '').'>';
//var_dump($key);
print $langs->trans("TOKEN_EXPIRED").'</td>';
print $langs->trans("TOKEN_EXPIRED");
print '</td>';
print '<td colspan="2">';
print yn($expire);
print '</td>';
@ -337,7 +361,8 @@ if ($mode == 'setup' && $user->admin) {
print '<tr class="oddeven">';
print '<td'.($key['required'] ? ' class="required"' : '').'>';
//var_dump($key);
print $langs->trans("TOKEN_EXPIRE_AT").'</td>';
print $langs->trans("TOKEN_EXPIRE_AT");
print '</td>';
print '<td colspan="2">';
print $expiredat;
print '</td>';
@ -399,17 +424,18 @@ if ($mode == 'userconf' && $user->admin) {
print '<th>'.$langs->trans("NumberOfCopy").'</th>';
print '<th class="center">'.$langs->trans("Delete").'</th>';
print "</tr>\n";
$sql = 'SELECT p.rowid, p.printer_name, p.printer_location, p.printer_id, p.copy, p.module, p.driver, p.userid, u.login FROM '.MAIN_DB_PREFIX.'printing as p, '.MAIN_DB_PREFIX.'user as u WHERE p.userid=u.rowid';
$sql = "SELECT p.rowid, p.printer_name, p.printer_location, p.printer_id, p.copy, p.module, p.driver, p.userid, u.login";
$sql .= " FROM ".MAIN_DB_PREFIX."printing as p, ".MAIN_DB_PREFIX."user as u WHERE p.userid = u.rowid";
$resql = $db->query($sql);
while ($row = $db->fetch_array($resql)) {
while ($obj = $db->fetch_object($resql)) {
print '<tr class="oddeven">';
print '<td>'.$row['login'].'</td>';
print '<td>'.$row['module'].'</td>';
print '<td>'.$row['driver'].'</td>';
print '<td>'.$row['printer_name'].'</td>';
print '<td>'.$row['printer_location'].'</td>';
print '<td>'.$row['printer_id'].'</td>';
print '<td>'.$row['copy'].'</td>';
print '<td>'.$obj->login.'</td>';
print '<td>'.$obj->module.'</td>';
print '<td>'.$obj->driver.'</td>';
print '<td>'.$obj->printer_name.'</td>';
print '<td>'.$obj->printer_location.'</td>';
print '<td>'.$obj->printer_id.'</td>';
print '<td>'.$obj->copy.'</td>';
print '<td class="center">'.img_picto($langs->trans("Delete"), 'delete').'</td>';
print "</tr>\n";
}

View File

@ -6459,6 +6459,7 @@ function get_default_localtax($thirdparty_seller, $thirdparty_buyer, $local, $id
function yn($yesno, $case = 1, $color = 0)
{
global $langs;
$result = 'unknown';
$classname = '';
if ($yesno == 1 || strtolower($yesno) == 'yes' || strtolower($yesno) == 'true') { // A mettre avant test sur no a cause du == 0

View File

@ -25,13 +25,13 @@
// Supported OAUTH (a provider is supported when a file xxx_oauthcallback.php is available into htdocs/core/modules/oauth)
$supportedoauth2array = array(
'OAUTH_GOOGLE_NAME'=>array('callbackfile' => 'google', 'picto' => 'google', 'urlforapp' => 'OAUTH_GOOGLE_DESC', 'name'=>'Google'),
'OAUTH_GOOGLE_NAME'=>array('callbackfile' => 'google', 'picto' => 'google', 'urlforapp' => 'OAUTH_GOOGLE_DESC', 'name'=>'Google', 'urlforcredentials'=>'https://console.developers.google.com/'),
);
if (!empty($conf->stripe->enabled)) {
$supportedoauth2array['OAUTH_STRIPE_TEST_NAME'] = array('callbackfile' => 'stripetest', 'picto' => 'stripe', 'urlforapp' => '', 'name'=>'StripeTest');
$supportedoauth2array['OAUTH_STRIPE_LIVE_NAME'] = array('callbackfile' => 'stripelive', 'picto' => 'stripe', 'urlforapp' => '', 'name'=>'StripeLive');
$supportedoauth2array['OAUTH_STRIPE_TEST_NAME'] = array('callbackfile' => 'stripetest', 'picto' => 'stripe', 'urlforapp' => '', 'name'=>'StripeTest', 'urlforcredentials'=>'');
$supportedoauth2array['OAUTH_STRIPE_LIVE_NAME'] = array('callbackfile' => 'stripelive', 'picto' => 'stripe', 'urlforapp' => '', 'name'=>'StripeLive', 'urlforcredentials'=>'');
}
$supportedoauth2array['OAUTH_GITHUB_NAME'] = array('callbackfile' => 'github', 'picto' => 'github', 'urlforapp' => 'OAUTH_GITHUB_DESC', 'name'=>'GitHub');
$supportedoauth2array['OAUTH_GITHUB_NAME'] = array('callbackfile' => 'github', 'picto' => 'github', 'urlforapp' => 'OAUTH_GITHUB_DESC', 'name'=>'GitHub', 'urlforcredentials'=>'https://github.com/settings/developers');

View File

@ -34,9 +34,12 @@ $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domai
//$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
$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"];
}
/**
@ -64,9 +67,11 @@ $serviceFactory->setHttpClient($httpClient);
$storage = new DoliStorage($db, $conf);
// Setup the credentials for the requests
$keyforparamid = 'OAUTH_GITHUB'.($keyforprovider ? '-'.$keyforprovider : '').'_ID';
$keyforparamsecret = 'OAUTH_GITHUB'.($keyforprovider ? '-'.$keyforprovider : '').'_SECRET';
$credentials = new Credentials(
$conf->global->OAUTH_GITHUB_ID,
$conf->global->OAUTH_GITHUB_SECRET,
getDolGlobalString($keyforparamid),
getDolGlobalString($keyforparamsecret),
$currentUri->getAbsoluteUri()
);
@ -81,13 +86,20 @@ if ($action != 'delete' && empty($requestedpermissionsarray)) {
//var_dump($requestedpermissionsarray);exit;
// Instantiate the Api service using the credentials, http client and storage mechanism for the token
$apiService = $serviceFactory->createService('GitHub', $credentials, $storage, $requestedpermissionsarray);
$apiService = $serviceFactory->createService('GitHub'.($keyforprovider ? '-'.$keyforprovider : ''), $credentials, $storage, $requestedpermissionsarray);
// access type needed to have oauth provider refreshing token
//$apiService->setAccessType('offline');
$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');
}
/*
* Actions
@ -140,14 +152,15 @@ 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 entry on page with no parameter, we arrive here
$_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).
if (GETPOST('state')) {
$url = $apiService->getAuthorizationUri(array('state'=>GETPOST('state')));
$url = $apiService->getAuthorizationUri(array('state' => GETPOST('state')));
} else {
$url = $apiService->getAuthorizationUri(); // Parameter state will be randomly generated
}

View File

@ -40,6 +40,11 @@ $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domai
$action = GETPOST('action', 'aZ09');
$backtourl = GETPOST('backtourl', 'alpha');
$keyforprovider = GETPOST('keyforprovider', 'aZ09');
if (empty($keyforprovider) && !empty($_SESSION["oauthkeyforproviderbeforeoauthjump"]) && (GETPOST('code') || $action == 'delete')) {
// If we are coming from the Oauth page
$keyforprovider = $_SESSION["oauthkeyforproviderbeforeoauthjump"];
}
/**
@ -63,23 +68,25 @@ $httpClient = new \OAuth\Common\Http\Client\CurlClient();
//$httpClient->setCurlParameters($params);
$serviceFactory->setHttpClient($httpClient);
// Dolibarr storage
$storage = new DoliStorage($db, $conf);
// Setup the credentials for the requests
$keyforparamid = 'OAUTH_GOOGLE'.($keyforprovider ? '-'.$keyforprovider : '').'_ID';
$keyforparamsecret = 'OAUTH_GOOGLE'.($keyforprovider ? '-'.$keyforprovider : '').'_SECRET';
$credentials = new Credentials(
$conf->global->OAUTH_GOOGLE_ID,
$conf->global->OAUTH_GOOGLE_SECRET,
getDolGlobalString($keyforparamid),
getDolGlobalString($keyforparamsecret),
$currentUri->getAbsoluteUri()
);
$state = GETPOST('state');
$statewithscopeonly = '';
$statewithanticsrfonly = '';
$requestedpermissionsarray = array();
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'.
$statewithanticsrfonly = preg_replace('/^.*\-/', '', $state);
}
if ($action != 'delete' && empty($requestedpermissionsarray)) {
print 'Error, parameter state is not defined';
@ -88,6 +95,8 @@ if ($action != 'delete' && empty($requestedpermissionsarray)) {
//var_dump($requestedpermissionsarray);exit;
// Dolibarr storage
$storage = new DoliStorage($db, $conf, $keyforprovider);
// Instantiate the Api service using the credentials, http client and storage mechanism for the token
// $requestedpermissionsarray contains list of scopes.
@ -101,6 +110,13 @@ $apiService->setAccessType('offline');
$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');
}
/*
* Actions
@ -117,7 +133,7 @@ if ($action == 'delete') {
}
if (GETPOST('code')) { // We are coming from oauth provider page.
dol_syslog("We are coming from the oauth provider page");
dol_syslog("We are coming from the oauth provider page keyforprovider=".$keyforprovider);
// 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']) {
@ -174,8 +190,10 @@ if (GETPOST('code')) { // We are coming from oauth provider page.
}
} 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
// to the OAuth provider login page.
$_SESSION["backtourlsavedbeforeoauthjump"] = $backtourl;
$_SESSION["oauthkeyforproviderbeforeoauthjump"] = $keyforprovider;
$_SESSION['oauthstateanticsrf'] = $state;
if (!preg_match('/^forlogin/', $state)) {
$apiService->setApprouvalPrompt('force');

View File

@ -34,9 +34,12 @@ $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domai
//$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
$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"];
}
/**
@ -64,9 +67,11 @@ $serviceFactory->setHttpClient($httpClient);
$storage = new DoliStorage($db, $conf);
// Setup the credentials for the requests
$keyforparamid = 'OAUTH_STRIPE_LIVE'.($keyforprovider ? '-'.$keyforprovider : '').'_ID';
$keyforparamsecret = 'OAUTH_STRIPE_LIVE'.($keyforprovider ? '-'.$keyforprovider : '').'_SECRET';
$credentials = new Credentials(
$conf->global->OAUTH_STRIPE_LIVE_ID,
$conf->global->STRIPE_LIVE_SECRET_KEY,
getDolGlobalString($keyforparamid),
getDolGlobalString($keyforparamsecret),
$currentUri->getAbsoluteUri()
);
@ -84,7 +89,7 @@ if (GETPOST('state')) {
// Instantiate the Api service using the credentials, http client and storage mechanism for the token
//$apiService = $serviceFactory->createService('StripeTest', $credentials, $storage, $requestedpermissionsarray);
$sql = "INSERT INTO ".MAIN_DB_PREFIX."oauth_token set service='StripeLive', entity=".$conf->entity;
$sql = "INSERT INTO ".MAIN_DB_PREFIX."oauth_token SET service = 'StripeLive".($keyforprovider ? '-'.$keyforprovider : '')."', entity=".$conf->entity;
$db->query($sql);
// access type needed to have oauth provider refreshing token
@ -92,6 +97,13 @@ $db->query($sql);
$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');
}
/*
* Actions
@ -148,6 +160,8 @@ if (!empty($_GET['code'])) { // We are coming from oauth provider page
} else // If entry on page with no parameter, we arrive here
{
$_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).
@ -156,7 +170,7 @@ if (!empty($_GET['code'])) { // We are coming from oauth provider page
} else {
//$url = $apiService->getAuthorizationUri(); // Parameter state will be randomly generated
//https://connect.stripe.com/oauth/authorize?response_type=code&client_id=ca_AX27ut70tJ1j6eyFCV3ObEXhNOo2jY6V&scope=read_write
$url = 'https://connect.stripe.com/oauth/authorize?response_type=code&client_id='.$conf->global->OAUTH_STRIPE_LIVE_ID.'&scope=read_write';
$url = 'https://connect.stripe.com/oauth/authorize?response_type=code&client_id='.$conf->global->$keyforparamid.'&scope=read_write';
}
// we go on oauth provider authorization page

View File

@ -34,9 +34,12 @@ $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domai
//$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
$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"];
}
/**
@ -64,9 +67,11 @@ $serviceFactory->setHttpClient($httpClient);
$storage = new DoliStorage($db, $conf);
// Setup the credentials for the requests
$keyforparamid = 'OAUTH_STRIPE_TEST'.($keyforprovider ? '-'.$keyforprovider : '').'_ID';
$keyforparamsecret = 'OAUTH_STRIPE_TEST'.($keyforprovider ? '-'.$keyforprovider : '').'_SECRET';
$credentials = new Credentials(
$conf->global->OAUTH_STRIPE_TEST_ID,
$conf->global->STRIPE_TEST_SECRET_KEY,
getDolGlobalString($keyforparamid),
getDolGlobalString($keyforparamsecret),
$currentUri->getAbsoluteUri()
);
@ -84,7 +89,7 @@ if (GETPOST('state')) {
// Instantiate the Api service using the credentials, http client and storage mechanism for the token
//$apiService = $serviceFactory->createService('StripeTest', $credentials, $storage, $requestedpermissionsarray);
$sql = "INSERT INTO ".MAIN_DB_PREFIX."oauth_token set service='StripeTest', entity=".$conf->entity;
$sql = "INSERT INTO ".MAIN_DB_PREFIX."oauth_token SET service = 'StripeTest".($keyforprovider ? '-'.$keyforprovider : '')."', entity=".$conf->entity;
$db->query($sql);
// access type needed to have oauth provider refreshing token
@ -92,6 +97,13 @@ $db->query($sql);
$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');
}
/*
* Actions
@ -148,6 +160,8 @@ if (!empty($_GET['code'])) { // We are coming from oauth provider page
} else // If entry on page with no parameter, we arrive here
{
$_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).
@ -156,7 +170,7 @@ if (!empty($_GET['code'])) { // We are coming from oauth provider page
} else {
//$url = $apiService->getAuthorizationUri(); // Parameter state will be randomly generated
//https://connect.stripe.com/oauth/authorize?response_type=code&client_id=ca_AX27ut70tJ1j6eyFCV3ObEXhNOo2jY6V&scope=read_write
$url = 'https://connect.stripe.com/oauth/authorize?response_type=code&client_id='.$conf->global->OAUTH_STRIPE_TEST_ID.'&scope=read_write';
$url = 'https://connect.stripe.com/oauth/authorize?response_type=code&client_id='.$conf->global->$keyforparamid.'&scope=read_write';
}
// we go on oauth provider authorization page

View File

@ -29,257 +29,280 @@ use OAuth\Common\Storage\Exception\TokenNotFoundException;
use OAuth\Common\Storage\Exception\AuthorizationStateNotFoundException;
use DoliDB;
/**
* Class to manage storage of OAUTH2 in Dolibarr
*/
class DoliStorage implements TokenStorageInterface
{
/**
* @var DoliDB Database handler
*/
protected $db;
/**
* @var DoliDB Database handler
*/
protected $db;
/**
* @var object|TokenInterface
*/
protected $tokens;
/**
* @var object|TokenInterface
*/
protected $tokens;
/**
* @var string Error code (or message)
*/
public $error;
/**
* @var string[] Several error codes (or messages)
*/
public $errors = array();
/**
* @var string Error code (or message)
*/
public $error;
/**
* @var string[] Several error codes (or messages)
*/
public $errors = array();
private $conf;
private $key;
private $stateKey;
private $conf;
private $key;
private $stateKey;
private $keyforprovider;
/**
* @param Conf $conf
* @param string $key
* @param string $stateKey
*/
public function __construct(DoliDB $db, $conf)
{
$this->db = $db;
$this->conf = $conf;
$this->tokens = array();
$this->states = array();
//$this->key = $key;
//$this->stateKey = $stateKey;
}
/**
* {@inheritDoc}
*/
public function retrieveAccessToken($service)
{
if ($this->hasAccessToken($service)) {
return $this->tokens[$service];
}
/**
* @param DoliDB $db Database handler
* @param Conf $conf Conf object
* @param string $keyforprovider Key to manage several providers of the same type. For example 'abc' will be added to 'Google' to defined storage key.
*/
public function __construct(DoliDB $db, $conf, $keyforprovider = '')
{
$this->db = $db;
$this->conf = $conf;
$this->keyforprovider = $keyforprovider;
$this->tokens = array();
$this->states = array();
//$this->key = $key;
//$this->stateKey = $stateKey;
}
throw new TokenNotFoundException('Token not found in db, are you sure you stored it?');
}
/**
* {@inheritDoc}
*/
public function retrieveAccessToken($service)
{
dol_syslog("retrieveAccessToken service=".$service);
/**
* {@inheritDoc}
*/
public function storeAccessToken($service, TokenInterface $token)
{
//var_dump("storeAccessToken");
//var_dump($token);
dol_syslog("storeAccessToken");
$serializedToken = serialize($token);
$this->tokens[$service] = $token;
if ($this->hasAccessToken($service)) {
return $this->tokens[$service];
}
if (!is_array($this->tokens)) {
$this->tokens = array();
}
$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."oauth_token";
$sql.= " WHERE service='".$this->db->escape($service)."' AND entity=1";
$resql = $this->db->query($sql);
if (! $resql)
{
dol_print_error($this->db);
}
$obj = $this->db->fetch_array($resql);
if ($obj) {
// update
$sql = "UPDATE ".MAIN_DB_PREFIX."oauth_token";
$sql.= " SET token='".$this->db->escape($serializedToken)."'";
$sql.= " WHERE rowid='".$obj['rowid']."'";
$resql = $this->db->query($sql);
} else {
// save
$sql = "INSERT INTO ".MAIN_DB_PREFIX."oauth_token (service, token, entity)";
$sql.= " VALUES ('".$this->db->escape($service)."', '".$this->db->escape($serializedToken)."', 1)";
$resql = $this->db->query($sql);
}
//print $sql;
// allow chaining
return $this;
}
throw new TokenNotFoundException('Token not found in db, are you sure you stored it?');
}
/**
* {@inheritDoc}
*/
public function hasAccessToken($service)
{
// get from db
dol_syslog("hasAccessToken service=".$service);
$sql = "SELECT token FROM ".MAIN_DB_PREFIX."oauth_token";
$sql.= " WHERE service='".$this->db->escape($service)."'";
$resql = $this->db->query($sql);
if (! $resql)
{
dol_print_error($this->db);
}
$result = $this->db->fetch_array($resql);
$token = unserialize($result['token']);
$this->tokens[$service] = $token;
/**
* {@inheritDoc}
*/
public function storeAccessToken($service, TokenInterface $token)
{
global $conf;
return is_array($this->tokens)
&& isset($this->tokens[$service])
&& $this->tokens[$service] instanceof TokenInterface;
}
//var_dump("storeAccessToken");
//var_dump($token);
dol_syslog("storeAccessToken service=".$service);
/**
* {@inheritDoc}
*/
public function clearToken($service)
{
// TODO
// get previously saved tokens
//$tokens = $this->retrieveAccessToken($service);
$serializedToken = serialize($token);
$this->tokens[$service] = $token;
//if (is_array($tokens) && array_key_exists($service, $tokens)) {
// unset($tokens[$service]);
if (!is_array($this->tokens)) {
$this->tokens = array();
}
$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."oauth_token";
$sql .= " WHERE service = '".$this->db->escape($service.($this->keyforprovider?'-'.$this->keyforprovider:''))."'";
$sql .= " AND entity IN (".getEntity('oauth_token').")";
$resql = $this->db->query($sql);
if (! $resql) {
dol_print_error($this->db);
}
$obj = $this->db->fetch_array($resql);
if ($obj) {
// update
$sql = "UPDATE ".MAIN_DB_PREFIX."oauth_token";
$sql.= " SET token = '".$this->db->escape($serializedToken)."'";
$sql.= " WHERE rowid = ".((int) $obj['rowid']);
$resql = $this->db->query($sql);
} else {
// save
$sql = "INSERT INTO ".MAIN_DB_PREFIX."oauth_token (service, token, entity)";
$sql.= " VALUES ('".$this->db->escape($service.($this->keyforprovider?'-'.$this->keyforprovider:''))."', '".$this->db->escape($serializedToken)."', ".((int) $conf->entity).")";
$resql = $this->db->query($sql);
}
//print $sql;
$sql = "DELETE FROM ".MAIN_DB_PREFIX."oauth_token";
$sql.= " WHERE service='".$this->db->escape($service)."'";
$resql = $this->db->query($sql);
//}
// allow chaining
return $this;
}
// allow chaining
return $this;
}
/**
* {@inheritDoc}
*/
public function hasAccessToken($service)
{
// get from db
dol_syslog("hasAccessToken service=".$service);
/**
* {@inheritDoc}
*/
public function clearAllTokens()
{
// TODO
$this->conf->remove($this->key);
$sql = "SELECT token FROM ".MAIN_DB_PREFIX."oauth_token";
$sql .= " WHERE service = '".$this->db->escape($service.($this->keyforprovider?'-'.$this->keyforprovider:''))."'";
$sql .= " AND entity IN (".getEntity('oauth_token').")";
$resql = $this->db->query($sql);
if (! $resql) {
dol_print_error($this->db);
}
$result = $this->db->fetch_array($resql);
$token = unserialize($result['token']);
// allow chaining
return $this;
}
$this->tokens[$service] = $token;
/**
* {@inheritDoc}
*/
public function retrieveAuthorizationState($service)
{
if ($this->hasAuthorizationState($service)) {
return $this->states[$service];
return is_array($this->tokens)
&& isset($this->tokens[$service])
&& $this->tokens[$service] instanceof TokenInterface;
}
}
/**
* {@inheritDoc}
*/
public function clearToken($service)
{
dol_syslog("clearToken service=".$service);
throw new AuthorizationStateNotFoundException('State not found in db, are you sure you stored it?');
}
// TODO
// get previously saved tokens
//$tokens = $this->retrieveAccessToken($service);
/**
* {@inheritDoc}
*/
public function storeAuthorizationState($service, $state)
{
// TODO save or update
//if (is_array($tokens) && array_key_exists($service, $tokens)) {
// unset($tokens[$service]);
if (!is_array($states)) {
$states = array();
}
$sql = "DELETE FROM ".MAIN_DB_PREFIX."oauth_token";
$sql .= " WHERE service = '".$this->db->escape($service.($this->keyforprovider?'-'.$this->keyforprovider:''))."'";
$sql .= " AND entity IN (".getEntity('oauth_token').")";
$resql = $this->db->query($sql);
//}
$states[$service] = $state;
$this->states[$service] = $state;
// allow chaining
return $this;
}
$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."oauth_state";
$sql.= " WHERE service='".$this->db->escape($service)."' AND entity=1";
$resql = $this->db->query($sql);
if (! $resql)
{
dol_print_error($this->db);
}
$obj = $this->db->fetch_array($resql);
if ($obj) {
// update
$sql = "UPDATE ".MAIN_DB_PREFIX."oauth_state";
$sql.= " SET state='".$this->db->escape($state)."'";
$sql.= " WHERE rowid='".$obj['rowid']."'";
$resql = $this->db->query($sql);
} else {
// save
$sql = "INSERT INTO ".MAIN_DB_PREFIX."oauth_state (service, state, entity)";
$sql.= " VALUES ('".$this->db->escape($service)."', '".$this->db->escape($state)."', 1)";
$resql = $this->db->query($sql);
}
/**
* {@inheritDoc}
*/
public function clearAllTokens()
{
// TODO
$this->conf->remove($this->key);
// allow chaining
return $this;
}
// allow chaining
return $this;
}
/**
* {@inheritDoc}
*/
public function hasAuthorizationState($service)
{
// get state from db
dol_syslog("get state from db");
$sql = "SELECT state FROM ".MAIN_DB_PREFIX."oauth_state";
$sql.= " WHERE service='".$this->db->escape($service)."'";
$resql = $this->db->query($sql);
$result = $this->db->fetch_array($resql);
$states[$service] = $result['state'];
$this->states[$service] = $states[$service];
/**
* {@inheritDoc}
*/
public function retrieveAuthorizationState($service)
{
if ($this->hasAuthorizationState($service)) {
return $this->states[$service];
}
return is_array($states)
&& isset($states[$service])
&& null !== $states[$service];
}
dol_syslog('State not found in db, are you sure you stored it?', LOG_WARNING);
throw new AuthorizationStateNotFoundException('State not found in db, are you sure you stored it?');
}
/**
* {@inheritDoc}
*/
public function clearAuthorizationState($service)
{
// TODO
// get previously saved tokens
//$states = $this->conf->get($this->stateKey);
/**
* {@inheritDoc}
*/
public function storeAuthorizationState($service, $state)
{
global $conf;
if (is_array($states) && array_key_exists($service, $states)) {
unset($states[$service]);
// TODO save or update
// Replace the stored tokens array
//$this->conf->set($this->stateKey, $states);
}
dol_syslog("storeAuthorizationState service=".$service);
// allow chaining
return $this;
}
if (!isset($this->states) || !is_array($this->states)) {
$this->states = array();
}
/**
* {@inheritDoc}
*/
public function clearAllAuthorizationStates()
{
// TODO
//$this->conf->remove($this->stateKey);
//$states[$service] = $state;
$this->states[$service] = $state;
// allow chaining
return $this;
}
$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."oauth_state";
$sql .= " WHERE service = '".$this->db->escape($service.($this->keyforprovider?'-'.$this->keyforprovider:''))."'";
$sql .= " AND entity IN (".getEntity('oauth_token').")";
$resql = $this->db->query($sql);
if (! $resql) {
dol_print_error($this->db);
}
$obj = $this->db->fetch_array($resql);
if ($obj) {
// update
$sql = "UPDATE ".MAIN_DB_PREFIX."oauth_state";
$sql.= " SET state = '".$this->db->escape($state)."'";
$sql.= " WHERE rowid = ".((int) $obj['rowid']);
$resql = $this->db->query($sql);
} else {
// save
$sql = "INSERT INTO ".MAIN_DB_PREFIX."oauth_state (service, state, entity)";
$sql.= " VALUES ('".$this->db->escape($service.($this->keyforprovider?'-'.$this->keyforprovider:''))."', '".$this->db->escape($state)."', ".((int) $conf->entity).")";
$resql = $this->db->query($sql);
}
// allow chaining
return $this;
}
/**
* {@inheritDoc}
*/
public function hasAuthorizationState($service)
{
// get state from db
dol_syslog("hasAuthorizationState service=".$service);
$sql = "SELECT state FROM ".MAIN_DB_PREFIX."oauth_state";
$sql .= " WHERE service = '".$this->db->escape($service.($this->keyforprovider?'-'.$this->keyforprovider:''))."'";
$sql .= " AND entity IN (".getEntity('oauth_token').")";
$resql = $this->db->query($sql);
$result = $this->db->fetch_array($resql);
$states = array();
$states[$service] = $result['state'];
$this->states[$service] = $states[$service];
return is_array($states)
&& isset($states[$service])
&& null !== $states[$service];
}
/**
* {@inheritDoc}
*/
public function clearAuthorizationState($service)
{
// TODO
// get previously saved tokens
//$states = $this->conf->get($this->stateKey);
if (is_array($this->states) && array_key_exists($service, $this->states)) {
unset($this->states[$service]);
// Replace the stored tokens array
//$this->conf->set($this->stateKey, $states);
}
// allow chaining
return $this;
}
/**
* {@inheritDoc}
*/
public function clearAllAuthorizationStates()
{
// TODO
//$this->conf->remove($this->stateKey);
// allow chaining
return $this;
}
}

View File

@ -2277,3 +2277,4 @@ INVOICE_ADD_ZATCA_QR_CODEMore=Some Arabic countries need this QR Code on their i
INVOICE_ADD_SWISS_QR_CODE=Show the swiss QR-Bill code on invoices
UrlSocialNetworksDesc=Url link of social network. Use {socialid} for the variable part that contains the social network ID.
IfThisCategoryIsChildOfAnother=If this category is a child of another one
NoName=No name

View File

@ -28,5 +28,8 @@ OAUTH_GITHUB_NAME=OAuth GitHub service
OAUTH_GITHUB_ID=OAuth GitHub Id
OAUTH_GITHUB_SECRET=OAuth GitHub Secret
OAUTH_GITHUB_DESC=Go to <a class="notasortlink" href="https://github.com/settings/developers" target="_blank" rel="noopener noreferrer external">this page</a> then "Register a new application" to create OAuth credentials
OAUTH_URL_FOR_CREDENTIAL=Go to <a class="notasortlink" href="%s" target="_blank" rel="noopener noreferrer external">this page</a><span class="fas fa-external-link-alt paddingleft"></span> to create or get your OAuth ID and Secret
OAUTH_STRIPE_TEST_NAME=OAuth Stripe Test
OAUTH_STRIPE_LIVE_NAME=OAuth Stripe Live
OAUTH_STRIPE_LIVE_NAME=OAuth Stripe Live
OAUTH_ID=OAuth ID
OAUTH_SECRET=OAuth secret

View File

@ -7255,6 +7255,8 @@ span.clipboardCPValue.hidewithsize {
display: inline-block;
color: transparent;
white-space: nowrap;
overflow-x: hidden;
vertical-align: middle;
}
div.clipboardCPValue.hidewithsize {
width: 0 !important;

View File

@ -7024,6 +7024,8 @@ span.clipboardCPValue.hidewithsize {
display: inline-block;
color: transparent;
white-space: nowrap;
overflow-x: hidden;
vertical-align: middle;
}
div.clipboardCPValue.hidewithsize {
width: 0 !important;