oauthlogintokens.php 17 KB

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