Help debug with button "Refresh token"

This commit is contained in:
Laurent Destailleur 2024-10-29 11:48:06 +01:00
parent 6a5540f439
commit 3caead1dc0
4 changed files with 143 additions and 6 deletions

View File

@ -413,7 +413,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
} else {
$keyforprovider = '';
}
$keyforsupportedoauth2array = preg_replace('/-.*$/', '', $keyforsupportedoauth2array);
$keyforsupportedoauth2array = preg_replace('/-.*$/', '', strtoupper($keyforsupportedoauth2array));
$keyforsupportedoauth2array = 'OAUTH_'.$keyforsupportedoauth2array.'_NAME';
if (!empty($supportedoauth2array)) {

View File

@ -30,6 +30,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/oauth.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
use OAuth\Common\Storage\DoliStorage;
use OAuth\Common\Consumer\Credentials;
$supportedoauth2array = getSupportedOauth2Array();
@ -114,6 +115,101 @@ if ($action == 'setvalue' && $user->admin) {
$action = '';
}
// Test a refresh of a token using the refresh token
if ($action == 'refreshtoken' && $user->admin) {
$keyforprovider = GETPOST('keyforprovider');
$OAUTH_SERVICENAME = GETPOST('service');
// Show value of token
$tokenobj = null;
// Load OAUth libraries
require_once DOL_DOCUMENT_ROOT.'/includes/OAuth/bootstrap.php';
$keyforsupportedoauth2array = $OAUTH_SERVICENAME;
if (preg_match('/^.*-/', $keyforsupportedoauth2array)) {
$keyforprovider = preg_replace('/^.*-/', '', $keyforsupportedoauth2array);
} else {
$keyforprovider = '';
}
$keyforsupportedoauth2array = preg_replace('/-.*$/', '', strtoupper($keyforsupportedoauth2array));
$keyforsupportedoauth2array = 'OAUTH_'.$keyforsupportedoauth2array.'_NAME';
$keyforparamtenant = 'OAUTH_'.strtoupper(empty($supportedoauth2array[$keyforsupportedoauth2array]['callbackfile']) ? 'Unknown' : $supportedoauth2array[$keyforsupportedoauth2array]['callbackfile']).($keyforprovider ? '-'.$keyforprovider : '').'_TENANT';
// Dolibarr storage
$storage = new DoliStorage($db, $conf, $keyforprovider, getDolGlobalString($keyforparamtenant));
try {
// $OAUTH_SERVICENAME is for example 'Google-keyforprovider'
print '<!-- '.$OAUTH_SERVICENAME.' -->'."\n";
dol_syslog("oauthlogintokens.php: Read token for service ".$OAUTH_SERVICENAME);
$tokenobj = $storage->retrieveAccessToken($OAUTH_SERVICENAME);
$expire = ($tokenobj->getEndOfLife() !== -9002 && $tokenobj->getEndOfLife() !== -9001 && time() > ($tokenobj->getEndOfLife() - 30));
// We have to save the refresh token in a memory variable because Google give it only once
$refreshtoken = $tokenobj->getRefreshToken();
print '<!-- data stored into field token: '.$storage->token.' - expire '.((string) $expire).' -->';
//print $tokenobj->getExtraParams()['id_token'].'<br>';
//print $tokenobj->getAccessToken().'<br>';
//print $tokenobj->getRefreshToken().'<br>';
//var_dump($expire);
// We do the refresh even if not expired, this is the goal of action.
$oauthname = explode('-', $OAUTH_SERVICENAME);
$keyforoauthservice = strtoupper($oauthname[0]).(empty($oauthname[1]) ? '' : '-'.$oauthname[1]);
$credentials = new Credentials(
getDolGlobalString('OAUTH_'.$keyforoauthservice.'_ID'),
getDolGlobalString('OAUTH_'.$keyforoauthservice.'_SECRET'),
getDolGlobalString('OAUTH_'.$keyforoauthservice.'_URLCALLBACK')
);
$serviceFactory = new \OAuth\ServiceFactory();
$httpClient = new \OAuth\Common\Http\Client\CurlClient();
// TODO Set options for proxy and timeout
// $params=array('CURLXXX'=>value, ...)
//$httpClient->setCurlParameters($params);
$serviceFactory->setHttpClient($httpClient);
$scopes = array();
if (preg_match('/^Microsoft/', $OAUTH_SERVICENAME)) {
//$extraparams = $tokenobj->getExtraParams();
$tmp = explode('-', $OAUTH_SERVICENAME);
$scopes = explode(',', getDolGlobalString('OAUTH_'.strtoupper($tmp[0]).(empty($tmp[1]) ? '' : '-'.$tmp[1]).'_SCOPE'));
}
// ex service is Google-Emails we need only the first part Google
$apiService = $serviceFactory->createService($oauthname[0], $credentials, $storage, $scopes);
if ($apiService instanceof OAuth\OAuth2\Service\AbstractService || $apiService instanceof OAuth\OAuth1\Service\AbstractService) {
// ServiceInterface does not provide refreshAccessToekn, AbstractService does
dol_syslog("oauthlogintokens.php: call refreshAccessToken to get the new access token");
$tokenobj = $apiService->refreshAccessToken($tokenobj); // This call refresh and store the new token (but does not include the refresh token)
dol_syslog("oauthlogintokens.php: call setRefreshToken");
$tokenobj->setRefreshToken($refreshtoken); // Restore the refresh token
dol_syslog("oauthlogintokens.php: call storeAccessToken to save the new access token + the old refresh token");
$storage->storeAccessToken($OAUTH_SERVICENAME, $tokenobj); // This save the new token including the refresh token
if ($expire) {
setEventMessages($langs->trans("OldTokenWasExpiredItHasBeenRefresh"), null, 'mesgs');
} else {
setEventMessages($langs->trans("OldTokenWasNotExpiredButItHasBeenRefresh"), null, 'mesgs');
}
} else {
dol_print_error($db, 'apiService is not a correct OAUTH2 Abstract service');
}
dol_syslog("oauthlogintokens.php: Read token again for service ".$OAUTH_SERVICENAME);
$tokenobj = $storage->retrieveAccessToken($OAUTH_SERVICENAME);
} catch (Exception $e) {
// Return an error if token not found
print $e->getMessage();
}
}
/*
* View
@ -176,7 +272,7 @@ if ($mode == 'setup' && $user->admin) {
$keybeforeprovider = $keyforsupportedoauth2array;
$keyforprovider = '';
}
$keyforsupportedoauth2array = preg_replace('/-.*$/', '', $keyforsupportedoauth2array);
$keyforsupportedoauth2array = preg_replace('/-.*$/', '', strtoupper($keyforsupportedoauth2array));
$keyforsupportedoauth2array = 'OAUTH_'.$keyforsupportedoauth2array.'_NAME';
$nameofservice = ucfirst(strtolower(empty($supportedoauth2array[$keyforsupportedoauth2array]['callbackfile']) ? 'Unknown' : $supportedoauth2array[$keyforsupportedoauth2array]['callbackfile']));
@ -191,6 +287,8 @@ if ($mode == 'setup' && $user->admin) {
}
$state = $shortscope; // TODO USe a better state
$urltorefresh = $_SERVER["PHP_SELF"].'?action=refreshtoken&token='.newToken();
// Define $urltorenew, $urltodelete, $urltocheckperms
if ($keyforsupportedoauth2array == 'OAUTH_GITHUB_NAME') {
// List of keys that will be converted into scopes (from constants 'SCOPE_state_in_uppercase' in file of service).
@ -220,6 +318,9 @@ if ($mode == 'setup' && $user->admin) {
if ($urltorenew) {
$urltorenew .= '&keyforprovider='.urlencode($keyforprovider);
}
if ($urltorefresh) {
$urltorefresh .= '&keyforprovider='.urlencode($keyforprovider).'&service='.urlencode($OAUTH_SERVICENAME);
}
if ($urltodelete) {
$urltodelete .= '&keyforprovider='.urlencode($keyforprovider);
}
@ -234,6 +335,7 @@ if ($mode == 'setup' && $user->admin) {
// $OAUTH_SERVICENAME is for example 'Google-keyforprovider'
print '<!-- '.$OAUTH_SERVICENAME.' -->'."\n";
$tokenobj = $storage->retrieveAccessToken($OAUTH_SERVICENAME);
print '<!-- data stored into field token: '.$storage->token.' -->';
//print $storage->token.'<br>';
//print $tokenobj->getExtraParams()['id_token'].'<br>';
//print $tokenobj->getAccessToken().'<br>';
@ -348,6 +450,11 @@ if ($mode == 'setup' && $user->admin) {
print $form->textwithpicto('', $langs->trans('RequestAccess'));
print '<br>';
}
// Request remote token
if ($urltorefresh && $refreshtoken) {
print '<a class="button smallpaddingimp reposition classfortooltip marginright" href="'.$urltorefresh.'" title="'.dolPrintHTMLForAttribute($langs->trans('RefreshTokenHelp')).'">'.$langs->trans('RefreshToken').'</a>';
}
// Check remote access
if ($urltocheckperms) {
print '<br>'.$langs->trans("ToCheckDeleteTokenOnProvider", $OAUTH_SERVICENAME).': <a href="'.$urltocheckperms.'" target="_'.strtolower($OAUTH_SERVICENAME).'">'.$urltocheckperms.'</a>';

View File

@ -1144,7 +1144,7 @@ class EmailCollector extends CommonObject
} else {
$keyforprovider = '';
}
$keyforsupportedoauth2array = preg_replace('/-.*$/', '', $keyforsupportedoauth2array);
$keyforsupportedoauth2array = preg_replace('/-.*$/', '', strtoupper($keyforsupportedoauth2array));
$keyforsupportedoauth2array = 'OAUTH_'.$keyforsupportedoauth2array.'_NAME';
if (!empty($supportedoauth2array)) {
@ -1185,11 +1185,22 @@ class EmailCollector extends CommonObject
$serviceFactory = new \OAuth\ServiceFactory();
$oauthname = explode('-', $OAUTH_SERVICENAME);
// ex service is Google-Emails we need only the first part Google
$apiService = $serviceFactory->createService($oauthname[0], $credentials, $storage, array());
$scopes = array();
if (preg_match('/^Microsoft/', $OAUTH_SERVICENAME)) {
//$extraparams = $tokenobj->getExtraParams();
$tmp = explode('-', $OAUTH_SERVICENAME);
$scopes = explode(',', getDolGlobalString('OAUTH_'.strtoupper($tmp[0]).(empty($tmp[1]) ? '' : '-'.$tmp[1]).'_SCOPE'));
}
$apiService = $serviceFactory->createService($oauthname[0], $credentials, $storage, $scopes);
'@phan-var-force OAuth\OAuth2\Service\AbstractService|OAuth\OAuth1\Service\AbstractService $apiService'; // createService is only ServiceInterface
// We have to save the token because Google give it only once
$refreshtoken = $tokenobj->getRefreshToken();
$tokenobj = $apiService->refreshAccessToken($tokenobj);
// We have to save the token because answer give it only once
$tokenobj->setRefreshToken($refreshtoken);
$storage->storeAccessToken($OAUTH_SERVICENAME, $tokenobj);
}

View File

@ -218,12 +218,31 @@ abstract class AbstractService extends BaseAbstractService implements ServiceInt
'refresh_token' => $refreshToken,
);
// @CHANGE LDR
//global $conf; $conf->global->OAUTH_ADD_SCOPE_AND_TENANT_IN_REFRESH_MESSAGE = 1;
if (getDolGlobalString('OAUTH_ADD_SCOPE_AND_TENANT_IN_REFRESH_MESSAGE')) {
if (!empty($this->scopes)) {
$parameters['scope'] = implode($this->getScopesDelimiter(), $this->scopes);
}
if ($this->storage->getTenant()) {
$parameters['tenant'] = $this->storage->getTenant();
}
}
//var_dump($parameters);
$responseBody = $this->httpClient->retrieveResponse(
$this->getAccessTokenEndpoint(),
$parameters,
$this->getExtraOAuthHeaders()
);
//print $responseBody;exit; // We must have a result "{"token_type":"Bearer","scope...
// @CHANGE LDR
$data = json_decode((string) $responseBody, true);
if (is_array($data) && !empty($data['error_description'])) {
print 'Oauth2 AbstractService error received: '.$data['error_description'];
}
//print $responseBody;exit; // We must have a result string "{"token_type":"Bearer","error_description":...,"scope...
$token = $this->parseAccessTokenResponse($responseBody);
$this->storage->storeAccessToken($this->service(), $token);