hook.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. <?php
  2. /**
  3. * ---------------------------------------------------------------------
  4. * SingleSignOn is a plugin which allows to use SSO for auth
  5. * ---------------------------------------------------------------------
  6. * Copyright (C) 2022 Edgard
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. * ---------------------------------------------------------------------
  21. * @copyright Copyright © 2021 - 2022 Edgard
  22. * @license http://www.gnu.org/licenses/gpl.txt GPLv3+
  23. * @link https://github.com/edgardmessias/glpi-singlesignon/
  24. * ---------------------------------------------------------------------
  25. */
  26. function plugin_singlesignon_display_login() {
  27. global $CFG_GLPI;
  28. $signon_provider = new PluginSinglesignonProvider();
  29. $condition = '`is_active` = 1';
  30. if (version_compare(GLPI_VERSION, '9.4', '>=')) {
  31. $condition = [$condition];
  32. }
  33. $rows = $signon_provider->find($condition);
  34. $html = [];
  35. foreach ($rows as $row) {
  36. $query = [];
  37. if (isset($_REQUEST['redirect'])) {
  38. $query['redirect'] = $_REQUEST['redirect'];
  39. }
  40. $url = PluginSinglesignonToolbox::getCallbackUrl($row['id'], $query);
  41. $isDefault = PluginSinglesignonToolbox::isDefault($row);
  42. if ($isDefault && !isset($_GET["noAUTO"])) {
  43. Html::redirect($url);
  44. return;
  45. }
  46. $html[] = PluginSinglesignonToolbox::renderButton($url, $row);
  47. }
  48. if (!empty($html)) {
  49. echo '<div class="singlesignon-box">';
  50. echo implode(" \n", $html);
  51. echo PluginSinglesignonToolbox::renderButton('#', ['name' => __('GLPI')], 'vsubmit old-login');
  52. echo '</div>';
  53. ?>
  54. <style>
  55. #display-login .singlesignon-box span {
  56. display: inline-block;
  57. margin: 5px;
  58. }
  59. #display-login .singlesignon-box .old-login {
  60. display: none;
  61. }
  62. #boxlogin .singlesignon-box span {
  63. display: block;
  64. }
  65. #boxlogin .singlesignon-box .vsubmit {
  66. display: flex;
  67. justify-content: center;
  68. align-items: center;
  69. font-size: 1.3em !important;
  70. text-align: center;
  71. box-sizing: border-box;
  72. }
  73. #boxlogin .singlesignon-box .vsubmit img {
  74. vertical-align: sub;
  75. }
  76. </style>
  77. <script type="text/javascript">
  78. $(document).ready(function() {
  79. // On click, open a popup
  80. $(document).on("click", ".singlesignon.oauth-login.popup", function(e) {
  81. e.preventDefault();
  82. var url = $(this).attr("href");
  83. var left = ($(window).width() / 2) - (600 / 2);
  84. var top = ($(window).height() / 2) - (800 / 2);
  85. var newWindow = window.open(url, "singlesignon", "width=600,height=800,left=" + left + ",top=" + top);
  86. if (window.focus) {
  87. newWindow.focus();
  88. }
  89. });
  90. <?php if (version_compare(GLPI_VERSION, '10', '>=')) : ?>
  91. var $boxButtons = $('.singlesignon-box');
  92. $boxButtons.parent().hide();
  93. var $line = $boxButtons.prev('hr');
  94. if ($line.length) {
  95. $line.remove();
  96. }
  97. var $row = $boxButtons.closest('.row');
  98. var $boxLogin = $row.find('div:eq(0)');
  99. $boxButtons.addClass('col-md-5 text-center');
  100. $boxButtons.prependTo($row);
  101. $boxButtons.find('span').addClass("row mb-2");
  102. $boxButtons.find('span a').addClass("col-md-12");
  103. $boxLogin.hide();
  104. $(document).on("click", ".singlesignon.old-login", function(e) {
  105. e.preventDefault();
  106. $boxButtons.slideUp(function() {
  107. $boxLogin.slideDown(function() {
  108. $boxLogin.find(':input:eq(0)').focus();
  109. });
  110. });
  111. });
  112. var $backLogin = $('<label />', {
  113. css: {
  114. cursor: 'pointer'
  115. },
  116. text: "<< " + <?php echo json_encode(__('Back')) ?>,
  117. }).prependTo($boxLogin);
  118. $backLogin.on('click', function(e) {
  119. e.preventDefault();
  120. $boxLogin.slideUp(function() {
  121. $boxButtons.slideDown();
  122. });
  123. });
  124. <?php else : ?>
  125. var $boxLogin = $('#boxlogin');
  126. var $form = $boxLogin.find('form');
  127. var $boxButtons = $('.singlesignon-box');
  128. // Move the buttons to before form
  129. $boxButtons.prependTo($boxLogin);
  130. $boxButtons.find('span').addClass('login_input');
  131. // Show old form
  132. $(document).on("click", ".singlesignon.old-login", function(e) {
  133. e.preventDefault();
  134. $boxButtons.slideUp();
  135. $form.slideDown(function() {
  136. $('#login_name').focus();
  137. });
  138. });
  139. var $line = $('<p />', {
  140. class: 'login_input'
  141. }).prependTo($form);
  142. var $backLogin = $('<label />', {
  143. css: {
  144. cursor: 'pointer'
  145. },
  146. text: "<< " + <?php echo json_encode(__('Back')) ?>,
  147. }).appendTo($line);
  148. $backLogin.on('click', function(e) {
  149. e.preventDefault();
  150. $boxButtons.slideDown();
  151. $form.slideUp();
  152. });
  153. $form.hide();
  154. <?php endif; ?>
  155. });
  156. </script>
  157. <?php
  158. }
  159. }
  160. function plugin_singlesignon_install() {
  161. /* @var $DB DB */
  162. global $DB;
  163. $currentVersion = '0.0.0';
  164. $default = [];
  165. $current = Config::getConfigurationValues('singlesignon');
  166. if (isset($current['version'])) {
  167. $currentVersion = $current['version'];
  168. }
  169. foreach ($default as $key => $value) {
  170. if (!isset($current[$key])) {
  171. $current[$key] = $value;
  172. }
  173. }
  174. Config::setConfigurationValues('singlesignon', $current);
  175. if (!sso_TableExists("glpi_plugin_singlesignon_providers")) {
  176. $query = "CREATE TABLE `glpi_plugin_singlesignon_providers` (
  177. `id` int(11) NOT NULL auto_increment,
  178. `is_default` tinyint(1) NOT NULL DEFAULT '0',
  179. `popup` tinyint(1) NOT NULL DEFAULT '0',
  180. `split_domain` tinyint(1) NOT NULL DEFAULT '0',
  181. `authorized_domains` varchar(255) COLLATE utf8_unicode_ci NULL,
  182. `type` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  183. `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  184. `client_id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  185. `client_secret` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  186. `scope` varchar(255) COLLATE utf8_unicode_ci NULL,
  187. `extra_options` varchar(255) COLLATE utf8_unicode_ci NULL,
  188. `url_authorize` varchar(255) COLLATE utf8_unicode_ci NULL,
  189. `url_access_token` varchar(255) COLLATE utf8_unicode_ci NULL,
  190. `url_resource_owner_details` varchar(255) COLLATE utf8_unicode_ci NULL,
  191. `is_active` tinyint(1) NOT NULL DEFAULT '0',
  192. `use_email_for_login` tinyint(1) NOT NULL DEFAULT '0',
  193. `split_name` tinyint(1) NOT NULL DEFAULT '0',
  194. `is_deleted` tinyint(1) NOT NULL default '0',
  195. `comment` text COLLATE utf8_unicode_ci,
  196. `date_mod` timestamp NULL DEFAULT NULL,
  197. `date_creation` timestamp NULL DEFAULT NULL,
  198. PRIMARY KEY (`id`),
  199. KEY `date_mod` (`date_mod`),
  200. KEY `date_creation` (`date_creation`)
  201. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci";
  202. $DB->query($query) or die("error creating glpi_plugin_singlesignon_providers " . $DB->error());
  203. } else {
  204. $query = "SHOW COLUMNS FROM glpi_plugin_singlesignon_providers LIKE 'is_default'";
  205. $result = $DB->query($query) or die($DB->error());
  206. if ($DB->numrows($result) != 1) {
  207. $DB->query("ALTER TABLE glpi_plugin_singlesignon_providers ADD is_default tinyint(1) NOT NULL DEFAULT '0'") or die($DB->error());
  208. }
  209. $query = "SHOW COLUMNS FROM glpi_plugin_singlesignon_providers LIKE 'popup'";
  210. $result = $DB->query($query) or die($DB->error());
  211. if ($DB->numrows($result) != 1) {
  212. $DB->query("ALTER TABLE glpi_plugin_singlesignon_providers ADD popup tinyint(1) NOT NULL DEFAULT '0'") or die($DB->error());
  213. }
  214. $query = "SHOW COLUMNS FROM glpi_plugin_singlesignon_providers LIKE 'split_domain'";
  215. $result = $DB->query($query) or die($DB->error());
  216. if ($DB->numrows($result) != 1) {
  217. $DB->query("ALTER TABLE glpi_plugin_singlesignon_providers ADD split_domain tinyint(1) NOT NULL DEFAULT '0'") or die($DB->error());
  218. }
  219. $query = "SHOW COLUMNS FROM glpi_plugin_singlesignon_providers LIKE 'authorized_domains'";
  220. $result = $DB->query($query) or die($DB->error());
  221. if ($DB->numrows($result) != 1) {
  222. $DB->query("ALTER TABLE glpi_plugin_singlesignon_providers ADD authorized_domains varchar(255) COLLATE utf8_unicode_ci NULL") or die($DB->error());
  223. }
  224. $query = "SHOW COLUMNS FROM glpi_plugin_singlesignon_providers LIKE 'use_email_for_login'";
  225. $result = $DB->query($query) or die($DB->error());
  226. if ($DB->numrows($result) != 1) {
  227. $DB->query("ALTER TABLE glpi_plugin_singlesignon_providers ADD use_email_for_login tinyint(1) NOT NULL DEFAULT '0'") or die($DB->error());
  228. }
  229. $query = "SHOW COLUMNS FROM glpi_plugin_singlesignon_providers LIKE 'split_name'";
  230. $result = $DB->query($query) or die($DB->error());
  231. if ($DB->numrows($result) != 1) {
  232. $DB->query("ALTER TABLE glpi_plugin_singlesignon_providers ADD split_name tinyint(1) NOT NULL DEFAULT '0'") or die($DB->error());
  233. }
  234. }
  235. // add display preferences
  236. $query_display_pref = "SELECT id
  237. FROM glpi_displaypreferences
  238. WHERE itemtype = 'PluginSinglesignonProvider'";
  239. $res_display_pref = $DB->query($query_display_pref);
  240. if ($DB->numrows($res_display_pref) == 0) {
  241. $DB->query("INSERT INTO `glpi_displaypreferences` VALUES (NULL,'PluginSinglesignonProvider','2','1','0');");
  242. $DB->query("INSERT INTO `glpi_displaypreferences` VALUES (NULL,'PluginSinglesignonProvider','3','2','0');");
  243. $DB->query("INSERT INTO `glpi_displaypreferences` VALUES (NULL,'PluginSinglesignonProvider','5','4','0');");
  244. $DB->query("INSERT INTO `glpi_displaypreferences` VALUES (NULL,'PluginSinglesignonProvider','6','5','0');");
  245. $DB->query("INSERT INTO `glpi_displaypreferences` VALUES (NULL,'PluginSinglesignonProvider','10','6','0');");
  246. }
  247. if (!sso_TableExists("glpi_plugin_singlesignon_providers_users") && version_compare($currentVersion, "1.2.0", '<')) {
  248. $query = "ALTER TABLE `glpi_plugin_singlesignon_providers`
  249. ADD `picture` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  250. ADD `bgcolor` varchar(7) DEFAULT NULL,
  251. ADD `color` varchar(7) DEFAULT NULL";
  252. $DB->query($query) or die("error adding picture column " . $DB->error());
  253. }
  254. if (!sso_TableExists("glpi_plugin_singlesignon_providers_users") && version_compare($currentVersion, "1.3.0", '<')) {
  255. $query = "CREATE TABLE `glpi_plugin_singlesignon_providers_users` (
  256. `id` int(11) NOT NULL AUTO_INCREMENT,
  257. `plugin_singlesignon_providers_id` int(11) NOT NULL DEFAULT '0',
  258. `users_id` int(11) NOT NULL DEFAULT '0',
  259. `remote_id` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  260. PRIMARY KEY (`id`),
  261. UNIQUE KEY `unicity` (`plugin_singlesignon_providers_id`,`users_id`),
  262. UNIQUE KEY `unicity_remote` (`plugin_singlesignon_providers_id`,`remote_id`)
  263. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;";
  264. $DB->query($query) or die("error creating glpi_plugin_singlesignon_providers_users " . $DB->error());
  265. }
  266. Config::setConfigurationValues('singlesignon', [
  267. 'version' => PLUGIN_SINGLESIGNON_VERSION,
  268. ]);
  269. return true;
  270. }
  271. function plugin_singlesignon_uninstall() {
  272. global $DB;
  273. $config = new Config();
  274. $condition = "`context` LIKE 'singlesignon%'";
  275. if (version_compare(GLPI_VERSION, '9.4', '>=')) {
  276. $condition = [$condition];
  277. }
  278. $rows = $config->find($condition);
  279. foreach ($rows as $id => $row) {
  280. $config->delete(['id' => $id]);
  281. }
  282. // Old version tables
  283. if (sso_TableExists("glpi_plugin_singlesignon_providers")) {
  284. $query = "DROP TABLE `glpi_plugin_singlesignon_providers`";
  285. $DB->query($query) or die("error deleting glpi_plugin_singlesignon_providers");
  286. }
  287. return true;
  288. }