oauthlogintokens.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. <?php
  2. /* Copyright (C) 2013-2016 Laurent Destailleur <eldy@users.sourceforge.net>
  3. * Copyright (C) 2014-2018 Frederic France <frederic.france@netlogic.fr>
  4. * Copyright (C) 2020 Nicolas ZABOURI <info@inovea-conseil.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  18. */
  19. /**
  20. * \file htdocs/admin/oauthlogintokens.php
  21. * \ingroup oauth
  22. * \brief Setup page to configure oauth access to login information
  23. */
  24. // Load Dolibarr environment
  25. require '../main.inc.php';
  26. require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
  27. require_once DOL_DOCUMENT_ROOT.'/core/lib/oauth.lib.php'; // This define $list and $supportedoauth2array
  28. require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
  29. use OAuth\Common\Storage\DoliStorage;
  30. // Load translation files required by the page
  31. $langs->loadLangs(array('admin', 'printing', 'oauth'));
  32. $action = GETPOST('action', 'aZ09');
  33. $mode = GETPOST('mode', 'alpha');
  34. $value = GETPOST('value', 'alpha');
  35. $varname = GETPOST('varname', 'alpha');
  36. $driver = GETPOST('driver', 'alpha');
  37. if (!empty($driver)) {
  38. $langs->load($driver);
  39. }
  40. if (!$mode) {
  41. $mode = 'setup';
  42. }
  43. if (!$user->admin) {
  44. accessforbidden();
  45. }
  46. /*
  47. * Action
  48. */
  49. /*if (($mode == 'test' || $mode == 'setup') && empty($driver))
  50. {
  51. setEventMessages($langs->trans('PleaseSelectaDriverfromList'), null);
  52. header("Location: ".$_SERVER['PHP_SELF'].'?mode=config');
  53. exit;
  54. }*/
  55. if ($action == 'setconst' && $user->admin) {
  56. $error = 0;
  57. $db->begin();
  58. $setupconstarray = GETPOST('setupdriver', 'array');
  59. foreach ($setupconstarray as $setupconst) {
  60. //print '<pre>'.print_r($setupconst, true).'</pre>';
  61. $constname = dol_escape_htmltag($setupconst['varname']);
  62. $constvalue = dol_escape_htmltag($setupconst['value']);
  63. $consttype = dol_escape_htmltag($setupconst['type']);
  64. $constnote = dol_escape_htmltag($setupconst['note']);
  65. $result = dolibarr_set_const($db, $constname, $constvalue, $consttype, 0, $constnote, $conf->entity);
  66. if (!($result > 0)) {
  67. $error++;
  68. }
  69. }
  70. if (!$error) {
  71. $db->commit();
  72. setEventMessages($langs->trans("SetupSaved"), null);
  73. } else {
  74. $db->rollback();
  75. dol_print_error($db);
  76. }
  77. $action = '';
  78. }
  79. if ($action == 'setvalue' && $user->admin) {
  80. $db->begin();
  81. $result = dolibarr_set_const($db, $varname, $value, 'chaine', 0, '', $conf->entity);
  82. if (!($result > 0)) {
  83. $error++;
  84. }
  85. if (!$error) {
  86. $db->commit();
  87. setEventMessages($langs->trans("SetupSaved"), null);
  88. } else {
  89. $db->rollback();
  90. dol_print_error($db);
  91. }
  92. $action = '';
  93. }
  94. /*
  95. * View
  96. */
  97. // Define $urlwithroot
  98. $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
  99. $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
  100. //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
  101. $form = new Form($db);
  102. llxHeader('', $langs->trans("TokenManager"));
  103. $linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
  104. print load_fiche_titre($langs->trans('ConfigOAuth'), $linkback, 'title_setup');
  105. $head = oauthadmin_prepare_head();
  106. print dol_get_fiche_head($head, 'tokengeneration', '', -1, '');
  107. if (GETPOST('error')) {
  108. setEventMessages(GETPOST('error'), null, 'errors');
  109. }
  110. if ($mode == 'setup' && $user->admin) {
  111. print '<span class="opacitymedium">'.$langs->trans("OAuthSetupForLogin")."</span><br><br>\n";
  112. // Define $listinsetup
  113. foreach ($conf->global as $key => $val) {
  114. if (!empty($val) && preg_match('/^OAUTH_.*_ID$/', $key)) {
  115. $provider = preg_replace('/_ID$/', '', $key);
  116. $listinsetup[] = array(
  117. $provider.'_NAME',
  118. $provider.'_ID',
  119. $provider.'_SECRET',
  120. $provider.'_URLAUTHORIZE', // For custom oauth links
  121. $provider.'_SCOPE' // For custom oauth links
  122. );
  123. }
  124. }
  125. $oauthstateanticsrf = bin2hex(random_bytes(128/8));
  126. // $list is defined into oauth.lib.php to the list of supporter OAuth providers.
  127. foreach ($listinsetup as $key) {
  128. $supported = 0;
  129. $keyforsupportedoauth2array = $key[0]; // May be OAUTH_GOOGLE_NAME or OAUTH_GOOGLE_xxx_NAME
  130. $keyforsupportedoauth2array = preg_replace('/^OAUTH_/', '', $keyforsupportedoauth2array);
  131. $keyforsupportedoauth2array = preg_replace('/_NAME$/', '', $keyforsupportedoauth2array);
  132. if (preg_match('/^.*-/', $keyforsupportedoauth2array)) {
  133. $keybeforeprovider = preg_replace('/-.*$/', '', $keyforsupportedoauth2array);
  134. $keyforprovider = preg_replace('/^.*-/', '', $keyforsupportedoauth2array);
  135. } else {
  136. $keybeforeprovider = $keyforsupportedoauth2array;
  137. $keyforprovider = '';
  138. }
  139. $keyforsupportedoauth2array = preg_replace('/-.*$/', '', $keyforsupportedoauth2array);
  140. $keyforsupportedoauth2array = 'OAUTH_'.$keyforsupportedoauth2array.'_NAME';
  141. $OAUTH_SERVICENAME = (empty($supportedoauth2array[$keyforsupportedoauth2array]['name']) ? 'Unknown' : $supportedoauth2array[$keyforsupportedoauth2array]['name'].($keyforprovider ? '-'.$keyforprovider : ''));
  142. $shortscope = '';
  143. if (getDolGlobalString($key[4])) {
  144. $shortscope = getDolGlobalString($key[4]);
  145. }
  146. $state = $shortscope; // TODO USe a better state
  147. // Define $urltorenew, $urltodelete, $urltocheckperms
  148. if ($keyforsupportedoauth2array == 'OAUTH_GITHUB_NAME') {
  149. // List of keys that will be converted into scopes (from constants 'SCOPE_state_in_uppercase' in file of service).
  150. // We pass this param list in to 'state' because we need it before and after the redirect.
  151. // Note: github does not accept csrf key inside the state parameter (only known values)
  152. $urltorenew = $urlwithroot.'/core/modules/oauth/github_oauthcallback.php?shortscope='.urlencode($shortscope).'&state='.urlencode($shortscope).'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
  153. $urltodelete = $urlwithroot.'/core/modules/oauth/github_oauthcallback.php?action=delete&token='.newToken().'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
  154. $urltocheckperms = 'https://github.com/settings/applications/';
  155. } elseif ($keyforsupportedoauth2array == 'OAUTH_GOOGLE_NAME') {
  156. // List of keys that will be converted into scopes (from constants 'SCOPE_state_in_uppercase' in file of service).
  157. // List of scopes for Google are here: https://developers.google.com/identity/protocols/oauth2/scopes
  158. // We pass this key list into the param 'state' because we need it before and after the redirect.
  159. $urltorenew = $urlwithroot.'/core/modules/oauth/google_oauthcallback.php?shortscope='.urlencode($shortscope).'&state='.urlencode($state).'-'.$oauthstateanticsrf.'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
  160. $urltodelete = $urlwithroot.'/core/modules/oauth/google_oauthcallback.php?action=delete&token='.newToken().'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
  161. $urltocheckperms = 'https://security.google.com/settings/security/permissions';
  162. } elseif (!empty($supportedoauth2array[$keyforsupportedoauth2array]['returnurl'])) {
  163. $urltorenew = $urlwithroot.$supportedoauth2array[$keyforsupportedoauth2array]['returnurl'].'?shortscope='.urlencode($shortscope).'&state='.urlencode($state).'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
  164. $urltodelete = $urlwithroot.$supportedoauth2array[$keyforsupportedoauth2array]['returnurl'].'?action=delete&token='.newToken().'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
  165. $urltocheckperms = '';
  166. } else {
  167. $urltorenew = '';
  168. $urltodelete = '';
  169. $urltocheckperms = '';
  170. }
  171. if ($urltorenew) {
  172. $urltorenew .= '&keyforprovider='.urlencode($keyforprovider);
  173. }
  174. if ($urltodelete) {
  175. $urltodelete .= '&keyforprovider='.urlencode($keyforprovider);
  176. }
  177. // Show value of token
  178. $tokenobj = null;
  179. // Token
  180. require_once DOL_DOCUMENT_ROOT.'/includes/OAuth/bootstrap.php';
  181. // Dolibarr storage
  182. $storage = new DoliStorage($db, $conf, $keyforprovider);
  183. try {
  184. // $OAUTH_SERVICENAME is for example 'Google-keyforprovider'
  185. print '<!-- '.$OAUTH_SERVICENAME.' -->'."\n";
  186. $tokenobj = $storage->retrieveAccessToken($OAUTH_SERVICENAME);
  187. //print $storage->token.'<br>';
  188. //print $tokenobj->getExtraParams()['id_token'].'<br>';
  189. //print $tokenobj->getAccessToken().'<br>';
  190. } catch (Exception $e) {
  191. // Return an error if token not found
  192. //print $e->getMessage();
  193. }
  194. // Set other properties
  195. $refreshtoken = false;
  196. $expiredat = '';
  197. $expire = false;
  198. // Is token expired or will token expire in the next 30 seconds
  199. if (is_object($tokenobj)) {
  200. $expire = ($tokenobj->getEndOfLife() !== $tokenobj::EOL_NEVER_EXPIRES && $tokenobj->getEndOfLife() !== $tokenobj::EOL_UNKNOWN && time() > ($tokenobj->getEndOfLife() - 30));
  201. }
  202. if ($key[1] != '' && $key[2] != '') {
  203. if (is_object($tokenobj)) {
  204. $refreshtoken = $tokenobj->getRefreshToken();
  205. $endoflife = $tokenobj->getEndOfLife();
  206. if ($endoflife == $tokenobj::EOL_NEVER_EXPIRES) {
  207. $expiredat = $langs->trans("Never");
  208. } elseif ($endoflife == $tokenobj::EOL_UNKNOWN) {
  209. $expiredat = $langs->trans("Unknown");
  210. } else {
  211. $expiredat = dol_print_date($endoflife, "dayhour", 'tzuserrel');
  212. }
  213. }
  214. }
  215. $submit_enabled = 0;
  216. print '<form method="post" action="'.$_SERVER["PHP_SELF"].'?mode=setup&amp;driver='.$driver.'" autocomplete="off">';
  217. print '<input type="hidden" name="token" value="'.newToken().'">';
  218. print '<input type="hidden" name="action" value="setconst">';
  219. print '<div class="div-table-responsive-no-min">';
  220. print '<table class="noborder centpercent">'."\n";
  221. // Api Name
  222. $label = $langs->trans($keyforsupportedoauth2array);
  223. print '<tr class="liste_titre">';
  224. print '<th class="titlefieldcreate">';
  225. print img_picto('', $supportedoauth2array[$keyforsupportedoauth2array]['picto'], 'class="pictofixedwidth"');
  226. if ($label == $keyforsupportedoauth2array) {
  227. print $supportedoauth2array[$keyforsupportedoauth2array]['name'];
  228. } else {
  229. print $label;
  230. }
  231. if ($keyforprovider) {
  232. print ' (<b>'.$keyforprovider.'</b>)';
  233. } else {
  234. print ' (<b>'.$langs->trans("NoName").'</b>)';
  235. }
  236. print '</th>';
  237. print '<th></th>';
  238. print '<th></th>';
  239. print "</tr>\n";
  240. print '<tr class="oddeven">';
  241. print '<td'.(empty($key['required']) ? '' : ' class="required"').'>';
  242. //var_dump($key);
  243. print $langs->trans("OAuthIDSecret").'</td>';
  244. print '<td>';
  245. print '<span class="opacitymedium">'.$langs->trans("SeePreviousTab").'</span>';
  246. print '</td>';
  247. print '<td>';
  248. print '</td>';
  249. print '</tr>'."\n";
  250. // Scopes
  251. print '<tr class="oddeven">';
  252. print '<td>'.$langs->trans("Scopes").'</td>';
  253. print '<td colspan="2">';
  254. $currentscopes = getDolGlobalString($key[4]);
  255. print $currentscopes;
  256. print '</td></tr>';
  257. print '<tr class="oddeven">';
  258. print '<td'.(empty($key['required']) ? '' : ' class="required"').'>';
  259. //var_dump($key);
  260. print $langs->trans("IsTokenGenerated");
  261. print '</td>';
  262. print '<td>';
  263. if (is_object($tokenobj)) {
  264. print $form->textwithpicto(yn(1), $langs->trans("HasAccessToken").' : '.dol_print_date($storage->date_modification, 'dayhour').' state='.dol_escape_htmltag($storage->state));
  265. } else {
  266. print '<span class="opacitymedium">'.$langs->trans("NoAccessToken").'</span>';
  267. }
  268. print '</td>';
  269. print '<td width="50%">';
  270. // Links to delete/checks token
  271. if (is_object($tokenobj)) {
  272. //test on $storage->hasAccessToken($OAUTH_SERVICENAME) ?
  273. if ($urltodelete) {
  274. print '<a class="button smallpaddingimp" href="'.$urltodelete.'">'.$langs->trans('DeleteAccess').'</a><br>';
  275. } else {
  276. print '<span class="opacitymedium">'.$langs->trans('GoOnTokenProviderToDeleteToken').'</span><br>';
  277. }
  278. }
  279. // Request remote token
  280. if ($urltorenew) {
  281. print '<a class="button smallpaddingimp" href="'.$urltorenew.'">'.$langs->trans('GetAccess').'</a>';
  282. print $form->textwithpicto('', $langs->trans('RequestAccess'));
  283. print '<br>';
  284. }
  285. // Check remote access
  286. if ($urltocheckperms) {
  287. print '<br>'.$langs->trans("ToCheckDeleteTokenOnProvider", $OAUTH_SERVICENAME).': <a href="'.$urltocheckperms.'" target="_'.strtolower($OAUTH_SERVICENAME).'">'.$urltocheckperms.'</a>';
  288. }
  289. print '</td>';
  290. print '</tr>';
  291. print '<tr class="oddeven">';
  292. print '<td'.(empty($key['required']) ? '' : ' class="required"').'>';
  293. //var_dump($key);
  294. print $langs->trans("Token").'</td>';
  295. print '<td colspan="2">';
  296. if (is_object($tokenobj)) {
  297. $tokentoshow = $tokenobj->getAccessToken();
  298. print '<span class="" title="'.dol_escape_htmltag($tokentoshow).'">'.showValueWithClipboardCPButton($tokentoshow, 1, dol_trunc($tokentoshow, 32)).'</span><br>';
  299. //print 'Refresh: '.$tokenobj->getRefreshToken().'<br>';
  300. //print 'EndOfLife: '.$tokenobj->getEndOfLife().'<br>';
  301. //var_dump($tokenobj->getExtraParams());
  302. /*print '<br>Extra: <br><textarea class="quatrevingtpercent">';
  303. print ''.join(',',$tokenobj->getExtraParams());
  304. print '</textarea>';*/
  305. }
  306. print '</td>';
  307. print '</tr>'."\n";
  308. if (is_object($tokenobj)) {
  309. // Token refresh
  310. print '<tr class="oddeven">';
  311. print '<td'.($key['required'] ? ' class="required"' : '').'>';
  312. //var_dump($key);
  313. print $langs->trans("TOKEN_REFRESH");
  314. print '</td>';
  315. print '<td colspan="2">';
  316. print '<span class="" title="'.dol_escape_htmltag($refreshtoken).'">'.showValueWithClipboardCPButton($refreshtoken, 1, dol_trunc($refreshtoken, 32)).'</span>';
  317. print '</td>';
  318. print '</tr>';
  319. // Token expired
  320. print '<tr class="oddeven">';
  321. print '<td'.(empty($key['required']) ? '' : ' class="required"').'>';
  322. //var_dump($key);
  323. print $langs->trans("TOKEN_EXPIRED");
  324. print '</td>';
  325. print '<td colspan="2">';
  326. print yn($expire);
  327. print '</td>';
  328. print '</tr>';
  329. // Token expired at
  330. print '<tr class="oddeven">';
  331. print '<td'.(empty($key['required']) ? '' : ' class="required"').'>';
  332. //var_dump($key);
  333. print $langs->trans("TOKEN_EXPIRE_AT");
  334. print '</td>';
  335. print '<td colspan="2">';
  336. print $expiredat;
  337. print '</td>';
  338. print '</tr>';
  339. }
  340. print '</table>';
  341. print '</div>';
  342. if (!empty($driver)) {
  343. if ($submit_enabled) {
  344. print $form->buttonsSaveCancel("Modify", '');
  345. }
  346. }
  347. print '</form>';
  348. print '<br>';
  349. }
  350. }
  351. if ($mode == 'test' && $user->admin) {
  352. print $langs->trans('PrintTestDesc'.$driver)."<br><br>\n";
  353. print '<div class="div-table-responsive-no-min">';
  354. print '<table class="noborder centpercent">';
  355. if (!empty($driver)) {
  356. require_once DOL_DOCUMENT_ROOT.'/core/modules/printing/'.$driver.'.modules.php';
  357. $classname = 'printing_'.$driver;
  358. $langs->load($driver);
  359. $printer = new $classname($db);
  360. //print '<pre>'.print_r($printer, true).'</pre>';
  361. if (count($printer->getlistAvailablePrinters())) {
  362. if ($printer->listAvailablePrinters() == 0) {
  363. print $printer->resprint;
  364. } else {
  365. setEventMessages($printer->error, $printer->errors, 'errors');
  366. }
  367. } else {
  368. print $langs->trans('PleaseConfigureDriverfromList');
  369. }
  370. }
  371. print '</table>';
  372. print '</div>';
  373. }
  374. if ($mode == 'userconf' && $user->admin) {
  375. print $langs->trans('PrintUserConfDesc'.$driver)."<br><br>\n";
  376. print '<div class="div-table-responsive">';
  377. print '<table class="noborder centpercent">';
  378. print '<tr class="liste_titre">';
  379. print '<th>'.$langs->trans("User").'</th>';
  380. print '<th>'.$langs->trans("PrintModule").'</th>';
  381. print '<th>'.$langs->trans("PrintDriver").'</th>';
  382. print '<th>'.$langs->trans("Printer").'</th>';
  383. print '<th>'.$langs->trans("PrinterLocation").'</th>';
  384. print '<th>'.$langs->trans("PrinterId").'</th>';
  385. print '<th>'.$langs->trans("NumberOfCopy").'</th>';
  386. print '<th class="center">'.$langs->trans("Delete").'</th>';
  387. print "</tr>\n";
  388. $sql = "SELECT p.rowid, p.printer_name, p.printer_location, p.printer_id, p.copy, p.module, p.driver, p.userid, u.login";
  389. $sql .= " FROM ".MAIN_DB_PREFIX."printing as p, ".MAIN_DB_PREFIX."user as u WHERE p.userid = u.rowid";
  390. $resql = $db->query($sql);
  391. while ($obj = $db->fetch_object($resql)) {
  392. print '<tr class="oddeven">';
  393. print '<td>'.$obj->login.'</td>';
  394. print '<td>'.$obj->module.'</td>';
  395. print '<td>'.$obj->driver.'</td>';
  396. print '<td>'.$obj->printer_name.'</td>';
  397. print '<td>'.$obj->printer_location.'</td>';
  398. print '<td>'.$obj->printer_id.'</td>';
  399. print '<td>'.$obj->copy.'</td>';
  400. print '<td class="center">'.img_picto($langs->trans("Delete"), 'delete').'</td>';
  401. print "</tr>\n";
  402. }
  403. print '</table>';
  404. print '</div>';
  405. }
  406. print dol_get_fiche_end();
  407. // End of page
  408. llxFooter();
  409. $db->close();