summaryrefslogtreecommitdiffstats
path: root/glpi-security2.patch
blob: 254c47a61cd6731159122656b3730d18f7167ccb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
From 9cd45a1ec1932189fc5295e0f9978b36ab5eecaa Mon Sep 17 00:00:00 2001
From: Remi Collet <remi@remirepo.net>
Date: Wed, 27 Mar 2019 14:55:25 +0100
Subject: [PATCH] Fix/cookie auth (#5562) * prevent timed attack * add new
 field for storing cookie token and reverse the verification (we store the
 hash on our side and not client side)

Backported from 9.4 26900a5e53a5ad347d20a947eb5f7e2b447fef9f

Check cookie validity on glpi side

Backported from 9.4 a3ab29c77c6fc7a45a7b0ef71c4442aee62acda6

Hack for DB Schema

As 9.3.3 use dbschema 9.3.2, we can switch to 9.3.3
Migration detection use dbversion, so will be raised
Script execution use version, which allow to keep it unchanged
More 9.4 is aware of 9.3.3 (not of 9.4)
---
 inc/auth.class.php           | 19 ++++-------
 inc/define.php               |  2 +-
 inc/update.class.php         |  7 +++-
 inc/user.class.php           | 64 ++++++++++++++++++++++++++++++------
 install/mysql/glpi-empty.sql | 10 +++---
 install/update_932_933.php   | 63 +++++++++++++++++++++++++++++++++++
 6 files changed, 136 insertions(+), 29 deletions(-)
 create mode 100644 install/update_932_933.php

diff --git a/inc/auth.class.php b/inc/auth.class.php
index 707d7ab31..67d361653 100644
--- a/inc/auth.class.php
+++ b/inc/auth.class.php
@@ -500,11 +500,11 @@ class Auth extends CommonGLPI {
                if (count($data) === 2) {
                   list ($cookie_id, $cookie_token) = $data;
 
-                  $token = User::getToken($cookie_id, 'personal_token');
+                  $user = new User();
+                  $user->getFromDB($cookie_id);
+                  $hash = $user->getAuthToken('cookie_token');
 
-                  if ($token !== false && Auth::checkPassword($token, $cookie_token)) {
-                     $user = new User();
-                     $user->getFromDB($cookie_id); //true if $token is not false
+                  if (Auth::checkPassword($cookie_token, $hash)) {
                      $this->user->fields['name'] = $user->fields['name'];
                      return true;
                   } else {
@@ -848,12 +848,7 @@ class Auth extends CommonGLPI {
       }
 
       if ($this->auth_succeded && $CFG_GLPI['login_remember_time'] > 0 && $remember_me) {
-         $token = false;
-         if (!empty($this->user->fields['personal_token'])) {
-            $token = $this->user->fields['personal_token'];
-         } else {
-            $token = User::getToken($this->user->fields['id'], 'personal_token');
-         }
+         $token = $this->user->getAuthToken('cookie_token', true);
 
          if ($token) {
             //Cookie name (Allow multiple GLPI)
@@ -861,11 +856,9 @@ class Auth extends CommonGLPI {
             //Cookie session path
             $cookie_path = ini_get('session.cookie_path');
 
-            $hash = Auth::getPasswordHash($token);
-
             $data = json_encode([
                 $this->user->fields['id'],
-                $hash,
+                $token,
             ]);
 
             //Send cookie to browser
diff --git a/inc/define.php b/inc/define.php
index 78125529e..22830bc05 100644
--- a/inc/define.php
+++ b/inc/define.php
@@ -41,7 +41,7 @@ if (substr(GLPI_VERSION, -4) === '-dev') {
    );
 } else {
    //for stable version
-   define("GLPI_SCHEMA_VERSION", '9.3.2');
+   define("GLPI_SCHEMA_VERSION", '9.3.3');
 }
 define('GLPI_MIN_PHP', '5.6.0'); // Must also be changed in top of index.php
 define('GLPI_YEAR', '2018');
diff --git a/inc/update.class.php b/inc/update.class.php
index fec2271c0..e3da3c9f0 100644
--- a/inc/update.class.php
+++ b/inc/update.class.php
@@ -431,7 +431,12 @@ class Update extends CommonGLPI {
          case "9.3.1":
             include_once "{$updir}update_931_932.php";
             update931to932();
-            break;
+
+         case "9.3.2":
+         case "9.3.3":
+            // post 9.3.3
+            include_once "{$updir}update_932_933.php";
+            update932to933();
 
          case GLPI_VERSION:
          case GLPI_SCHEMA_VERSION:
diff --git a/inc/user.class.php b/inc/user.class.php
index 67bfc7149..d4139edfa 100644
--- a/inc/user.class.php
+++ b/inc/user.class.php
@@ -4595,26 +4595,70 @@ class User extends CommonDBTM {
    }
 
 
-   /**
+    /**
+    * Get token of a user. If it does not exists  then generate it.
+    *
+    * @since 9.4
+    *
+    * @param string $field the field storing the token
+    * @param boolean $force_new force generation of a new token
+    *
+    * @return string|false token or false in case of error
+    */
+   public function getAuthToken($field = 'personal_token', $force_new = false) {
+      global $CFG_GLPI;
+
+      if ($this->isNewItem()) {
+         return false;
+      }
+
+      // check date validity for cookie token
+      $outdated = false;
+      if ($field === 'cookie_token') {
+         $date_create = new DateTime($this->fields[$field."_date"]);
+         $date_expir  = $date_create->add(new DateInterval('PT'.$CFG_GLPI["login_remember_time"].'S'));
+
+         if ($date_expir < new DateTime()) {
+            $outdated = true;
+         }
+      }
+
+      // token exists, is not oudated, and we may use it
+      if (!empty($this->fields[$field]) && !$force_new && !$outdated) {
+         return $this->fields[$field];
+      }
+
+      // else get a new token
+      $token = self::getUniqueToken($field);
+
+      // for cookie token, we need to store it hashed
+      $hash = $token;
+      if ($field === 'cookie_token') {
+         $hash = Auth::getPasswordHash($token);
+      }
+
+      // save this token in db
+      $this->update(['id'             => $this->getID(),
+                     $field           => $hash,
+                     $field . "_date" => $_SESSION['glpi_currenttime']]);
+
+      return $token;
+   }
+
+/**
     * Get token of a user. If not exists generate it.
     *
     * @param integer $ID    User ID
     * @param string  $field Field storing the token
+    * @param boolean $force_new force generation of a new token
     *
     * @return string|boolean User token, false if user does not exist
     */
-   static function getToken($ID, $field = 'personal_token') {
+   static function getToken($ID, $field = 'personal_token', $force_new = false) {
 
       $user = new self();
       if ($user->getFromDB($ID)) {
-         if (!empty($user->fields[$field])) {
-            return $user->fields[$field];
-         }
-         $token = self::getUniqueToken($field);
-         $user->update(['id'             => $user->getID(),
-                             $field           => $token,
-                             $field . "_date" => $_SESSION['glpi_currenttime']]);
-         return $user->fields[$field];
+         return $user->getAuthToken($field, $force_new);
       }
 
       return false;
diff --git a/install/mysql/glpi-empty.sql b/install/mysql/glpi-empty.sql
index abfe14600..14d6976c9 100644
--- a/install/mysql/glpi-empty.sql
+++ b/install/mysql/glpi-empty.sql
@@ -8850,6 +8850,8 @@ CREATE TABLE `glpi_users` (
   `personal_token_date` datetime DEFAULT NULL,
   `api_token` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
   `api_token_date` datetime DEFAULT NULL,
+  `cookie_token` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
+  `cookie_token_date` datetime DEFAULT NULL,
   `display_count_on_home` int(11) DEFAULT NULL,
   `notification_to_myself` tinyint(1) DEFAULT NULL,
   `duedateok_color` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
@@ -8900,10 +8902,10 @@ CREATE TABLE `glpi_users` (
   KEY `sync_field` (`sync_field`)
 ) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
 
-INSERT INTO `glpi_users` VALUES ('2','glpi','$2y$10$rXXzbc2ShaiCldwkw4AZL.n.9QSH7c0c9XJAyyjrbL9BwmWditAYm','','','','',NULL,'0',NULL,'0','20','1',NULL,'0','1','2014-06-18 08:02:24','2014-06-18 08:02:24',NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL);
-INSERT INTO `glpi_users` VALUES ('3','post-only','$2y$10$dTMar1F3ef5X/H1IjX9gYOjQWBR1K4bERGf4/oTPxFtJE/c3vXILm','','','','',NULL,'0','en_GB','0','20','1',NULL,'0','1',NULL,NULL,NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL);
-INSERT INTO `glpi_users` VALUES ('4','tech','$2y$10$.xEgErizkp6Az0z.DHyoeOoenuh0RcsX4JapBk2JMD6VI17KtB1lO','','','','',NULL,'0','en_GB','0','20','1',NULL,'0','1',NULL,NULL,NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL);
-INSERT INTO `glpi_users` VALUES ('5','normal','$2y$10$Z6doq4zVHkSPZFbPeXTCluN1Q/r0ryZ3ZsSJncJqkN3.8cRiN0NV.','','','','',NULL,'0','en_GB','0','20','1',NULL,'0','1',NULL,NULL,NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL);
+INSERT INTO `glpi_users` VALUES ('2','glpi','$2y$10$rXXzbc2ShaiCldwkw4AZL.n.9QSH7c0c9XJAyyjrbL9BwmWditAYm','','','','',NULL,'0',NULL,'0','20','1',NULL,'0','1','2014-06-18 08:02:24','2014-06-18 08:02:24',NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL);
+INSERT INTO `glpi_users` VALUES ('3','post-only','$2y$10$dTMar1F3ef5X/H1IjX9gYOjQWBR1K4bERGf4/oTPxFtJE/c3vXILm','','','','',NULL,'0','en_GB','0','20','1',NULL,'0','1',NULL,NULL,NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL);
+INSERT INTO `glpi_users` VALUES ('4','tech','$2y$10$.xEgErizkp6Az0z.DHyoeOoenuh0RcsX4JapBk2JMD6VI17KtB1lO','','','','',NULL,'0','en_GB','0','20','1',NULL,'0','1',NULL,NULL,NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL);
+INSERT INTO `glpi_users` VALUES ('5','normal','$2y$10$Z6doq4zVHkSPZFbPeXTCluN1Q/r0ryZ3ZsSJncJqkN3.8cRiN0NV.','','','','',NULL,'0','en_GB','0','20','1',NULL,'0','1',NULL,NULL,NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL);
 
 ### Dump table glpi_usertitles
 
diff --git a/install/update_932_933.php b/install/update_932_933.php
new file mode 100644
index 000000000..240c5cb00
--- /dev/null
+++ b/install/update_932_933.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ * ---------------------------------------------------------------------
+ * GLPI - Gestionnaire Libre de Parc Informatique
+ * Copyright (C) 2015-2017 Teclib' and contributors.
+ *
+ * http://glpi-project.org
+ *
+ * based on GLPI - Gestionnaire Libre de Parc Informatique
+ * Copyright (C) 2003-2014 by the INDEPNET Development Team.
+ *
+ * ---------------------------------------------------------------------
+ *
+ * LICENSE
+ *
+ * This file is part of GLPI.
+ *
+ * GLPI is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GLPI is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GLPI. If not, see <http://www.gnu.org/licenses/>.
+ * ---------------------------------------------------------------------
+ */
+
+/** @file
+* @brief
+*/
+
+/**
+ * Update from 9.3.2 to 9.3.3 (DB schema version, introduced post 9.3.3)
+ *
+ * @return bool for success (will die for most error)
+**/
+function update932to933() {
+   global $DB, $migration, $CFG_GLPI;
+
+   $current_config   = Config::getConfigurationValues('core');
+   $updateresult     = true;
+   $ADDTODISPLAYPREF = [];
+
+   //TRANS: %s is the number of new version
+   $migration->displayTitle(sprintf(__('Update to %s'), '9.3.3'));
+   $migration->setVersion('9.3.3');
+
+   // Create a dedicated token for rememberme process
+   if (!$DB->fieldExists('glpi_users', 'cookie_token')) {
+      $migration->addField('glpi_users', 'cookie_token', 'string', ['after' => 'api_token_date']);
+      $migration->addField('glpi_users', 'cookie_token_date', 'datetime', ['after' => 'cookie_token']);
+   }
+
+   // ************ Keep it at the end **************
+   $migration->executeMigration();
+
+   return $updateresult;
+}
-- 
2.20.1