oauth.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. <?php
  2. /* Copyright (C) 2015-2018 Frederic France <frederic.france@netlogic.fr>
  3. * Copyright (C) 2016 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
  4. * Copyright (C) 2022 Laurent Destailleur <eldy@users.sourceforge.net>
  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/oauth.php
  21. * \ingroup oauth
  22. * \brief Setup page to configure oauth access api
  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. // $supportedoauth2array is defined into oauth.lib.php
  29. // Define $urlwithroot
  30. $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
  31. $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
  32. //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
  33. // Load translation files required by the page
  34. $langs->loadLangs(array('admin', 'oauth', 'modulebuilder'));
  35. // Security check
  36. if (!$user->admin) {
  37. accessforbidden();
  38. }
  39. $action = GETPOST('action', 'aZ09');
  40. $provider = GETPOST('provider', 'aZ09');
  41. $label = GETPOST('label', 'aZ09');
  42. $error = 0;
  43. /*
  44. * Actions
  45. */
  46. if ($action == 'add') { // $provider is OAUTH_XXX
  47. if ($provider && $provider != '-1') {
  48. $constname = strtoupper($provider).($label ? '-'.$label : '').'_ID';
  49. if (getDolGlobalString($constname)) {
  50. setEventMessages($langs->trans("AOAuthEntryForThisProviderAndLabelAlreadyHasAKey"), null, 'errors');
  51. $error++;
  52. } else {
  53. dolibarr_set_const($db, $constname, $langs->trans('ToComplete'), 'chaine', 0, '', $conf->entity);
  54. setEventMessages($langs->trans("OAuthProviderAdded"), null);
  55. }
  56. }
  57. }
  58. if ($action == 'update') {
  59. foreach ($conf->global as $key => $val) {
  60. if (!empty($val) && preg_match('/^OAUTH_.+_ID$/', $key)) {
  61. $constvalue = str_replace('_ID', '', $key);
  62. if (!dolibarr_set_const($db, $constvalue.'_ID', GETPOST($constvalue.'_ID'), 'chaine', 0, '', $conf->entity)) {
  63. $error++;
  64. }
  65. // If we reset this provider, we also remove the secret
  66. if (!dolibarr_set_const($db, $constvalue.'_SECRET', GETPOST($constvalue.'_ID') ? GETPOST($constvalue.'_SECRET') : '', 'chaine', 0, '', $conf->entity)) {
  67. $error++;
  68. }
  69. if (GETPOSTISSET($constvalue.'_URLAUTHORIZE')) {
  70. if (!dolibarr_set_const($db, $constvalue.'_URLAUTHORIZE', GETPOST($constvalue.'_URLAUTHORIZE'), 'chaine', 0, '', $conf->entity)) {
  71. $error++;
  72. }
  73. }
  74. if (GETPOSTISSET($constvalue.'_TENANT')) {
  75. if (!dolibarr_set_const($db, $constvalue.'_TENANT', GETPOST($constvalue.'_TENANT'), 'chaine', 0, '', $conf->entity)) {
  76. $error++;
  77. }
  78. }
  79. if (GETPOSTISSET($constvalue.'_SCOPE')) {
  80. if (is_array(GETPOST($constvalue.'_SCOPE'))) {
  81. $scopestring = implode(',', GETPOST($constvalue.'_SCOPE'));
  82. } else {
  83. $scopestring = GETPOST($constvalue.'_SCOPE');
  84. }
  85. if (!dolibarr_set_const($db, $constvalue.'_SCOPE', $scopestring, 'chaine', 0, '', $conf->entity)) {
  86. $error++;
  87. }
  88. } else {
  89. if (!dolibarr_set_const($db, $constvalue.'_SCOPE', '', 'chaine', 0, '', $conf->entity)) {
  90. $error++;
  91. }
  92. }
  93. }
  94. }
  95. if (!$error) {
  96. setEventMessages($langs->trans("SetupSaved"), null);
  97. } else {
  98. setEventMessages($langs->trans("Error"), null, 'errors');
  99. }
  100. }
  101. if ($action == 'confirm_delete') {
  102. $provider = GETPOST('provider', 'aZ09');
  103. $label = GETPOST('label');
  104. $globalkey = empty($provider) ? $label : $label.'-'.$provider;
  105. if (getDolGlobalString($globalkey.'_ID') && getDolGlobalString($globalkey.'_SECRET')) { // If ID and secret exist, we delete first the token
  106. $backtourl = DOL_URL_ROOT.'/admin/oauth.php?action=delete_entry&provider='.$provider.'&label='.$label.'&token='.newToken();
  107. $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
  108. $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT;
  109. $callbacktodel = $urlwithroot;
  110. if ($label == 'OAUTH_GOOGLE') {
  111. $callbacktodel .= '/core/modules/oauth/google_oauthcallback.php?action=delete&keyforprovider='.$provider.'&token='.newToken().'&backtourl='.urlencode($backtourl);
  112. } elseif ($label == 'OAUTH_GITHUB') {
  113. $callbacktodel .= '/core/modules/oauth/github_oauthcallback.php?action=delete&keyforprovider='.$provider.'&token='.newToken().'&backtourl='.urlencode($backtourl);
  114. } elseif ($label == 'OAUTH_STRIPE_LIVE') {
  115. $callbacktodel .= '/core/modules/oauth/stripelive_oauthcallback.php?action=delete&keyforprovider='.$provider.'&token='.newToken().'&backtourl='.urlencode($backtourl);
  116. } elseif ($label == 'OAUTH_STRIPE_TEST') {
  117. $callbacktodel .= '/core/modules/oauth/stripetest_oauthcallback.php?action=delete&keyforprovider='.$provider.'&token='.newToken().'&backtourl='.urlencode($backtourl);
  118. } elseif ($label == 'OAUTH_MICROSOFT') {
  119. $callbacktodel .= '/core/modules/oauth/microsoft_oauthcallback.php?action=delete&keyforprovider='.$provider.'&token='.newToken().'&backtourl='.urlencode($backtourl);
  120. } elseif ($label == 'OAUTH_OTHER') {
  121. $callbacktodel .= '/core/modules/oauth/generic_oauthcallback.php?action=delete&keyforprovider='.$provider.'&token='.newToken().'&backtourl='.urlencode($backtourl);
  122. }
  123. header("Location: ".$callbacktodel);
  124. exit;
  125. } else {
  126. $action = 'delete_entry';
  127. }
  128. }
  129. if ($action == 'delete_entry') {
  130. $provider = GETPOST('provider', 'aZ09');
  131. $label = GETPOST('label');
  132. $globalkey = empty($provider) ? $label : $label.'-'.$provider;
  133. if (!dolibarr_del_const($db, $globalkey.'_NAME', $conf->entity) || !dolibarr_del_const($db, $globalkey.'_ID', $conf->entity) || !dolibarr_del_const($db, $globalkey.'_SECRET', $conf->entity) || !dolibarr_del_const($db, $globalkey.'_URLAUTHORIZE', $conf->entity) || !dolibarr_del_const($db, $globalkey.'_SCOPE', $conf->entity)) {
  134. setEventMessages($langs->trans("ErrorInEntryDeletion"), null, 'errors');
  135. $error++;
  136. } else {
  137. setEventMessages($langs->trans("EntryDeleted"), null);
  138. }
  139. }
  140. /*
  141. * View
  142. */
  143. llxHeader();
  144. $form = new Form($db);
  145. // Confirmation of action process
  146. if ($action == 'delete') {
  147. $formquestion = array();
  148. $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?provider='.GETPOST('provider').'&label='.GETPOST('label'), $langs->trans('OAuthServiceConfirmDeleteTitle'), $langs->trans('OAuthServiceConfirmDeleteMessage'), 'confirm_delete', $formquestion, 0, 1, 220);
  149. print $formconfirm;
  150. }
  151. $linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
  152. print load_fiche_titre($langs->trans('ConfigOAuth'), $linkback, 'title_setup');
  153. print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
  154. print '<input type="hidden" name="token" value="'.newToken().'">';
  155. print '<input type="hidden" name="action" value="add">';
  156. $head = oauthadmin_prepare_head();
  157. print dol_get_fiche_head($head, 'services', '', -1, '');
  158. print '<span class="opacitymedium">'.$langs->trans("ListOfSupportedOauthProviders").'</span><br><br>';
  159. print '<select name="provider" id="provider" class="minwidth150">';
  160. print '<option name="-1" value="-1">'.$langs->trans("OAuthProvider").'</option>';
  161. foreach ($list as $key) {
  162. $supported = 0;
  163. $keyforsupportedoauth2array = $key[0];
  164. if (in_array($keyforsupportedoauth2array, array_keys($supportedoauth2array))) {
  165. $supported = 1;
  166. }
  167. if (!$supported) {
  168. continue; // show only supported
  169. }
  170. $i++;
  171. print '<option name="'.$keyforsupportedoauth2array.'" value="'.str_replace('_NAME', '', $keyforsupportedoauth2array).'">'.$supportedoauth2array[$keyforsupportedoauth2array]['name'].'</option>'."\n";
  172. }
  173. print '</select>';
  174. print ajax_combobox('provider');
  175. print ' <input type="text" name="label" value="" placeholder="'.$langs->trans("Label").'" pattern="^\S+$" title="'.$langs->trans("SpaceOrSpecialCharAreNotAllowed").'">';
  176. print ' <input type="submit" class="button small" name="add" value="'.$langs->trans("Add").'">';
  177. print '<br>';
  178. print '<br>';
  179. print dol_get_fiche_end();
  180. print '</form>';
  181. $listinsetup = [];
  182. // Define $listinsetup
  183. foreach ($conf->global as $key => $val) {
  184. if (!empty($val) && preg_match('/^OAUTH_.*_ID$/', $key)) {
  185. $provider = preg_replace('/_ID$/', '', $key);
  186. $listinsetup[] = array(
  187. $provider.'_NAME',
  188. $provider.'_ID',
  189. $provider.'_SECRET',
  190. $provider.'_URLAUTHORIZE', // For custom oauth links
  191. $provider.'_SCOPE' // For custom oauth links
  192. );
  193. }
  194. }
  195. if (count($listinsetup) > 0) {
  196. print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
  197. print '<input type="hidden" name="token" value="'.newToken().'">';
  198. print '<input type="hidden" name="action" value="update">';
  199. print '<div class="div-table-responsive-no-min">';
  200. $i = 0;
  201. // $list is defined into oauth.lib.php to the list of supporter OAuth providers.
  202. foreach ($listinsetup as $key) {
  203. $supported = 0;
  204. $keyforsupportedoauth2array = $key[0]; // May be OAUTH_GOOGLE_NAME or OAUTH_GOOGLE_xxx_NAME
  205. $keyforsupportedoauth2array = preg_replace('/^OAUTH_/', '', $keyforsupportedoauth2array);
  206. $keyforsupportedoauth2array = preg_replace('/_NAME$/', '', $keyforsupportedoauth2array);
  207. if (preg_match('/^.*-/', $keyforsupportedoauth2array)) {
  208. $keybeforeprovider = preg_replace('/-.*$/', '', $keyforsupportedoauth2array);
  209. $keyforprovider = preg_replace('/^.*-/', '', $keyforsupportedoauth2array);
  210. } else {
  211. $keybeforeprovider = $keyforsupportedoauth2array;
  212. $keyforprovider = '';
  213. }
  214. $keyforsupportedoauth2array = preg_replace('/-.*$/', '', $keyforsupportedoauth2array);
  215. $keyforsupportedoauth2array = 'OAUTH_'.$keyforsupportedoauth2array.'_NAME';
  216. if (in_array($keyforsupportedoauth2array, array_keys($supportedoauth2array))) {
  217. $supported = 1;
  218. }
  219. if (!$supported) {
  220. continue; // show only supported
  221. }
  222. $i++;
  223. print '<table class="noborder centpercent">';
  224. // OAUTH service name
  225. $label = $langs->trans($keyforsupportedoauth2array);
  226. print '<tr class="liste_titre'.($i > 1 ? ' liste_titre_add' : '').'">';
  227. print '<td class="titlefieldcreate">';
  228. print img_picto('', $supportedoauth2array[$keyforsupportedoauth2array]['picto'], 'class="pictofixedwidth"');
  229. if ($label == $keyforsupportedoauth2array) {
  230. print $supportedoauth2array[$keyforsupportedoauth2array]['name'];
  231. } else {
  232. print $label;
  233. }
  234. if ($keyforprovider) {
  235. print ' (<b>'.$keyforprovider.'</b>)';
  236. } else {
  237. print ' (<b>'.$langs->trans("NoName").'</b>)';
  238. }
  239. print '</td>';
  240. print '<td>';
  241. if (!empty($supportedoauth2array[$keyforsupportedoauth2array]['urlforcredentials'])) {
  242. print $langs->trans("OAUTH_URL_FOR_CREDENTIAL", $supportedoauth2array[$keyforsupportedoauth2array]['urlforcredentials']);
  243. }
  244. print '</td>';
  245. // Delete
  246. print '<td>';
  247. $label = preg_replace('/_NAME$/', '', $keyforsupportedoauth2array);
  248. print '<a href="'.$_SERVER["PHP_SELF"].'?action=delete&token='.newToken().'&provider='.urlencode($keyforprovider).'&label='.urlencode($label).'">';
  249. print img_picto('', 'delete');
  250. print '</a>';
  251. print '</form>';
  252. print '</td>';
  253. print '</tr>';
  254. if ($supported) {
  255. $redirect_uri = $urlwithroot.'/core/modules/oauth/'.$supportedoauth2array[$keyforsupportedoauth2array]['callbackfile'].'_oauthcallback.php';
  256. print '<tr class="oddeven value">';
  257. print '<td>'.$langs->trans("UseTheFollowingUrlAsRedirectURI").'</td>';
  258. print '<td><input style="width: 80%" type="text" name="uri'.$keyforsupportedoauth2array.'" id="uri'.$keyforsupportedoauth2array.$keyforprovider.'" value="'.$redirect_uri.'" disabled>';
  259. print ajax_autoselect('uri'.$keyforsupportedoauth2array.$keyforprovider);
  260. print '</td>';
  261. print '<td></td>';
  262. print '</tr>';
  263. if ($keyforsupportedoauth2array == 'OAUTH_OTHER_NAME') {
  264. print '<tr class="oddeven value">';
  265. print '<td>'.$langs->trans("URLOfServiceForAuthorization").'</td>';
  266. print '<td><input style="width: 80%" type="text" name="'.$key[3].'" value="'.getDolGlobalString($key[3]).'" >';
  267. print '</td>';
  268. print '<td></td>';
  269. print '</tr>';
  270. }
  271. } else {
  272. print '<tr class="oddeven value">';
  273. print '<td>'.$langs->trans("UseTheFollowingUrlAsRedirectURI").'</td>';
  274. print '<td>'.$langs->trans("FeatureNotYetSupported").'</td>';
  275. print '</td>';
  276. print '<td></td>';
  277. print '</tr>';
  278. }
  279. // Api Id
  280. print '<tr class="oddeven value">';
  281. print '<td><label for="'.$key[1].'">'.$langs->trans("OAUTH_ID").'</label></td>';
  282. print '<td><input type="text" size="100" id="'.$key[1].'" name="'.$key[1].'" value="'.getDolGlobalString($key[1]).'">';
  283. print '</td>';
  284. print '<td></td>';
  285. print '</tr>';
  286. // Api Secret
  287. print '<tr class="oddeven value">';
  288. print '<td><label for="'.$key[2].'">'.$langs->trans("OAUTH_SECRET").'</label></td>';
  289. print '<td><input type="password" size="100" id="'.$key[2].'" name="'.$key[2].'" value="'.getDolGlobalString($key[2]).'">';
  290. print '</td>';
  291. print '<td></td>';
  292. print '</tr>';
  293. // Tenant
  294. if ($keybeforeprovider == 'MICROSOFT') {
  295. print '<tr class="oddeven value">';
  296. print '<td><label for="'.$key[2].'">'.$langs->trans("OAUTH_TENANT").'</label></td>';
  297. print '<td><input type="text" size="100" id="OAUTH_'.$keybeforeprovider.($keyforprovider ? '-'.$keyforprovider : '').'_TENANT" name="OAUTH_'.$keybeforeprovider.($keyforprovider ? '-'.$keyforprovider : '').'_TENANT" value="'.getDolGlobalString('OAUTH_'.$keybeforeprovider.($keyforprovider ? '-'.$keyforprovider : '').'_TENANT').'">';
  298. print '</td>';
  299. print '<td></td>';
  300. print '</tr>';
  301. }
  302. // TODO Move this into token generation ?
  303. if ($supported) {
  304. if ($keyforsupportedoauth2array == 'OAUTH_OTHER_NAME') {
  305. print '<tr class="oddeven value">';
  306. print '<td>'.$langs->trans("Scopes").'</td>';
  307. print '<td>';
  308. print '<input style="width: 80%" type"text" name="'.$key[4].'" value="'.getDolGlobalString($key[4]).'" >';
  309. print '</td>';
  310. print '<td></td>';
  311. print '</tr>';
  312. } else {
  313. $availablescopes = array_flip(explode(',', $supportedoauth2array[$keyforsupportedoauth2array]['availablescopes']));
  314. $currentscopes = explode(',', getDolGlobalString($key[4]));
  315. $scopestodispay = array();
  316. foreach ($availablescopes as $keyscope => $valscope) {
  317. if (in_array($keyscope, $currentscopes)) {
  318. $scopestodispay[$keyscope] = 1;
  319. } else {
  320. $scopestodispay[$keyscope] = 0;
  321. }
  322. }
  323. // Api Scope
  324. print '<tr class="oddeven value">';
  325. print '<td>'.$langs->trans("Scopes").'</td>';
  326. print '<td>';
  327. foreach ($scopestodispay as $scope => $val) {
  328. print '<input type="checkbox" id="'.$keyforprovider.$scope.'" name="'.$key[4].'[]" value="'.$scope.'"'.($val ? ' checked' : '').'>';
  329. print '<label style="margin-right: 10px" for="'.$keyforprovider.$scope.'">'.$scope.'</label>';
  330. }
  331. print '</td>';
  332. print '<td></td>';
  333. print '</tr>';
  334. }
  335. } else {
  336. print '<tr class="oddeven value">';
  337. print '<td>'.$langs->trans("UseTheFollowingUrlAsRedirectURI").'</td>';
  338. print '<td>'.$langs->trans("FeatureNotYetSupported").'</td>';
  339. print '</td>';
  340. print '<td></td>';
  341. print '</tr>';
  342. }
  343. print '</table>'."\n";
  344. print '<br>';
  345. }
  346. print '</div>';
  347. print $form->buttonsSaveCancel("Save", '');
  348. print '</form>';
  349. }
  350. // End of page
  351. llxFooter();
  352. $db->close();