Passed
Push — master ( 778ef8...3ee2db )
by Roeland
19:15 queued 09:15
created
lib/private/Authentication/Token/DefaultTokenProvider.php 2 patches
Indentation   +306 added lines, -306 removed lines patch added patch discarded remove patch
@@ -44,310 +44,310 @@
 block discarded – undo
44 44
 
45 45
 class DefaultTokenProvider implements IProvider {
46 46
 
47
-	/** @var DefaultTokenMapper */
48
-	private $mapper;
49
-
50
-	/** @var ICrypto */
51
-	private $crypto;
52
-
53
-	/** @var IConfig */
54
-	private $config;
55
-
56
-	/** @var ILogger */
57
-	private $logger;
58
-
59
-	/** @var ITimeFactory */
60
-	private $time;
61
-
62
-	public function __construct(DefaultTokenMapper $mapper,
63
-								ICrypto $crypto,
64
-								IConfig $config,
65
-								ILogger $logger,
66
-								ITimeFactory $time) {
67
-		$this->mapper = $mapper;
68
-		$this->crypto = $crypto;
69
-		$this->config = $config;
70
-		$this->logger = $logger;
71
-		$this->time = $time;
72
-	}
73
-
74
-	/**
75
-	 * Create and persist a new token
76
-	 *
77
-	 * @param string $token
78
-	 * @param string $uid
79
-	 * @param string $loginName
80
-	 * @param string|null $password
81
-	 * @param string $name
82
-	 * @param int $type token type
83
-	 * @param int $remember whether the session token should be used for remember-me
84
-	 * @return IToken
85
-	 */
86
-	public function generateToken(string $token,
87
-								  string $uid,
88
-								  string $loginName,
89
-								  $password,
90
-								  string $name,
91
-								  int $type = IToken::TEMPORARY_TOKEN,
92
-								  int $remember = IToken::DO_NOT_REMEMBER): IToken {
93
-		$dbToken = new DefaultToken();
94
-		$dbToken->setUid($uid);
95
-		$dbToken->setLoginName($loginName);
96
-		if (!is_null($password)) {
97
-			$dbToken->setPassword($this->encryptPassword($password, $token));
98
-		}
99
-		$dbToken->setName($name);
100
-		$dbToken->setToken($this->hashToken($token));
101
-		$dbToken->setType($type);
102
-		$dbToken->setRemember($remember);
103
-		$dbToken->setLastActivity($this->time->getTime());
104
-		$dbToken->setLastCheck($this->time->getTime());
105
-		$dbToken->setVersion(DefaultToken::VERSION);
106
-
107
-		$this->mapper->insert($dbToken);
108
-
109
-		return $dbToken;
110
-	}
111
-
112
-	/**
113
-	 * Save the updated token
114
-	 *
115
-	 * @param IToken $token
116
-	 * @throws InvalidTokenException
117
-	 */
118
-	public function updateToken(IToken $token) {
119
-		if (!($token instanceof DefaultToken)) {
120
-			throw new InvalidTokenException("Invalid token type");
121
-		}
122
-		$this->mapper->update($token);
123
-	}
124
-
125
-	/**
126
-	 * Update token activity timestamp
127
-	 *
128
-	 * @throws InvalidTokenException
129
-	 * @param IToken $token
130
-	 */
131
-	public function updateTokenActivity(IToken $token) {
132
-		if (!($token instanceof DefaultToken)) {
133
-			throw new InvalidTokenException("Invalid token type");
134
-		}
135
-		/** @var DefaultToken $token */
136
-		$now = $this->time->getTime();
137
-		if ($token->getLastActivity() < ($now - 60)) {
138
-			// Update token only once per minute
139
-			$token->setLastActivity($now);
140
-			$this->mapper->update($token);
141
-		}
142
-	}
143
-
144
-	public function getTokenByUser(string $uid): array {
145
-		return $this->mapper->getTokenByUser($uid);
146
-	}
147
-
148
-	/**
149
-	 * Get a token by token
150
-	 *
151
-	 * @param string $tokenId
152
-	 * @throws InvalidTokenException
153
-	 * @throws ExpiredTokenException
154
-	 * @return IToken
155
-	 */
156
-	public function getToken(string $tokenId): IToken {
157
-		try {
158
-			$token = $this->mapper->getToken($this->hashToken($tokenId));
159
-		} catch (DoesNotExistException $ex) {
160
-			throw new InvalidTokenException("Token does not exist", 0, $ex);
161
-		}
162
-
163
-		if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
164
-			throw new ExpiredTokenException($token);
165
-		}
166
-
167
-		return $token;
168
-	}
169
-
170
-	/**
171
-	 * Get a token by token id
172
-	 *
173
-	 * @param int $tokenId
174
-	 * @throws InvalidTokenException
175
-	 * @throws ExpiredTokenException
176
-	 * @return IToken
177
-	 */
178
-	public function getTokenById(int $tokenId): IToken {
179
-		try {
180
-			$token = $this->mapper->getTokenById($tokenId);
181
-		} catch (DoesNotExistException $ex) {
182
-			throw new InvalidTokenException("Token with ID $tokenId does not exist", 0, $ex);
183
-		}
184
-
185
-		if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
186
-			throw new ExpiredTokenException($token);
187
-		}
188
-
189
-		return $token;
190
-	}
191
-
192
-	/**
193
-	 * @param string $oldSessionId
194
-	 * @param string $sessionId
195
-	 * @throws InvalidTokenException
196
-	 * @return IToken
197
-	 */
198
-	public function renewSessionToken(string $oldSessionId, string $sessionId): IToken {
199
-		$token = $this->getToken($oldSessionId);
200
-
201
-		$newToken = new DefaultToken();
202
-		$newToken->setUid($token->getUID());
203
-		$newToken->setLoginName($token->getLoginName());
204
-		if (!is_null($token->getPassword())) {
205
-			$password = $this->decryptPassword($token->getPassword(), $oldSessionId);
206
-			$newToken->setPassword($this->encryptPassword($password, $sessionId));
207
-		}
208
-		$newToken->setName($token->getName());
209
-		$newToken->setToken($this->hashToken($sessionId));
210
-		$newToken->setType(IToken::TEMPORARY_TOKEN);
211
-		$newToken->setRemember($token->getRemember());
212
-		$newToken->setLastActivity($this->time->getTime());
213
-		$this->mapper->insert($newToken);
214
-		$this->mapper->delete($token);
215
-
216
-		return $newToken;
217
-	}
218
-
219
-	/**
220
-	 * @param IToken $savedToken
221
-	 * @param string $tokenId session token
222
-	 * @throws InvalidTokenException
223
-	 * @throws PasswordlessTokenException
224
-	 * @return string
225
-	 */
226
-	public function getPassword(IToken $savedToken, string $tokenId): string {
227
-		$password = $savedToken->getPassword();
228
-		if (is_null($password)) {
229
-			throw new PasswordlessTokenException();
230
-		}
231
-		return $this->decryptPassword($password, $tokenId);
232
-	}
233
-
234
-	/**
235
-	 * Encrypt and set the password of the given token
236
-	 *
237
-	 * @param IToken $token
238
-	 * @param string $tokenId
239
-	 * @param string $password
240
-	 * @throws InvalidTokenException
241
-	 */
242
-	public function setPassword(IToken $token, string $tokenId, string $password) {
243
-		if (!($token instanceof DefaultToken)) {
244
-			throw new InvalidTokenException("Invalid token type");
245
-		}
246
-		/** @var DefaultToken $token */
247
-		$token->setPassword($this->encryptPassword($password, $tokenId));
248
-		$this->mapper->update($token);
249
-	}
250
-
251
-	/**
252
-	 * Invalidate (delete) the given session token
253
-	 *
254
-	 * @param string $token
255
-	 */
256
-	public function invalidateToken(string $token) {
257
-		$this->mapper->invalidate($this->hashToken($token));
258
-	}
259
-
260
-	public function invalidateTokenById(string $uid, int $id) {
261
-		$this->mapper->deleteById($uid, $id);
262
-	}
263
-
264
-	/**
265
-	 * Invalidate (delete) old session tokens
266
-	 */
267
-	public function invalidateOldTokens() {
268
-		$olderThan = $this->time->getTime() - (int) $this->config->getSystemValue('session_lifetime', 60 * 60 * 24);
269
-		$this->logger->debug('Invalidating session tokens older than ' . date('c', $olderThan), ['app' => 'cron']);
270
-		$this->mapper->invalidateOld($olderThan, IToken::DO_NOT_REMEMBER);
271
-		$rememberThreshold = $this->time->getTime() - (int) $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
272
-		$this->logger->debug('Invalidating remembered session tokens older than ' . date('c', $rememberThreshold), ['app' => 'cron']);
273
-		$this->mapper->invalidateOld($rememberThreshold, IToken::REMEMBER);
274
-	}
275
-
276
-	/**
277
-	 * Rotate the token. Usefull for for example oauth tokens
278
-	 *
279
-	 * @param IToken $token
280
-	 * @param string $oldTokenId
281
-	 * @param string $newTokenId
282
-	 * @return IToken
283
-	 */
284
-	public function rotate(IToken $token, string $oldTokenId, string $newTokenId): IToken {
285
-		try {
286
-			$password = $this->getPassword($token, $oldTokenId);
287
-			$token->setPassword($this->encryptPassword($password, $newTokenId));
288
-		} catch (PasswordlessTokenException $e) {
289
-		}
290
-
291
-		$token->setToken($this->hashToken($newTokenId));
292
-		$this->updateToken($token);
293
-
294
-		return $token;
295
-	}
296
-
297
-	/**
298
-	 * @param string $token
299
-	 * @return string
300
-	 */
301
-	private function hashToken(string $token): string {
302
-		$secret = $this->config->getSystemValue('secret');
303
-		return hash('sha512', $token . $secret);
304
-	}
305
-
306
-	/**
307
-	 * Encrypt the given password
308
-	 *
309
-	 * The token is used as key
310
-	 *
311
-	 * @param string $password
312
-	 * @param string $token
313
-	 * @return string encrypted password
314
-	 */
315
-	private function encryptPassword(string $password, string $token): string {
316
-		$secret = $this->config->getSystemValue('secret');
317
-		return $this->crypto->encrypt($password, $token . $secret);
318
-	}
319
-
320
-	/**
321
-	 * Decrypt the given password
322
-	 *
323
-	 * The token is used as key
324
-	 *
325
-	 * @param string $password
326
-	 * @param string $token
327
-	 * @throws InvalidTokenException
328
-	 * @return string the decrypted key
329
-	 */
330
-	private function decryptPassword(string $password, string $token): string {
331
-		$secret = $this->config->getSystemValue('secret');
332
-		try {
333
-			return $this->crypto->decrypt($password, $token . $secret);
334
-		} catch (Exception $ex) {
335
-			// Delete the invalid token
336
-			$this->invalidateToken($token);
337
-			throw new InvalidTokenException("Can not decrypt token password: " . $ex->getMessage(), 0, $ex);
338
-		}
339
-	}
340
-
341
-	public function markPasswordInvalid(IToken $token, string $tokenId) {
342
-		if (!($token instanceof DefaultToken)) {
343
-			throw new InvalidTokenException("Invalid token type");
344
-		}
345
-
346
-		//No need to mark as invalid. We just invalide default tokens
347
-		$this->invalidateToken($tokenId);
348
-	}
349
-
350
-	public function updatePasswords(string $uid, string $password) {
351
-		// Nothing to do here
352
-	}
47
+    /** @var DefaultTokenMapper */
48
+    private $mapper;
49
+
50
+    /** @var ICrypto */
51
+    private $crypto;
52
+
53
+    /** @var IConfig */
54
+    private $config;
55
+
56
+    /** @var ILogger */
57
+    private $logger;
58
+
59
+    /** @var ITimeFactory */
60
+    private $time;
61
+
62
+    public function __construct(DefaultTokenMapper $mapper,
63
+                                ICrypto $crypto,
64
+                                IConfig $config,
65
+                                ILogger $logger,
66
+                                ITimeFactory $time) {
67
+        $this->mapper = $mapper;
68
+        $this->crypto = $crypto;
69
+        $this->config = $config;
70
+        $this->logger = $logger;
71
+        $this->time = $time;
72
+    }
73
+
74
+    /**
75
+     * Create and persist a new token
76
+     *
77
+     * @param string $token
78
+     * @param string $uid
79
+     * @param string $loginName
80
+     * @param string|null $password
81
+     * @param string $name
82
+     * @param int $type token type
83
+     * @param int $remember whether the session token should be used for remember-me
84
+     * @return IToken
85
+     */
86
+    public function generateToken(string $token,
87
+                                    string $uid,
88
+                                    string $loginName,
89
+                                    $password,
90
+                                    string $name,
91
+                                    int $type = IToken::TEMPORARY_TOKEN,
92
+                                    int $remember = IToken::DO_NOT_REMEMBER): IToken {
93
+        $dbToken = new DefaultToken();
94
+        $dbToken->setUid($uid);
95
+        $dbToken->setLoginName($loginName);
96
+        if (!is_null($password)) {
97
+            $dbToken->setPassword($this->encryptPassword($password, $token));
98
+        }
99
+        $dbToken->setName($name);
100
+        $dbToken->setToken($this->hashToken($token));
101
+        $dbToken->setType($type);
102
+        $dbToken->setRemember($remember);
103
+        $dbToken->setLastActivity($this->time->getTime());
104
+        $dbToken->setLastCheck($this->time->getTime());
105
+        $dbToken->setVersion(DefaultToken::VERSION);
106
+
107
+        $this->mapper->insert($dbToken);
108
+
109
+        return $dbToken;
110
+    }
111
+
112
+    /**
113
+     * Save the updated token
114
+     *
115
+     * @param IToken $token
116
+     * @throws InvalidTokenException
117
+     */
118
+    public function updateToken(IToken $token) {
119
+        if (!($token instanceof DefaultToken)) {
120
+            throw new InvalidTokenException("Invalid token type");
121
+        }
122
+        $this->mapper->update($token);
123
+    }
124
+
125
+    /**
126
+     * Update token activity timestamp
127
+     *
128
+     * @throws InvalidTokenException
129
+     * @param IToken $token
130
+     */
131
+    public function updateTokenActivity(IToken $token) {
132
+        if (!($token instanceof DefaultToken)) {
133
+            throw new InvalidTokenException("Invalid token type");
134
+        }
135
+        /** @var DefaultToken $token */
136
+        $now = $this->time->getTime();
137
+        if ($token->getLastActivity() < ($now - 60)) {
138
+            // Update token only once per minute
139
+            $token->setLastActivity($now);
140
+            $this->mapper->update($token);
141
+        }
142
+    }
143
+
144
+    public function getTokenByUser(string $uid): array {
145
+        return $this->mapper->getTokenByUser($uid);
146
+    }
147
+
148
+    /**
149
+     * Get a token by token
150
+     *
151
+     * @param string $tokenId
152
+     * @throws InvalidTokenException
153
+     * @throws ExpiredTokenException
154
+     * @return IToken
155
+     */
156
+    public function getToken(string $tokenId): IToken {
157
+        try {
158
+            $token = $this->mapper->getToken($this->hashToken($tokenId));
159
+        } catch (DoesNotExistException $ex) {
160
+            throw new InvalidTokenException("Token does not exist", 0, $ex);
161
+        }
162
+
163
+        if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
164
+            throw new ExpiredTokenException($token);
165
+        }
166
+
167
+        return $token;
168
+    }
169
+
170
+    /**
171
+     * Get a token by token id
172
+     *
173
+     * @param int $tokenId
174
+     * @throws InvalidTokenException
175
+     * @throws ExpiredTokenException
176
+     * @return IToken
177
+     */
178
+    public function getTokenById(int $tokenId): IToken {
179
+        try {
180
+            $token = $this->mapper->getTokenById($tokenId);
181
+        } catch (DoesNotExistException $ex) {
182
+            throw new InvalidTokenException("Token with ID $tokenId does not exist", 0, $ex);
183
+        }
184
+
185
+        if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
186
+            throw new ExpiredTokenException($token);
187
+        }
188
+
189
+        return $token;
190
+    }
191
+
192
+    /**
193
+     * @param string $oldSessionId
194
+     * @param string $sessionId
195
+     * @throws InvalidTokenException
196
+     * @return IToken
197
+     */
198
+    public function renewSessionToken(string $oldSessionId, string $sessionId): IToken {
199
+        $token = $this->getToken($oldSessionId);
200
+
201
+        $newToken = new DefaultToken();
202
+        $newToken->setUid($token->getUID());
203
+        $newToken->setLoginName($token->getLoginName());
204
+        if (!is_null($token->getPassword())) {
205
+            $password = $this->decryptPassword($token->getPassword(), $oldSessionId);
206
+            $newToken->setPassword($this->encryptPassword($password, $sessionId));
207
+        }
208
+        $newToken->setName($token->getName());
209
+        $newToken->setToken($this->hashToken($sessionId));
210
+        $newToken->setType(IToken::TEMPORARY_TOKEN);
211
+        $newToken->setRemember($token->getRemember());
212
+        $newToken->setLastActivity($this->time->getTime());
213
+        $this->mapper->insert($newToken);
214
+        $this->mapper->delete($token);
215
+
216
+        return $newToken;
217
+    }
218
+
219
+    /**
220
+     * @param IToken $savedToken
221
+     * @param string $tokenId session token
222
+     * @throws InvalidTokenException
223
+     * @throws PasswordlessTokenException
224
+     * @return string
225
+     */
226
+    public function getPassword(IToken $savedToken, string $tokenId): string {
227
+        $password = $savedToken->getPassword();
228
+        if (is_null($password)) {
229
+            throw new PasswordlessTokenException();
230
+        }
231
+        return $this->decryptPassword($password, $tokenId);
232
+    }
233
+
234
+    /**
235
+     * Encrypt and set the password of the given token
236
+     *
237
+     * @param IToken $token
238
+     * @param string $tokenId
239
+     * @param string $password
240
+     * @throws InvalidTokenException
241
+     */
242
+    public function setPassword(IToken $token, string $tokenId, string $password) {
243
+        if (!($token instanceof DefaultToken)) {
244
+            throw new InvalidTokenException("Invalid token type");
245
+        }
246
+        /** @var DefaultToken $token */
247
+        $token->setPassword($this->encryptPassword($password, $tokenId));
248
+        $this->mapper->update($token);
249
+    }
250
+
251
+    /**
252
+     * Invalidate (delete) the given session token
253
+     *
254
+     * @param string $token
255
+     */
256
+    public function invalidateToken(string $token) {
257
+        $this->mapper->invalidate($this->hashToken($token));
258
+    }
259
+
260
+    public function invalidateTokenById(string $uid, int $id) {
261
+        $this->mapper->deleteById($uid, $id);
262
+    }
263
+
264
+    /**
265
+     * Invalidate (delete) old session tokens
266
+     */
267
+    public function invalidateOldTokens() {
268
+        $olderThan = $this->time->getTime() - (int) $this->config->getSystemValue('session_lifetime', 60 * 60 * 24);
269
+        $this->logger->debug('Invalidating session tokens older than ' . date('c', $olderThan), ['app' => 'cron']);
270
+        $this->mapper->invalidateOld($olderThan, IToken::DO_NOT_REMEMBER);
271
+        $rememberThreshold = $this->time->getTime() - (int) $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
272
+        $this->logger->debug('Invalidating remembered session tokens older than ' . date('c', $rememberThreshold), ['app' => 'cron']);
273
+        $this->mapper->invalidateOld($rememberThreshold, IToken::REMEMBER);
274
+    }
275
+
276
+    /**
277
+     * Rotate the token. Usefull for for example oauth tokens
278
+     *
279
+     * @param IToken $token
280
+     * @param string $oldTokenId
281
+     * @param string $newTokenId
282
+     * @return IToken
283
+     */
284
+    public function rotate(IToken $token, string $oldTokenId, string $newTokenId): IToken {
285
+        try {
286
+            $password = $this->getPassword($token, $oldTokenId);
287
+            $token->setPassword($this->encryptPassword($password, $newTokenId));
288
+        } catch (PasswordlessTokenException $e) {
289
+        }
290
+
291
+        $token->setToken($this->hashToken($newTokenId));
292
+        $this->updateToken($token);
293
+
294
+        return $token;
295
+    }
296
+
297
+    /**
298
+     * @param string $token
299
+     * @return string
300
+     */
301
+    private function hashToken(string $token): string {
302
+        $secret = $this->config->getSystemValue('secret');
303
+        return hash('sha512', $token . $secret);
304
+    }
305
+
306
+    /**
307
+     * Encrypt the given password
308
+     *
309
+     * The token is used as key
310
+     *
311
+     * @param string $password
312
+     * @param string $token
313
+     * @return string encrypted password
314
+     */
315
+    private function encryptPassword(string $password, string $token): string {
316
+        $secret = $this->config->getSystemValue('secret');
317
+        return $this->crypto->encrypt($password, $token . $secret);
318
+    }
319
+
320
+    /**
321
+     * Decrypt the given password
322
+     *
323
+     * The token is used as key
324
+     *
325
+     * @param string $password
326
+     * @param string $token
327
+     * @throws InvalidTokenException
328
+     * @return string the decrypted key
329
+     */
330
+    private function decryptPassword(string $password, string $token): string {
331
+        $secret = $this->config->getSystemValue('secret');
332
+        try {
333
+            return $this->crypto->decrypt($password, $token . $secret);
334
+        } catch (Exception $ex) {
335
+            // Delete the invalid token
336
+            $this->invalidateToken($token);
337
+            throw new InvalidTokenException("Can not decrypt token password: " . $ex->getMessage(), 0, $ex);
338
+        }
339
+    }
340
+
341
+    public function markPasswordInvalid(IToken $token, string $tokenId) {
342
+        if (!($token instanceof DefaultToken)) {
343
+            throw new InvalidTokenException("Invalid token type");
344
+        }
345
+
346
+        //No need to mark as invalid. We just invalide default tokens
347
+        $this->invalidateToken($tokenId);
348
+    }
349
+
350
+    public function updatePasswords(string $uid, string $password) {
351
+        // Nothing to do here
352
+    }
353 353
 }
Please login to merge, or discard this patch.
Spacing   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -160,7 +160,7 @@  discard block
 block discarded – undo
160 160
 			throw new InvalidTokenException("Token does not exist", 0, $ex);
161 161
 		}
162 162
 
163
-		if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
163
+		if ((int) $token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
164 164
 			throw new ExpiredTokenException($token);
165 165
 		}
166 166
 
@@ -182,7 +182,7 @@  discard block
 block discarded – undo
182 182
 			throw new InvalidTokenException("Token with ID $tokenId does not exist", 0, $ex);
183 183
 		}
184 184
 
185
-		if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
185
+		if ((int) $token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
186 186
 			throw new ExpiredTokenException($token);
187 187
 		}
188 188
 
@@ -266,10 +266,10 @@  discard block
 block discarded – undo
266 266
 	 */
267 267
 	public function invalidateOldTokens() {
268 268
 		$olderThan = $this->time->getTime() - (int) $this->config->getSystemValue('session_lifetime', 60 * 60 * 24);
269
-		$this->logger->debug('Invalidating session tokens older than ' . date('c', $olderThan), ['app' => 'cron']);
269
+		$this->logger->debug('Invalidating session tokens older than '.date('c', $olderThan), ['app' => 'cron']);
270 270
 		$this->mapper->invalidateOld($olderThan, IToken::DO_NOT_REMEMBER);
271 271
 		$rememberThreshold = $this->time->getTime() - (int) $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
272
-		$this->logger->debug('Invalidating remembered session tokens older than ' . date('c', $rememberThreshold), ['app' => 'cron']);
272
+		$this->logger->debug('Invalidating remembered session tokens older than '.date('c', $rememberThreshold), ['app' => 'cron']);
273 273
 		$this->mapper->invalidateOld($rememberThreshold, IToken::REMEMBER);
274 274
 	}
275 275
 
@@ -300,7 +300,7 @@  discard block
 block discarded – undo
300 300
 	 */
301 301
 	private function hashToken(string $token): string {
302 302
 		$secret = $this->config->getSystemValue('secret');
303
-		return hash('sha512', $token . $secret);
303
+		return hash('sha512', $token.$secret);
304 304
 	}
305 305
 
306 306
 	/**
@@ -314,7 +314,7 @@  discard block
 block discarded – undo
314 314
 	 */
315 315
 	private function encryptPassword(string $password, string $token): string {
316 316
 		$secret = $this->config->getSystemValue('secret');
317
-		return $this->crypto->encrypt($password, $token . $secret);
317
+		return $this->crypto->encrypt($password, $token.$secret);
318 318
 	}
319 319
 
320 320
 	/**
@@ -330,11 +330,11 @@  discard block
 block discarded – undo
330 330
 	private function decryptPassword(string $password, string $token): string {
331 331
 		$secret = $this->config->getSystemValue('secret');
332 332
 		try {
333
-			return $this->crypto->decrypt($password, $token . $secret);
333
+			return $this->crypto->decrypt($password, $token.$secret);
334 334
 		} catch (Exception $ex) {
335 335
 			// Delete the invalid token
336 336
 			$this->invalidateToken($token);
337
-			throw new InvalidTokenException("Can not decrypt token password: " . $ex->getMessage(), 0, $ex);
337
+			throw new InvalidTokenException("Can not decrypt token password: ".$ex->getMessage(), 0, $ex);
338 338
 		}
339 339
 	}
340 340
 
Please login to merge, or discard this patch.
lib/private/Authentication/Token/PublicKeyTokenProvider.php 2 patches
Indentation   +388 added lines, -388 removed lines patch added patch discarded remove patch
@@ -42,392 +42,392 @@
 block discarded – undo
42 42
 use OCP\Security\ICrypto;
43 43
 
44 44
 class PublicKeyTokenProvider implements IProvider {
45
-	/** @var PublicKeyTokenMapper */
46
-	private $mapper;
47
-
48
-	/** @var ICrypto */
49
-	private $crypto;
50
-
51
-	/** @var IConfig */
52
-	private $config;
53
-
54
-	/** @var ILogger $logger */
55
-	private $logger;
56
-
57
-	/** @var ITimeFactory $time */
58
-	private $time;
59
-
60
-	/** @var CappedMemoryCache */
61
-	private $cache;
62
-
63
-	public function __construct(PublicKeyTokenMapper $mapper,
64
-								ICrypto $crypto,
65
-								IConfig $config,
66
-								ILogger $logger,
67
-								ITimeFactory $time) {
68
-		$this->mapper = $mapper;
69
-		$this->crypto = $crypto;
70
-		$this->config = $config;
71
-		$this->logger = $logger;
72
-		$this->time = $time;
73
-
74
-		$this->cache = new CappedMemoryCache();
75
-	}
76
-
77
-	/**
78
-	 * {@inheritDoc}
79
-	 */
80
-	public function generateToken(string $token,
81
-								  string $uid,
82
-								  string $loginName,
83
-								  $password,
84
-								  string $name,
85
-								  int $type = IToken::TEMPORARY_TOKEN,
86
-								  int $remember = IToken::DO_NOT_REMEMBER): IToken {
87
-		$dbToken = $this->newToken($token, $uid, $loginName, $password, $name, $type, $remember);
88
-		$this->mapper->insert($dbToken);
89
-
90
-		// Add the token to the cache
91
-		$this->cache[$dbToken->getToken()] = $dbToken;
92
-
93
-		return $dbToken;
94
-	}
95
-
96
-	public function getToken(string $tokenId): IToken {
97
-		$tokenHash = $this->hashToken($tokenId);
98
-
99
-		if (isset($this->cache[$tokenHash])) {
100
-			$token = $this->cache[$tokenHash];
101
-		} else {
102
-			try {
103
-				$token = $this->mapper->getToken($this->hashToken($tokenId));
104
-				$this->cache[$token->getToken()] = $token;
105
-			} catch (DoesNotExistException $ex) {
106
-				throw new InvalidTokenException("Token does not exist: " . $ex->getMessage(), 0, $ex);
107
-			}
108
-		}
109
-
110
-		if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
111
-			throw new ExpiredTokenException($token);
112
-		}
113
-
114
-		if ($token->getType() === IToken::WIPE_TOKEN) {
115
-			throw new WipeTokenException($token);
116
-		}
117
-
118
-		if ($token->getPasswordInvalid() === true) {
119
-			//The password is invalid we should throw an TokenPasswordExpiredException
120
-			throw new TokenPasswordExpiredException($token);
121
-		}
122
-
123
-		return $token;
124
-	}
125
-
126
-	public function getTokenById(int $tokenId): IToken {
127
-		try {
128
-			$token = $this->mapper->getTokenById($tokenId);
129
-		} catch (DoesNotExistException $ex) {
130
-			throw new InvalidTokenException("Token with ID $tokenId does not exist: " . $ex->getMessage(), 0, $ex);
131
-		}
132
-
133
-		if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
134
-			throw new ExpiredTokenException($token);
135
-		}
136
-
137
-		if ($token->getType() === IToken::WIPE_TOKEN) {
138
-			throw new WipeTokenException($token);
139
-		}
140
-
141
-		if ($token->getPasswordInvalid() === true) {
142
-			//The password is invalid we should throw an TokenPasswordExpiredException
143
-			throw new TokenPasswordExpiredException($token);
144
-		}
145
-
146
-		return $token;
147
-	}
148
-
149
-	public function renewSessionToken(string $oldSessionId, string $sessionId): IToken {
150
-		$this->cache->clear();
151
-
152
-		$token = $this->getToken($oldSessionId);
153
-
154
-		if (!($token instanceof PublicKeyToken)) {
155
-			throw new InvalidTokenException("Invalid token type");
156
-		}
157
-
158
-		$password = null;
159
-		if (!is_null($token->getPassword())) {
160
-			$privateKey = $this->decrypt($token->getPrivateKey(), $oldSessionId);
161
-			$password = $this->decryptPassword($token->getPassword(), $privateKey);
162
-		}
163
-
164
-		$newToken = $this->generateToken(
165
-			$sessionId,
166
-			$token->getUID(),
167
-			$token->getLoginName(),
168
-			$password,
169
-			$token->getName(),
170
-			IToken::TEMPORARY_TOKEN,
171
-			$token->getRemember()
172
-		);
173
-
174
-		$this->mapper->delete($token);
175
-
176
-		return $newToken;
177
-	}
178
-
179
-	public function invalidateToken(string $token) {
180
-		$this->cache->clear();
181
-
182
-		$this->mapper->invalidate($this->hashToken($token));
183
-	}
184
-
185
-	public function invalidateTokenById(string $uid, int $id) {
186
-		$this->cache->clear();
187
-
188
-		$this->mapper->deleteById($uid, $id);
189
-	}
190
-
191
-	public function invalidateOldTokens() {
192
-		$this->cache->clear();
193
-
194
-		$olderThan = $this->time->getTime() - (int) $this->config->getSystemValue('session_lifetime', 60 * 60 * 24);
195
-		$this->logger->debug('Invalidating session tokens older than ' . date('c', $olderThan), ['app' => 'cron']);
196
-		$this->mapper->invalidateOld($olderThan, IToken::DO_NOT_REMEMBER);
197
-		$rememberThreshold = $this->time->getTime() - (int) $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
198
-		$this->logger->debug('Invalidating remembered session tokens older than ' . date('c', $rememberThreshold), ['app' => 'cron']);
199
-		$this->mapper->invalidateOld($rememberThreshold, IToken::REMEMBER);
200
-	}
201
-
202
-	public function updateToken(IToken $token) {
203
-		$this->cache->clear();
204
-
205
-		if (!($token instanceof PublicKeyToken)) {
206
-			throw new InvalidTokenException("Invalid token type");
207
-		}
208
-		$this->mapper->update($token);
209
-	}
210
-
211
-	public function updateTokenActivity(IToken $token) {
212
-		$this->cache->clear();
213
-
214
-		if (!($token instanceof PublicKeyToken)) {
215
-			throw new InvalidTokenException("Invalid token type");
216
-		}
217
-		/** @var DefaultToken $token */
218
-		$now = $this->time->getTime();
219
-		if ($token->getLastActivity() < ($now - 60)) {
220
-			// Update token only once per minute
221
-			$token->setLastActivity($now);
222
-			$this->mapper->update($token);
223
-		}
224
-	}
225
-
226
-	public function getTokenByUser(string $uid): array {
227
-		return $this->mapper->getTokenByUser($uid);
228
-	}
229
-
230
-	public function getPassword(IToken $token, string $tokenId): string {
231
-		if (!($token instanceof PublicKeyToken)) {
232
-			throw new InvalidTokenException("Invalid token type");
233
-		}
234
-
235
-		if ($token->getPassword() === null) {
236
-			throw new PasswordlessTokenException();
237
-		}
238
-
239
-		// Decrypt private key with tokenId
240
-		$privateKey = $this->decrypt($token->getPrivateKey(), $tokenId);
241
-
242
-		// Decrypt password with private key
243
-		return $this->decryptPassword($token->getPassword(), $privateKey);
244
-	}
245
-
246
-	public function setPassword(IToken $token, string $tokenId, string $password) {
247
-		$this->cache->clear();
248
-
249
-		if (!($token instanceof PublicKeyToken)) {
250
-			throw new InvalidTokenException("Invalid token type");
251
-		}
252
-
253
-		// When changing passwords all temp tokens are deleted
254
-		$this->mapper->deleteTempToken($token);
255
-
256
-		// Update the password for all tokens
257
-		$tokens = $this->mapper->getTokenByUser($token->getUID());
258
-		foreach ($tokens as $t) {
259
-			$publicKey = $t->getPublicKey();
260
-			$t->setPassword($this->encryptPassword($password, $publicKey));
261
-			$this->updateToken($t);
262
-		}
263
-	}
264
-
265
-	public function rotate(IToken $token, string $oldTokenId, string $newTokenId): IToken {
266
-		$this->cache->clear();
267
-
268
-		if (!($token instanceof PublicKeyToken)) {
269
-			throw new InvalidTokenException("Invalid token type");
270
-		}
271
-
272
-		// Decrypt private key with oldTokenId
273
-		$privateKey = $this->decrypt($token->getPrivateKey(), $oldTokenId);
274
-		// Encrypt with the new token
275
-		$token->setPrivateKey($this->encrypt($privateKey, $newTokenId));
276
-
277
-		$token->setToken($this->hashToken($newTokenId));
278
-		$this->updateToken($token);
279
-
280
-		return $token;
281
-	}
282
-
283
-	private function encrypt(string $plaintext, string $token): string {
284
-		$secret = $this->config->getSystemValue('secret');
285
-		return $this->crypto->encrypt($plaintext, $token . $secret);
286
-	}
287
-
288
-	/**
289
-	 * @throws InvalidTokenException
290
-	 */
291
-	private function decrypt(string $cipherText, string $token): string {
292
-		$secret = $this->config->getSystemValue('secret');
293
-		try {
294
-			return $this->crypto->decrypt($cipherText, $token . $secret);
295
-		} catch (\Exception $ex) {
296
-			// Delete the invalid token
297
-			$this->invalidateToken($token);
298
-			throw new InvalidTokenException("Could not decrypt token password: " . $ex->getMessage(), 0, $ex);
299
-		}
300
-	}
301
-
302
-	private function encryptPassword(string $password, string $publicKey): string {
303
-		openssl_public_encrypt($password, $encryptedPassword, $publicKey, OPENSSL_PKCS1_OAEP_PADDING);
304
-		$encryptedPassword = base64_encode($encryptedPassword);
305
-
306
-		return $encryptedPassword;
307
-	}
308
-
309
-	private function decryptPassword(string $encryptedPassword, string $privateKey): string {
310
-		$encryptedPassword = base64_decode($encryptedPassword);
311
-		openssl_private_decrypt($encryptedPassword, $password, $privateKey, OPENSSL_PKCS1_OAEP_PADDING);
312
-
313
-		return $password;
314
-	}
315
-
316
-	private function hashToken(string $token): string {
317
-		$secret = $this->config->getSystemValue('secret');
318
-		return hash('sha512', $token . $secret);
319
-	}
320
-
321
-	/**
322
-	 * Convert a DefaultToken to a publicKeyToken
323
-	 * This will also be updated directly in the Database
324
-	 * @throws \RuntimeException when OpenSSL reports a problem
325
-	 */
326
-	public function convertToken(DefaultToken $defaultToken, string $token, $password): PublicKeyToken {
327
-		$this->cache->clear();
328
-
329
-		$pkToken = $this->newToken(
330
-			$token,
331
-			$defaultToken->getUID(),
332
-			$defaultToken->getLoginName(),
333
-			$password,
334
-			$defaultToken->getName(),
335
-			$defaultToken->getType(),
336
-			$defaultToken->getRemember()
337
-		);
338
-
339
-		$pkToken->setExpires($defaultToken->getExpires());
340
-		$pkToken->setId($defaultToken->getId());
341
-
342
-		return $this->mapper->update($pkToken);
343
-	}
344
-
345
-	/**
346
-	 * @throws \RuntimeException when OpenSSL reports a problem
347
-	 */
348
-	private function newToken(string $token,
349
-							  string $uid,
350
-							  string $loginName,
351
-							  $password,
352
-							  string $name,
353
-							  int $type,
354
-							  int $remember): PublicKeyToken {
355
-		$dbToken = new PublicKeyToken();
356
-		$dbToken->setUid($uid);
357
-		$dbToken->setLoginName($loginName);
358
-
359
-		$config = array_merge([
360
-			'digest_alg' => 'sha512',
361
-			'private_key_bits' => 2048,
362
-		], $this->config->getSystemValue('openssl', []));
363
-
364
-		// Generate new key
365
-		$res = openssl_pkey_new($config);
366
-		if ($res === false) {
367
-			$this->logOpensslError();
368
-			throw new \RuntimeException('OpenSSL reported a problem');
369
-		}
370
-
371
-		if (openssl_pkey_export($res, $privateKey, null, $config) === false) {
372
-			$this->logOpensslError();
373
-			throw new \RuntimeException('OpenSSL reported a problem');
374
-		}
375
-
376
-		// Extract the public key from $res to $pubKey
377
-		$publicKey = openssl_pkey_get_details($res);
378
-		$publicKey = $publicKey['key'];
379
-
380
-		$dbToken->setPublicKey($publicKey);
381
-		$dbToken->setPrivateKey($this->encrypt($privateKey, $token));
382
-
383
-		if (!is_null($password)) {
384
-			$dbToken->setPassword($this->encryptPassword($password, $publicKey));
385
-		}
386
-
387
-		$dbToken->setName($name);
388
-		$dbToken->setToken($this->hashToken($token));
389
-		$dbToken->setType($type);
390
-		$dbToken->setRemember($remember);
391
-		$dbToken->setLastActivity($this->time->getTime());
392
-		$dbToken->setLastCheck($this->time->getTime());
393
-		$dbToken->setVersion(PublicKeyToken::VERSION);
394
-
395
-		return $dbToken;
396
-	}
397
-
398
-	public function markPasswordInvalid(IToken $token, string $tokenId) {
399
-		$this->cache->clear();
400
-
401
-		if (!($token instanceof PublicKeyToken)) {
402
-			throw new InvalidTokenException("Invalid token type");
403
-		}
404
-
405
-		$token->setPasswordInvalid(true);
406
-		$this->mapper->update($token);
407
-	}
408
-
409
-	public function updatePasswords(string $uid, string $password) {
410
-		$this->cache->clear();
411
-
412
-		if (!$this->mapper->hasExpiredTokens($uid)) {
413
-			// Nothing to do here
414
-			return;
415
-		}
416
-
417
-		// Update the password for all tokens
418
-		$tokens = $this->mapper->getTokenByUser($uid);
419
-		foreach ($tokens as $t) {
420
-			$publicKey = $t->getPublicKey();
421
-			$t->setPassword($this->encryptPassword($password, $publicKey));
422
-			$this->updateToken($t);
423
-		}
424
-	}
425
-
426
-	private function logOpensslError() {
427
-		$errors = [];
428
-		while ($error = openssl_error_string()) {
429
-			$errors[] = $error;
430
-		}
431
-		$this->logger->critical('Something is wrong with your openssl setup: ' . implode(', ', $errors));
432
-	}
45
+    /** @var PublicKeyTokenMapper */
46
+    private $mapper;
47
+
48
+    /** @var ICrypto */
49
+    private $crypto;
50
+
51
+    /** @var IConfig */
52
+    private $config;
53
+
54
+    /** @var ILogger $logger */
55
+    private $logger;
56
+
57
+    /** @var ITimeFactory $time */
58
+    private $time;
59
+
60
+    /** @var CappedMemoryCache */
61
+    private $cache;
62
+
63
+    public function __construct(PublicKeyTokenMapper $mapper,
64
+                                ICrypto $crypto,
65
+                                IConfig $config,
66
+                                ILogger $logger,
67
+                                ITimeFactory $time) {
68
+        $this->mapper = $mapper;
69
+        $this->crypto = $crypto;
70
+        $this->config = $config;
71
+        $this->logger = $logger;
72
+        $this->time = $time;
73
+
74
+        $this->cache = new CappedMemoryCache();
75
+    }
76
+
77
+    /**
78
+     * {@inheritDoc}
79
+     */
80
+    public function generateToken(string $token,
81
+                                    string $uid,
82
+                                    string $loginName,
83
+                                    $password,
84
+                                    string $name,
85
+                                    int $type = IToken::TEMPORARY_TOKEN,
86
+                                    int $remember = IToken::DO_NOT_REMEMBER): IToken {
87
+        $dbToken = $this->newToken($token, $uid, $loginName, $password, $name, $type, $remember);
88
+        $this->mapper->insert($dbToken);
89
+
90
+        // Add the token to the cache
91
+        $this->cache[$dbToken->getToken()] = $dbToken;
92
+
93
+        return $dbToken;
94
+    }
95
+
96
+    public function getToken(string $tokenId): IToken {
97
+        $tokenHash = $this->hashToken($tokenId);
98
+
99
+        if (isset($this->cache[$tokenHash])) {
100
+            $token = $this->cache[$tokenHash];
101
+        } else {
102
+            try {
103
+                $token = $this->mapper->getToken($this->hashToken($tokenId));
104
+                $this->cache[$token->getToken()] = $token;
105
+            } catch (DoesNotExistException $ex) {
106
+                throw new InvalidTokenException("Token does not exist: " . $ex->getMessage(), 0, $ex);
107
+            }
108
+        }
109
+
110
+        if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
111
+            throw new ExpiredTokenException($token);
112
+        }
113
+
114
+        if ($token->getType() === IToken::WIPE_TOKEN) {
115
+            throw new WipeTokenException($token);
116
+        }
117
+
118
+        if ($token->getPasswordInvalid() === true) {
119
+            //The password is invalid we should throw an TokenPasswordExpiredException
120
+            throw new TokenPasswordExpiredException($token);
121
+        }
122
+
123
+        return $token;
124
+    }
125
+
126
+    public function getTokenById(int $tokenId): IToken {
127
+        try {
128
+            $token = $this->mapper->getTokenById($tokenId);
129
+        } catch (DoesNotExistException $ex) {
130
+            throw new InvalidTokenException("Token with ID $tokenId does not exist: " . $ex->getMessage(), 0, $ex);
131
+        }
132
+
133
+        if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
134
+            throw new ExpiredTokenException($token);
135
+        }
136
+
137
+        if ($token->getType() === IToken::WIPE_TOKEN) {
138
+            throw new WipeTokenException($token);
139
+        }
140
+
141
+        if ($token->getPasswordInvalid() === true) {
142
+            //The password is invalid we should throw an TokenPasswordExpiredException
143
+            throw new TokenPasswordExpiredException($token);
144
+        }
145
+
146
+        return $token;
147
+    }
148
+
149
+    public function renewSessionToken(string $oldSessionId, string $sessionId): IToken {
150
+        $this->cache->clear();
151
+
152
+        $token = $this->getToken($oldSessionId);
153
+
154
+        if (!($token instanceof PublicKeyToken)) {
155
+            throw new InvalidTokenException("Invalid token type");
156
+        }
157
+
158
+        $password = null;
159
+        if (!is_null($token->getPassword())) {
160
+            $privateKey = $this->decrypt($token->getPrivateKey(), $oldSessionId);
161
+            $password = $this->decryptPassword($token->getPassword(), $privateKey);
162
+        }
163
+
164
+        $newToken = $this->generateToken(
165
+            $sessionId,
166
+            $token->getUID(),
167
+            $token->getLoginName(),
168
+            $password,
169
+            $token->getName(),
170
+            IToken::TEMPORARY_TOKEN,
171
+            $token->getRemember()
172
+        );
173
+
174
+        $this->mapper->delete($token);
175
+
176
+        return $newToken;
177
+    }
178
+
179
+    public function invalidateToken(string $token) {
180
+        $this->cache->clear();
181
+
182
+        $this->mapper->invalidate($this->hashToken($token));
183
+    }
184
+
185
+    public function invalidateTokenById(string $uid, int $id) {
186
+        $this->cache->clear();
187
+
188
+        $this->mapper->deleteById($uid, $id);
189
+    }
190
+
191
+    public function invalidateOldTokens() {
192
+        $this->cache->clear();
193
+
194
+        $olderThan = $this->time->getTime() - (int) $this->config->getSystemValue('session_lifetime', 60 * 60 * 24);
195
+        $this->logger->debug('Invalidating session tokens older than ' . date('c', $olderThan), ['app' => 'cron']);
196
+        $this->mapper->invalidateOld($olderThan, IToken::DO_NOT_REMEMBER);
197
+        $rememberThreshold = $this->time->getTime() - (int) $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
198
+        $this->logger->debug('Invalidating remembered session tokens older than ' . date('c', $rememberThreshold), ['app' => 'cron']);
199
+        $this->mapper->invalidateOld($rememberThreshold, IToken::REMEMBER);
200
+    }
201
+
202
+    public function updateToken(IToken $token) {
203
+        $this->cache->clear();
204
+
205
+        if (!($token instanceof PublicKeyToken)) {
206
+            throw new InvalidTokenException("Invalid token type");
207
+        }
208
+        $this->mapper->update($token);
209
+    }
210
+
211
+    public function updateTokenActivity(IToken $token) {
212
+        $this->cache->clear();
213
+
214
+        if (!($token instanceof PublicKeyToken)) {
215
+            throw new InvalidTokenException("Invalid token type");
216
+        }
217
+        /** @var DefaultToken $token */
218
+        $now = $this->time->getTime();
219
+        if ($token->getLastActivity() < ($now - 60)) {
220
+            // Update token only once per minute
221
+            $token->setLastActivity($now);
222
+            $this->mapper->update($token);
223
+        }
224
+    }
225
+
226
+    public function getTokenByUser(string $uid): array {
227
+        return $this->mapper->getTokenByUser($uid);
228
+    }
229
+
230
+    public function getPassword(IToken $token, string $tokenId): string {
231
+        if (!($token instanceof PublicKeyToken)) {
232
+            throw new InvalidTokenException("Invalid token type");
233
+        }
234
+
235
+        if ($token->getPassword() === null) {
236
+            throw new PasswordlessTokenException();
237
+        }
238
+
239
+        // Decrypt private key with tokenId
240
+        $privateKey = $this->decrypt($token->getPrivateKey(), $tokenId);
241
+
242
+        // Decrypt password with private key
243
+        return $this->decryptPassword($token->getPassword(), $privateKey);
244
+    }
245
+
246
+    public function setPassword(IToken $token, string $tokenId, string $password) {
247
+        $this->cache->clear();
248
+
249
+        if (!($token instanceof PublicKeyToken)) {
250
+            throw new InvalidTokenException("Invalid token type");
251
+        }
252
+
253
+        // When changing passwords all temp tokens are deleted
254
+        $this->mapper->deleteTempToken($token);
255
+
256
+        // Update the password for all tokens
257
+        $tokens = $this->mapper->getTokenByUser($token->getUID());
258
+        foreach ($tokens as $t) {
259
+            $publicKey = $t->getPublicKey();
260
+            $t->setPassword($this->encryptPassword($password, $publicKey));
261
+            $this->updateToken($t);
262
+        }
263
+    }
264
+
265
+    public function rotate(IToken $token, string $oldTokenId, string $newTokenId): IToken {
266
+        $this->cache->clear();
267
+
268
+        if (!($token instanceof PublicKeyToken)) {
269
+            throw new InvalidTokenException("Invalid token type");
270
+        }
271
+
272
+        // Decrypt private key with oldTokenId
273
+        $privateKey = $this->decrypt($token->getPrivateKey(), $oldTokenId);
274
+        // Encrypt with the new token
275
+        $token->setPrivateKey($this->encrypt($privateKey, $newTokenId));
276
+
277
+        $token->setToken($this->hashToken($newTokenId));
278
+        $this->updateToken($token);
279
+
280
+        return $token;
281
+    }
282
+
283
+    private function encrypt(string $plaintext, string $token): string {
284
+        $secret = $this->config->getSystemValue('secret');
285
+        return $this->crypto->encrypt($plaintext, $token . $secret);
286
+    }
287
+
288
+    /**
289
+     * @throws InvalidTokenException
290
+     */
291
+    private function decrypt(string $cipherText, string $token): string {
292
+        $secret = $this->config->getSystemValue('secret');
293
+        try {
294
+            return $this->crypto->decrypt($cipherText, $token . $secret);
295
+        } catch (\Exception $ex) {
296
+            // Delete the invalid token
297
+            $this->invalidateToken($token);
298
+            throw new InvalidTokenException("Could not decrypt token password: " . $ex->getMessage(), 0, $ex);
299
+        }
300
+    }
301
+
302
+    private function encryptPassword(string $password, string $publicKey): string {
303
+        openssl_public_encrypt($password, $encryptedPassword, $publicKey, OPENSSL_PKCS1_OAEP_PADDING);
304
+        $encryptedPassword = base64_encode($encryptedPassword);
305
+
306
+        return $encryptedPassword;
307
+    }
308
+
309
+    private function decryptPassword(string $encryptedPassword, string $privateKey): string {
310
+        $encryptedPassword = base64_decode($encryptedPassword);
311
+        openssl_private_decrypt($encryptedPassword, $password, $privateKey, OPENSSL_PKCS1_OAEP_PADDING);
312
+
313
+        return $password;
314
+    }
315
+
316
+    private function hashToken(string $token): string {
317
+        $secret = $this->config->getSystemValue('secret');
318
+        return hash('sha512', $token . $secret);
319
+    }
320
+
321
+    /**
322
+     * Convert a DefaultToken to a publicKeyToken
323
+     * This will also be updated directly in the Database
324
+     * @throws \RuntimeException when OpenSSL reports a problem
325
+     */
326
+    public function convertToken(DefaultToken $defaultToken, string $token, $password): PublicKeyToken {
327
+        $this->cache->clear();
328
+
329
+        $pkToken = $this->newToken(
330
+            $token,
331
+            $defaultToken->getUID(),
332
+            $defaultToken->getLoginName(),
333
+            $password,
334
+            $defaultToken->getName(),
335
+            $defaultToken->getType(),
336
+            $defaultToken->getRemember()
337
+        );
338
+
339
+        $pkToken->setExpires($defaultToken->getExpires());
340
+        $pkToken->setId($defaultToken->getId());
341
+
342
+        return $this->mapper->update($pkToken);
343
+    }
344
+
345
+    /**
346
+     * @throws \RuntimeException when OpenSSL reports a problem
347
+     */
348
+    private function newToken(string $token,
349
+                                string $uid,
350
+                                string $loginName,
351
+                                $password,
352
+                                string $name,
353
+                                int $type,
354
+                                int $remember): PublicKeyToken {
355
+        $dbToken = new PublicKeyToken();
356
+        $dbToken->setUid($uid);
357
+        $dbToken->setLoginName($loginName);
358
+
359
+        $config = array_merge([
360
+            'digest_alg' => 'sha512',
361
+            'private_key_bits' => 2048,
362
+        ], $this->config->getSystemValue('openssl', []));
363
+
364
+        // Generate new key
365
+        $res = openssl_pkey_new($config);
366
+        if ($res === false) {
367
+            $this->logOpensslError();
368
+            throw new \RuntimeException('OpenSSL reported a problem');
369
+        }
370
+
371
+        if (openssl_pkey_export($res, $privateKey, null, $config) === false) {
372
+            $this->logOpensslError();
373
+            throw new \RuntimeException('OpenSSL reported a problem');
374
+        }
375
+
376
+        // Extract the public key from $res to $pubKey
377
+        $publicKey = openssl_pkey_get_details($res);
378
+        $publicKey = $publicKey['key'];
379
+
380
+        $dbToken->setPublicKey($publicKey);
381
+        $dbToken->setPrivateKey($this->encrypt($privateKey, $token));
382
+
383
+        if (!is_null($password)) {
384
+            $dbToken->setPassword($this->encryptPassword($password, $publicKey));
385
+        }
386
+
387
+        $dbToken->setName($name);
388
+        $dbToken->setToken($this->hashToken($token));
389
+        $dbToken->setType($type);
390
+        $dbToken->setRemember($remember);
391
+        $dbToken->setLastActivity($this->time->getTime());
392
+        $dbToken->setLastCheck($this->time->getTime());
393
+        $dbToken->setVersion(PublicKeyToken::VERSION);
394
+
395
+        return $dbToken;
396
+    }
397
+
398
+    public function markPasswordInvalid(IToken $token, string $tokenId) {
399
+        $this->cache->clear();
400
+
401
+        if (!($token instanceof PublicKeyToken)) {
402
+            throw new InvalidTokenException("Invalid token type");
403
+        }
404
+
405
+        $token->setPasswordInvalid(true);
406
+        $this->mapper->update($token);
407
+    }
408
+
409
+    public function updatePasswords(string $uid, string $password) {
410
+        $this->cache->clear();
411
+
412
+        if (!$this->mapper->hasExpiredTokens($uid)) {
413
+            // Nothing to do here
414
+            return;
415
+        }
416
+
417
+        // Update the password for all tokens
418
+        $tokens = $this->mapper->getTokenByUser($uid);
419
+        foreach ($tokens as $t) {
420
+            $publicKey = $t->getPublicKey();
421
+            $t->setPassword($this->encryptPassword($password, $publicKey));
422
+            $this->updateToken($t);
423
+        }
424
+    }
425
+
426
+    private function logOpensslError() {
427
+        $errors = [];
428
+        while ($error = openssl_error_string()) {
429
+            $errors[] = $error;
430
+        }
431
+        $this->logger->critical('Something is wrong with your openssl setup: ' . implode(', ', $errors));
432
+    }
433 433
 }
Please login to merge, or discard this patch.
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -103,11 +103,11 @@  discard block
 block discarded – undo
103 103
 				$token = $this->mapper->getToken($this->hashToken($tokenId));
104 104
 				$this->cache[$token->getToken()] = $token;
105 105
 			} catch (DoesNotExistException $ex) {
106
-				throw new InvalidTokenException("Token does not exist: " . $ex->getMessage(), 0, $ex);
106
+				throw new InvalidTokenException("Token does not exist: ".$ex->getMessage(), 0, $ex);
107 107
 			}
108 108
 		}
109 109
 
110
-		if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
110
+		if ((int) $token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
111 111
 			throw new ExpiredTokenException($token);
112 112
 		}
113 113
 
@@ -127,10 +127,10 @@  discard block
 block discarded – undo
127 127
 		try {
128 128
 			$token = $this->mapper->getTokenById($tokenId);
129 129
 		} catch (DoesNotExistException $ex) {
130
-			throw new InvalidTokenException("Token with ID $tokenId does not exist: " . $ex->getMessage(), 0, $ex);
130
+			throw new InvalidTokenException("Token with ID $tokenId does not exist: ".$ex->getMessage(), 0, $ex);
131 131
 		}
132 132
 
133
-		if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
133
+		if ((int) $token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
134 134
 			throw new ExpiredTokenException($token);
135 135
 		}
136 136
 
@@ -192,10 +192,10 @@  discard block
 block discarded – undo
192 192
 		$this->cache->clear();
193 193
 
194 194
 		$olderThan = $this->time->getTime() - (int) $this->config->getSystemValue('session_lifetime', 60 * 60 * 24);
195
-		$this->logger->debug('Invalidating session tokens older than ' . date('c', $olderThan), ['app' => 'cron']);
195
+		$this->logger->debug('Invalidating session tokens older than '.date('c', $olderThan), ['app' => 'cron']);
196 196
 		$this->mapper->invalidateOld($olderThan, IToken::DO_NOT_REMEMBER);
197 197
 		$rememberThreshold = $this->time->getTime() - (int) $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
198
-		$this->logger->debug('Invalidating remembered session tokens older than ' . date('c', $rememberThreshold), ['app' => 'cron']);
198
+		$this->logger->debug('Invalidating remembered session tokens older than '.date('c', $rememberThreshold), ['app' => 'cron']);
199 199
 		$this->mapper->invalidateOld($rememberThreshold, IToken::REMEMBER);
200 200
 	}
201 201
 
@@ -282,7 +282,7 @@  discard block
 block discarded – undo
282 282
 
283 283
 	private function encrypt(string $plaintext, string $token): string {
284 284
 		$secret = $this->config->getSystemValue('secret');
285
-		return $this->crypto->encrypt($plaintext, $token . $secret);
285
+		return $this->crypto->encrypt($plaintext, $token.$secret);
286 286
 	}
287 287
 
288 288
 	/**
@@ -291,11 +291,11 @@  discard block
 block discarded – undo
291 291
 	private function decrypt(string $cipherText, string $token): string {
292 292
 		$secret = $this->config->getSystemValue('secret');
293 293
 		try {
294
-			return $this->crypto->decrypt($cipherText, $token . $secret);
294
+			return $this->crypto->decrypt($cipherText, $token.$secret);
295 295
 		} catch (\Exception $ex) {
296 296
 			// Delete the invalid token
297 297
 			$this->invalidateToken($token);
298
-			throw new InvalidTokenException("Could not decrypt token password: " . $ex->getMessage(), 0, $ex);
298
+			throw new InvalidTokenException("Could not decrypt token password: ".$ex->getMessage(), 0, $ex);
299 299
 		}
300 300
 	}
301 301
 
@@ -315,7 +315,7 @@  discard block
 block discarded – undo
315 315
 
316 316
 	private function hashToken(string $token): string {
317 317
 		$secret = $this->config->getSystemValue('secret');
318
-		return hash('sha512', $token . $secret);
318
+		return hash('sha512', $token.$secret);
319 319
 	}
320 320
 
321 321
 	/**
@@ -428,6 +428,6 @@  discard block
 block discarded – undo
428 428
 		while ($error = openssl_error_string()) {
429 429
 			$errors[] = $error;
430 430
 		}
431
-		$this->logger->critical('Something is wrong with your openssl setup: ' . implode(', ', $errors));
431
+		$this->logger->critical('Something is wrong with your openssl setup: '.implode(', ', $errors));
432 432
 	}
433 433
 }
Please login to merge, or discard this patch.
lib/private/User/Session.php 2 patches
Indentation   +920 added lines, -920 removed lines patch added patch discarded remove patch
@@ -90,924 +90,924 @@
 block discarded – undo
90 90
  */
91 91
 class Session implements IUserSession, Emitter {
92 92
 
93
-	/** @var Manager|PublicEmitter $manager */
94
-	private $manager;
95
-
96
-	/** @var ISession $session */
97
-	private $session;
98
-
99
-	/** @var ITimeFactory */
100
-	private $timeFactory;
101
-
102
-	/** @var IProvider */
103
-	private $tokenProvider;
104
-
105
-	/** @var IConfig */
106
-	private $config;
107
-
108
-	/** @var User $activeUser */
109
-	protected $activeUser;
110
-
111
-	/** @var ISecureRandom */
112
-	private $random;
113
-
114
-	/** @var ILockdownManager  */
115
-	private $lockdownManager;
116
-
117
-	/** @var ILogger */
118
-	private $logger;
119
-	/** @var IEventDispatcher */
120
-	private $dispatcher;
121
-
122
-	/**
123
-	 * @param Manager $manager
124
-	 * @param ISession $session
125
-	 * @param ITimeFactory $timeFactory
126
-	 * @param IProvider $tokenProvider
127
-	 * @param IConfig $config
128
-	 * @param ISecureRandom $random
129
-	 * @param ILockdownManager $lockdownManager
130
-	 * @param ILogger $logger
131
-	 */
132
-	public function __construct(Manager $manager,
133
-								ISession $session,
134
-								ITimeFactory $timeFactory,
135
-								$tokenProvider,
136
-								IConfig $config,
137
-								ISecureRandom $random,
138
-								ILockdownManager $lockdownManager,
139
-								ILogger $logger,
140
-								IEventDispatcher $dispatcher
141
-	) {
142
-		$this->manager = $manager;
143
-		$this->session = $session;
144
-		$this->timeFactory = $timeFactory;
145
-		$this->tokenProvider = $tokenProvider;
146
-		$this->config = $config;
147
-		$this->random = $random;
148
-		$this->lockdownManager = $lockdownManager;
149
-		$this->logger = $logger;
150
-		$this->dispatcher = $dispatcher;
151
-	}
152
-
153
-	/**
154
-	 * @param IProvider $provider
155
-	 */
156
-	public function setTokenProvider(IProvider $provider) {
157
-		$this->tokenProvider = $provider;
158
-	}
159
-
160
-	/**
161
-	 * @param string $scope
162
-	 * @param string $method
163
-	 * @param callable $callback
164
-	 */
165
-	public function listen($scope, $method, callable $callback) {
166
-		$this->manager->listen($scope, $method, $callback);
167
-	}
168
-
169
-	/**
170
-	 * @param string $scope optional
171
-	 * @param string $method optional
172
-	 * @param callable $callback optional
173
-	 */
174
-	public function removeListener($scope = null, $method = null, callable $callback = null) {
175
-		$this->manager->removeListener($scope, $method, $callback);
176
-	}
177
-
178
-	/**
179
-	 * get the manager object
180
-	 *
181
-	 * @return Manager|PublicEmitter
182
-	 */
183
-	public function getManager() {
184
-		return $this->manager;
185
-	}
186
-
187
-	/**
188
-	 * get the session object
189
-	 *
190
-	 * @return ISession
191
-	 */
192
-	public function getSession() {
193
-		return $this->session;
194
-	}
195
-
196
-	/**
197
-	 * set the session object
198
-	 *
199
-	 * @param ISession $session
200
-	 */
201
-	public function setSession(ISession $session) {
202
-		if ($this->session instanceof ISession) {
203
-			$this->session->close();
204
-		}
205
-		$this->session = $session;
206
-		$this->activeUser = null;
207
-	}
208
-
209
-	/**
210
-	 * set the currently active user
211
-	 *
212
-	 * @param IUser|null $user
213
-	 */
214
-	public function setUser($user) {
215
-		if (is_null($user)) {
216
-			$this->session->remove('user_id');
217
-		} else {
218
-			$this->session->set('user_id', $user->getUID());
219
-		}
220
-		$this->activeUser = $user;
221
-	}
222
-
223
-	/**
224
-	 * get the current active user
225
-	 *
226
-	 * @return IUser|null Current user, otherwise null
227
-	 */
228
-	public function getUser() {
229
-		// FIXME: This is a quick'n dirty work-around for the incognito mode as
230
-		// described at https://github.com/owncloud/core/pull/12912#issuecomment-67391155
231
-		if (OC_User::isIncognitoMode()) {
232
-			return null;
233
-		}
234
-		if (is_null($this->activeUser)) {
235
-			$uid = $this->session->get('user_id');
236
-			if (is_null($uid)) {
237
-				return null;
238
-			}
239
-			$this->activeUser = $this->manager->get($uid);
240
-			if (is_null($this->activeUser)) {
241
-				return null;
242
-			}
243
-			$this->validateSession();
244
-		}
245
-		return $this->activeUser;
246
-	}
247
-
248
-	/**
249
-	 * Validate whether the current session is valid
250
-	 *
251
-	 * - For token-authenticated clients, the token validity is checked
252
-	 * - For browsers, the session token validity is checked
253
-	 */
254
-	protected function validateSession() {
255
-		$token = null;
256
-		$appPassword = $this->session->get('app_password');
257
-
258
-		if (is_null($appPassword)) {
259
-			try {
260
-				$token = $this->session->getId();
261
-			} catch (SessionNotAvailableException $ex) {
262
-				return;
263
-			}
264
-		} else {
265
-			$token = $appPassword;
266
-		}
267
-
268
-		if (!$this->validateToken($token)) {
269
-			// Session was invalidated
270
-			$this->logout();
271
-		}
272
-	}
273
-
274
-	/**
275
-	 * Checks whether the user is logged in
276
-	 *
277
-	 * @return bool if logged in
278
-	 */
279
-	public function isLoggedIn() {
280
-		$user = $this->getUser();
281
-		if (is_null($user)) {
282
-			return false;
283
-		}
284
-
285
-		return $user->isEnabled();
286
-	}
287
-
288
-	/**
289
-	 * set the login name
290
-	 *
291
-	 * @param string|null $loginName for the logged in user
292
-	 */
293
-	public function setLoginName($loginName) {
294
-		if (is_null($loginName)) {
295
-			$this->session->remove('loginname');
296
-		} else {
297
-			$this->session->set('loginname', $loginName);
298
-		}
299
-	}
300
-
301
-	/**
302
-	 * get the login name of the current user
303
-	 *
304
-	 * @return string
305
-	 */
306
-	public function getLoginName() {
307
-		if ($this->activeUser) {
308
-			return $this->session->get('loginname');
309
-		}
310
-
311
-		$uid = $this->session->get('user_id');
312
-		if ($uid) {
313
-			$this->activeUser = $this->manager->get($uid);
314
-			return $this->session->get('loginname');
315
-		}
316
-
317
-		return null;
318
-	}
319
-
320
-	/**
321
-	 * @return null|string
322
-	 */
323
-	public function getImpersonatingUserID(): ?string {
324
-		return $this->session->get('oldUserId');
325
-	}
326
-
327
-	public function setImpersonatingUserID(bool $useCurrentUser = true): void {
328
-		if ($useCurrentUser === false) {
329
-			$this->session->remove('oldUserId');
330
-			return;
331
-		}
332
-
333
-		$currentUser = $this->getUser();
334
-
335
-		if ($currentUser === null) {
336
-			throw new \OC\User\NoUserException();
337
-		}
338
-		$this->session->set('oldUserId', $currentUser->getUID());
339
-	}
340
-	/**
341
-	 * set the token id
342
-	 *
343
-	 * @param int|null $token that was used to log in
344
-	 */
345
-	protected function setToken($token) {
346
-		if ($token === null) {
347
-			$this->session->remove('token-id');
348
-		} else {
349
-			$this->session->set('token-id', $token);
350
-		}
351
-	}
352
-
353
-	/**
354
-	 * try to log in with the provided credentials
355
-	 *
356
-	 * @param string $uid
357
-	 * @param string $password
358
-	 * @return boolean|null
359
-	 * @throws LoginException
360
-	 */
361
-	public function login($uid, $password) {
362
-		$this->session->regenerateId();
363
-		if ($this->validateToken($password, $uid)) {
364
-			return $this->loginWithToken($password);
365
-		}
366
-		return $this->loginWithPassword($uid, $password);
367
-	}
368
-
369
-	/**
370
-	 * @param IUser $user
371
-	 * @param array $loginDetails
372
-	 * @param bool $regenerateSessionId
373
-	 * @return true returns true if login successful or an exception otherwise
374
-	 * @throws LoginException
375
-	 */
376
-	public function completeLogin(IUser $user, array $loginDetails, $regenerateSessionId = true) {
377
-		if (!$user->isEnabled()) {
378
-			// disabled users can not log in
379
-			// injecting l10n does not work - there is a circular dependency between session and \OCP\L10N\IFactory
380
-			$message = \OC::$server->getL10N('lib')->t('User disabled');
381
-			throw new LoginException($message);
382
-		}
383
-
384
-		if ($regenerateSessionId) {
385
-			$this->session->regenerateId();
386
-		}
387
-
388
-		$this->setUser($user);
389
-		$this->setLoginName($loginDetails['loginName']);
390
-
391
-		$isToken = isset($loginDetails['token']) && $loginDetails['token'] instanceof IToken;
392
-		if ($isToken) {
393
-			$this->setToken($loginDetails['token']->getId());
394
-			$this->lockdownManager->setToken($loginDetails['token']);
395
-			$firstTimeLogin = false;
396
-		} else {
397
-			$this->setToken(null);
398
-			$firstTimeLogin = $user->updateLastLoginTimestamp();
399
-		}
400
-
401
-		$this->dispatcher->dispatchTyped(new PostLoginEvent(
402
-			$user,
403
-			$loginDetails['password'],
404
-			$isToken
405
-		));
406
-		$this->manager->emit('\OC\User', 'postLogin', [
407
-			$user,
408
-			$loginDetails['password'],
409
-			$isToken,
410
-		]);
411
-		if ($this->isLoggedIn()) {
412
-			$this->prepareUserLogin($firstTimeLogin, $regenerateSessionId);
413
-			return true;
414
-		}
415
-
416
-		$message = \OC::$server->getL10N('lib')->t('Login canceled by app');
417
-		throw new LoginException($message);
418
-	}
419
-
420
-	/**
421
-	 * Tries to log in a client
422
-	 *
423
-	 * Checks token auth enforced
424
-	 * Checks 2FA enabled
425
-	 *
426
-	 * @param string $user
427
-	 * @param string $password
428
-	 * @param IRequest $request
429
-	 * @param OC\Security\Bruteforce\Throttler $throttler
430
-	 * @throws LoginException
431
-	 * @throws PasswordLoginForbiddenException
432
-	 * @return boolean
433
-	 */
434
-	public function logClientIn($user,
435
-								$password,
436
-								IRequest $request,
437
-								OC\Security\Bruteforce\Throttler $throttler) {
438
-		$currentDelay = $throttler->sleepDelay($request->getRemoteAddress(), 'login');
439
-
440
-		if ($this->manager instanceof PublicEmitter) {
441
-			$this->manager->emit('\OC\User', 'preLogin', [$user, $password]);
442
-		}
443
-
444
-		try {
445
-			$isTokenPassword = $this->isTokenPassword($password);
446
-		} catch (ExpiredTokenException $e) {
447
-			// Just return on an expired token no need to check further or record a failed login
448
-			return false;
449
-		}
450
-
451
-		if (!$isTokenPassword && $this->isTokenAuthEnforced()) {
452
-			throw new PasswordLoginForbiddenException();
453
-		}
454
-		if (!$isTokenPassword && $this->isTwoFactorEnforced($user)) {
455
-			throw new PasswordLoginForbiddenException();
456
-		}
457
-
458
-		// Try to login with this username and password
459
-		if (!$this->login($user, $password)) {
460
-
461
-			// Failed, maybe the user used their email address
462
-			$users = $this->manager->getByEmail($user);
463
-			if (!(\count($users) === 1 && $this->login($users[0]->getUID(), $password))) {
464
-				$this->logger->warning('Login failed: \'' . $user . '\' (Remote IP: \'' . \OC::$server->getRequest()->getRemoteAddress() . '\')', ['app' => 'core']);
465
-
466
-				$throttler->registerAttempt('login', $request->getRemoteAddress(), ['user' => $user]);
467
-
468
-				$this->dispatcher->dispatchTyped(new OC\Authentication\Events\LoginFailed($user));
469
-
470
-				if ($currentDelay === 0) {
471
-					$throttler->sleepDelay($request->getRemoteAddress(), 'login');
472
-				}
473
-				return false;
474
-			}
475
-		}
476
-
477
-		if ($isTokenPassword) {
478
-			$this->session->set('app_password', $password);
479
-		} elseif ($this->supportsCookies($request)) {
480
-			// Password login, but cookies supported -> create (browser) session token
481
-			$this->createSessionToken($request, $this->getUser()->getUID(), $user, $password);
482
-		}
483
-
484
-		return true;
485
-	}
486
-
487
-	protected function supportsCookies(IRequest $request) {
488
-		if (!is_null($request->getCookie('cookie_test'))) {
489
-			return true;
490
-		}
491
-		setcookie('cookie_test', 'test', $this->timeFactory->getTime() + 3600);
492
-		return false;
493
-	}
494
-
495
-	private function isTokenAuthEnforced() {
496
-		return $this->config->getSystemValue('token_auth_enforced', false);
497
-	}
498
-
499
-	protected function isTwoFactorEnforced($username) {
500
-		Util::emitHook(
501
-			'\OCA\Files_Sharing\API\Server2Server',
502
-			'preLoginNameUsedAsUserName',
503
-			['uid' => &$username]
504
-		);
505
-		$user = $this->manager->get($username);
506
-		if (is_null($user)) {
507
-			$users = $this->manager->getByEmail($username);
508
-			if (empty($users)) {
509
-				return false;
510
-			}
511
-			if (count($users) !== 1) {
512
-				return true;
513
-			}
514
-			$user = $users[0];
515
-		}
516
-		// DI not possible due to cyclic dependencies :'-/
517
-		return OC::$server->getTwoFactorAuthManager()->isTwoFactorAuthenticated($user);
518
-	}
519
-
520
-	/**
521
-	 * Check if the given 'password' is actually a device token
522
-	 *
523
-	 * @param string $password
524
-	 * @return boolean
525
-	 * @throws ExpiredTokenException
526
-	 */
527
-	public function isTokenPassword($password) {
528
-		try {
529
-			$this->tokenProvider->getToken($password);
530
-			return true;
531
-		} catch (ExpiredTokenException $e) {
532
-			throw $e;
533
-		} catch (InvalidTokenException $ex) {
534
-			$this->logger->logException($ex, [
535
-				'level' => ILogger::DEBUG,
536
-				'message' => 'Token is not valid: ' . $ex->getMessage(),
537
-			]);
538
-			return false;
539
-		}
540
-	}
541
-
542
-	protected function prepareUserLogin($firstTimeLogin, $refreshCsrfToken = true) {
543
-		if ($refreshCsrfToken) {
544
-			// TODO: mock/inject/use non-static
545
-			// Refresh the token
546
-			\OC::$server->getCsrfTokenManager()->refreshToken();
547
-		}
548
-
549
-		//we need to pass the user name, which may differ from login name
550
-		$user = $this->getUser()->getUID();
551
-		OC_Util::setupFS($user);
552
-
553
-		if ($firstTimeLogin) {
554
-			// TODO: lock necessary?
555
-			//trigger creation of user home and /files folder
556
-			$userFolder = \OC::$server->getUserFolder($user);
557
-
558
-			try {
559
-				// copy skeleton
560
-				\OC_Util::copySkeleton($user, $userFolder);
561
-			} catch (NotPermittedException $ex) {
562
-				// read only uses
563
-			}
564
-
565
-			// trigger any other initialization
566
-			\OC::$server->getEventDispatcher()->dispatch(IUser::class . '::firstLogin', new GenericEvent($this->getUser()));
567
-		}
568
-	}
569
-
570
-	/**
571
-	 * Tries to login the user with HTTP Basic Authentication
572
-	 *
573
-	 * @todo do not allow basic auth if the user is 2FA enforced
574
-	 * @param IRequest $request
575
-	 * @param OC\Security\Bruteforce\Throttler $throttler
576
-	 * @return boolean if the login was successful
577
-	 */
578
-	public function tryBasicAuthLogin(IRequest $request,
579
-									  OC\Security\Bruteforce\Throttler $throttler) {
580
-		if (!empty($request->server['PHP_AUTH_USER']) && !empty($request->server['PHP_AUTH_PW'])) {
581
-			try {
582
-				if ($this->logClientIn($request->server['PHP_AUTH_USER'], $request->server['PHP_AUTH_PW'], $request, $throttler)) {
583
-					/**
584
-					 * Add DAV authenticated. This should in an ideal world not be
585
-					 * necessary but the iOS App reads cookies from anywhere instead
586
-					 * only the DAV endpoint.
587
-					 * This makes sure that the cookies will be valid for the whole scope
588
-					 * @see https://github.com/owncloud/core/issues/22893
589
-					 */
590
-					$this->session->set(
591
-						Auth::DAV_AUTHENTICATED, $this->getUser()->getUID()
592
-					);
593
-
594
-					// Set the last-password-confirm session to make the sudo mode work
595
-					$this->session->set('last-password-confirm', $this->timeFactory->getTime());
596
-
597
-					return true;
598
-				}
599
-			} catch (PasswordLoginForbiddenException $ex) {
600
-				// Nothing to do
601
-			}
602
-		}
603
-		return false;
604
-	}
605
-
606
-	/**
607
-	 * Log an user in via login name and password
608
-	 *
609
-	 * @param string $uid
610
-	 * @param string $password
611
-	 * @return boolean
612
-	 * @throws LoginException if an app canceld the login process or the user is not enabled
613
-	 */
614
-	private function loginWithPassword($uid, $password) {
615
-		$user = $this->manager->checkPasswordNoLogging($uid, $password);
616
-		if ($user === false) {
617
-			// Password check failed
618
-			return false;
619
-		}
620
-
621
-		return $this->completeLogin($user, ['loginName' => $uid, 'password' => $password], false);
622
-	}
623
-
624
-	/**
625
-	 * Log an user in with a given token (id)
626
-	 *
627
-	 * @param string $token
628
-	 * @return boolean
629
-	 * @throws LoginException if an app canceled the login process or the user is not enabled
630
-	 */
631
-	private function loginWithToken($token) {
632
-		try {
633
-			$dbToken = $this->tokenProvider->getToken($token);
634
-		} catch (InvalidTokenException $ex) {
635
-			return false;
636
-		}
637
-		$uid = $dbToken->getUID();
638
-
639
-		// When logging in with token, the password must be decrypted first before passing to login hook
640
-		$password = '';
641
-		try {
642
-			$password = $this->tokenProvider->getPassword($dbToken, $token);
643
-		} catch (PasswordlessTokenException $ex) {
644
-			// Ignore and use empty string instead
645
-		}
646
-
647
-		$this->manager->emit('\OC\User', 'preLogin', [$uid, $password]);
648
-
649
-		$user = $this->manager->get($uid);
650
-		if (is_null($user)) {
651
-			// user does not exist
652
-			return false;
653
-		}
654
-
655
-		return $this->completeLogin(
656
-			$user,
657
-			[
658
-				'loginName' => $dbToken->getLoginName(),
659
-				'password' => $password,
660
-				'token' => $dbToken
661
-			],
662
-			false);
663
-	}
664
-
665
-	/**
666
-	 * Create a new session token for the given user credentials
667
-	 *
668
-	 * @param IRequest $request
669
-	 * @param string $uid user UID
670
-	 * @param string $loginName login name
671
-	 * @param string $password
672
-	 * @param int $remember
673
-	 * @return boolean
674
-	 */
675
-	public function createSessionToken(IRequest $request, $uid, $loginName, $password = null, $remember = IToken::DO_NOT_REMEMBER) {
676
-		if (is_null($this->manager->get($uid))) {
677
-			// User does not exist
678
-			return false;
679
-		}
680
-		$name = isset($request->server['HTTP_USER_AGENT']) ? $request->server['HTTP_USER_AGENT'] : 'unknown browser';
681
-		try {
682
-			$sessionId = $this->session->getId();
683
-			$pwd = $this->getPassword($password);
684
-			// Make sure the current sessionId has no leftover tokens
685
-			$this->tokenProvider->invalidateToken($sessionId);
686
-			$this->tokenProvider->generateToken($sessionId, $uid, $loginName, $pwd, $name, IToken::TEMPORARY_TOKEN, $remember);
687
-			return true;
688
-		} catch (SessionNotAvailableException $ex) {
689
-			// This can happen with OCC, where a memory session is used
690
-			// if a memory session is used, we shouldn't create a session token anyway
691
-			return false;
692
-		}
693
-	}
694
-
695
-	/**
696
-	 * Checks if the given password is a token.
697
-	 * If yes, the password is extracted from the token.
698
-	 * If no, the same password is returned.
699
-	 *
700
-	 * @param string $password either the login password or a device token
701
-	 * @return string|null the password or null if none was set in the token
702
-	 */
703
-	private function getPassword($password) {
704
-		if (is_null($password)) {
705
-			// This is surely no token ;-)
706
-			return null;
707
-		}
708
-		try {
709
-			$token = $this->tokenProvider->getToken($password);
710
-			try {
711
-				return $this->tokenProvider->getPassword($token, $password);
712
-			} catch (PasswordlessTokenException $ex) {
713
-				return null;
714
-			}
715
-		} catch (InvalidTokenException $ex) {
716
-			return $password;
717
-		}
718
-	}
719
-
720
-	/**
721
-	 * @param IToken $dbToken
722
-	 * @param string $token
723
-	 * @return boolean
724
-	 */
725
-	private function checkTokenCredentials(IToken $dbToken, $token) {
726
-		// Check whether login credentials are still valid and the user was not disabled
727
-		// This check is performed each 5 minutes
728
-		$lastCheck = $dbToken->getLastCheck() ? : 0;
729
-		$now = $this->timeFactory->getTime();
730
-		if ($lastCheck > ($now - 60 * 5)) {
731
-			// Checked performed recently, nothing to do now
732
-			return true;
733
-		}
734
-
735
-		try {
736
-			$pwd = $this->tokenProvider->getPassword($dbToken, $token);
737
-		} catch (InvalidTokenException $ex) {
738
-			// An invalid token password was used -> log user out
739
-			return false;
740
-		} catch (PasswordlessTokenException $ex) {
741
-			// Token has no password
742
-
743
-			if (!is_null($this->activeUser) && !$this->activeUser->isEnabled()) {
744
-				$this->tokenProvider->invalidateToken($token);
745
-				return false;
746
-			}
747
-
748
-			$dbToken->setLastCheck($now);
749
-			return true;
750
-		}
751
-
752
-		// Invalidate token if the user is no longer active
753
-		if (!is_null($this->activeUser) && !$this->activeUser->isEnabled()) {
754
-			$this->tokenProvider->invalidateToken($token);
755
-			return false;
756
-		}
757
-
758
-		// If the token password is no longer valid mark it as such
759
-		if ($this->manager->checkPassword($dbToken->getLoginName(), $pwd) === false) {
760
-			$this->tokenProvider->markPasswordInvalid($dbToken, $token);
761
-			// User is logged out
762
-			return false;
763
-		}
764
-
765
-		$dbToken->setLastCheck($now);
766
-		return true;
767
-	}
768
-
769
-	/**
770
-	 * Check if the given token exists and performs password/user-enabled checks
771
-	 *
772
-	 * Invalidates the token if checks fail
773
-	 *
774
-	 * @param string $token
775
-	 * @param string $user login name
776
-	 * @return boolean
777
-	 */
778
-	private function validateToken($token, $user = null) {
779
-		try {
780
-			$dbToken = $this->tokenProvider->getToken($token);
781
-		} catch (InvalidTokenException $ex) {
782
-			return false;
783
-		}
784
-
785
-		// Check if login names match
786
-		if (!is_null($user) && $dbToken->getLoginName() !== $user) {
787
-			// TODO: this makes it imposssible to use different login names on browser and client
788
-			// e.g. login by e-mail '[email protected]' on browser for generating the token will not
789
-			//      allow to use the client token with the login name 'user'.
790
-			return false;
791
-		}
792
-
793
-		if (!$this->checkTokenCredentials($dbToken, $token)) {
794
-			return false;
795
-		}
796
-
797
-		// Update token scope
798
-		$this->lockdownManager->setToken($dbToken);
799
-
800
-		$this->tokenProvider->updateTokenActivity($dbToken);
801
-
802
-		return true;
803
-	}
804
-
805
-	/**
806
-	 * Tries to login the user with auth token header
807
-	 *
808
-	 * @param IRequest $request
809
-	 * @todo check remember me cookie
810
-	 * @return boolean
811
-	 */
812
-	public function tryTokenLogin(IRequest $request) {
813
-		$authHeader = $request->getHeader('Authorization');
814
-		if (strpos($authHeader, 'Bearer ') === false) {
815
-			// No auth header, let's try session id
816
-			try {
817
-				$token = $this->session->getId();
818
-			} catch (SessionNotAvailableException $ex) {
819
-				return false;
820
-			}
821
-		} else {
822
-			$token = substr($authHeader, 7);
823
-		}
824
-
825
-		if (!$this->loginWithToken($token)) {
826
-			return false;
827
-		}
828
-		if (!$this->validateToken($token)) {
829
-			return false;
830
-		}
831
-
832
-		// Set the session variable so we know this is an app password
833
-		$this->session->set('app_password', $token);
834
-
835
-		return true;
836
-	}
837
-
838
-	/**
839
-	 * perform login using the magic cookie (remember login)
840
-	 *
841
-	 * @param string $uid the username
842
-	 * @param string $currentToken
843
-	 * @param string $oldSessionId
844
-	 * @return bool
845
-	 */
846
-	public function loginWithCookie($uid, $currentToken, $oldSessionId) {
847
-		$this->session->regenerateId();
848
-		$this->manager->emit('\OC\User', 'preRememberedLogin', [$uid]);
849
-		$user = $this->manager->get($uid);
850
-		if (is_null($user)) {
851
-			// user does not exist
852
-			return false;
853
-		}
854
-
855
-		// get stored tokens
856
-		$tokens = $this->config->getUserKeys($uid, 'login_token');
857
-		// test cookies token against stored tokens
858
-		if (!in_array($currentToken, $tokens, true)) {
859
-			return false;
860
-		}
861
-		// replace successfully used token with a new one
862
-		$this->config->deleteUserValue($uid, 'login_token', $currentToken);
863
-		$newToken = $this->random->generate(32);
864
-		$this->config->setUserValue($uid, 'login_token', $newToken, $this->timeFactory->getTime());
865
-
866
-		try {
867
-			$sessionId = $this->session->getId();
868
-			$token = $this->tokenProvider->renewSessionToken($oldSessionId, $sessionId);
869
-		} catch (SessionNotAvailableException $ex) {
870
-			return false;
871
-		} catch (InvalidTokenException $ex) {
872
-			\OC::$server->getLogger()->warning('Renewing session token failed', ['app' => 'core']);
873
-			return false;
874
-		}
875
-
876
-		$this->setMagicInCookie($user->getUID(), $newToken);
877
-
878
-		//login
879
-		$this->setUser($user);
880
-		$this->setLoginName($token->getLoginName());
881
-		$this->setToken($token->getId());
882
-		$this->lockdownManager->setToken($token);
883
-		$user->updateLastLoginTimestamp();
884
-		$password = null;
885
-		try {
886
-			$password = $this->tokenProvider->getPassword($token, $sessionId);
887
-		} catch (PasswordlessTokenException $ex) {
888
-			// Ignore
889
-		}
890
-		$this->manager->emit('\OC\User', 'postRememberedLogin', [$user, $password]);
891
-		return true;
892
-	}
893
-
894
-	/**
895
-	 * @param IUser $user
896
-	 */
897
-	public function createRememberMeToken(IUser $user) {
898
-		$token = $this->random->generate(32);
899
-		$this->config->setUserValue($user->getUID(), 'login_token', $token, $this->timeFactory->getTime());
900
-		$this->setMagicInCookie($user->getUID(), $token);
901
-	}
902
-
903
-	/**
904
-	 * logout the user from the session
905
-	 */
906
-	public function logout() {
907
-		$user = $this->getUser();
908
-		$this->manager->emit('\OC\User', 'logout', [$user]);
909
-		if ($user !== null) {
910
-			try {
911
-				$this->tokenProvider->invalidateToken($this->session->getId());
912
-			} catch (SessionNotAvailableException $ex) {
913
-			}
914
-		}
915
-		$this->setUser(null);
916
-		$this->setLoginName(null);
917
-		$this->setToken(null);
918
-		$this->unsetMagicInCookie();
919
-		$this->session->clear();
920
-		$this->manager->emit('\OC\User', 'postLogout', [$user]);
921
-	}
922
-
923
-	/**
924
-	 * Set cookie value to use in next page load
925
-	 *
926
-	 * @param string $username username to be set
927
-	 * @param string $token
928
-	 */
929
-	public function setMagicInCookie($username, $token) {
930
-		$secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
931
-		$webRoot = \OC::$WEBROOT;
932
-		if ($webRoot === '') {
933
-			$webRoot = '/';
934
-		}
935
-
936
-		$maxAge = $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
937
-		\OC\Http\CookieHelper::setCookie(
938
-			'nc_username',
939
-			$username,
940
-			$maxAge,
941
-			$webRoot,
942
-			'',
943
-			$secureCookie,
944
-			true,
945
-			\OC\Http\CookieHelper::SAMESITE_LAX
946
-		);
947
-		\OC\Http\CookieHelper::setCookie(
948
-			'nc_token',
949
-			$token,
950
-			$maxAge,
951
-			$webRoot,
952
-			'',
953
-			$secureCookie,
954
-			true,
955
-			\OC\Http\CookieHelper::SAMESITE_LAX
956
-		);
957
-		try {
958
-			\OC\Http\CookieHelper::setCookie(
959
-				'nc_session_id',
960
-				$this->session->getId(),
961
-				$maxAge,
962
-				$webRoot,
963
-				'',
964
-				$secureCookie,
965
-				true,
966
-				\OC\Http\CookieHelper::SAMESITE_LAX
967
-			);
968
-		} catch (SessionNotAvailableException $ex) {
969
-			// ignore
970
-		}
971
-	}
972
-
973
-	/**
974
-	 * Remove cookie for "remember username"
975
-	 */
976
-	public function unsetMagicInCookie() {
977
-		//TODO: DI for cookies and IRequest
978
-		$secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
979
-
980
-		unset($_COOKIE['nc_username']); //TODO: DI
981
-		unset($_COOKIE['nc_token']);
982
-		unset($_COOKIE['nc_session_id']);
983
-		setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
984
-		setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
985
-		setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
986
-		// old cookies might be stored under /webroot/ instead of /webroot
987
-		// and Firefox doesn't like it!
988
-		setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
989
-		setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
990
-		setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
991
-	}
992
-
993
-	/**
994
-	 * Update password of the browser session token if there is one
995
-	 *
996
-	 * @param string $password
997
-	 */
998
-	public function updateSessionTokenPassword($password) {
999
-		try {
1000
-			$sessionId = $this->session->getId();
1001
-			$token = $this->tokenProvider->getToken($sessionId);
1002
-			$this->tokenProvider->setPassword($token, $sessionId, $password);
1003
-		} catch (SessionNotAvailableException $ex) {
1004
-			// Nothing to do
1005
-		} catch (InvalidTokenException $ex) {
1006
-			// Nothing to do
1007
-		}
1008
-	}
1009
-
1010
-	public function updateTokens(string $uid, string $password) {
1011
-		$this->tokenProvider->updatePasswords($uid, $password);
1012
-	}
93
+    /** @var Manager|PublicEmitter $manager */
94
+    private $manager;
95
+
96
+    /** @var ISession $session */
97
+    private $session;
98
+
99
+    /** @var ITimeFactory */
100
+    private $timeFactory;
101
+
102
+    /** @var IProvider */
103
+    private $tokenProvider;
104
+
105
+    /** @var IConfig */
106
+    private $config;
107
+
108
+    /** @var User $activeUser */
109
+    protected $activeUser;
110
+
111
+    /** @var ISecureRandom */
112
+    private $random;
113
+
114
+    /** @var ILockdownManager  */
115
+    private $lockdownManager;
116
+
117
+    /** @var ILogger */
118
+    private $logger;
119
+    /** @var IEventDispatcher */
120
+    private $dispatcher;
121
+
122
+    /**
123
+     * @param Manager $manager
124
+     * @param ISession $session
125
+     * @param ITimeFactory $timeFactory
126
+     * @param IProvider $tokenProvider
127
+     * @param IConfig $config
128
+     * @param ISecureRandom $random
129
+     * @param ILockdownManager $lockdownManager
130
+     * @param ILogger $logger
131
+     */
132
+    public function __construct(Manager $manager,
133
+                                ISession $session,
134
+                                ITimeFactory $timeFactory,
135
+                                $tokenProvider,
136
+                                IConfig $config,
137
+                                ISecureRandom $random,
138
+                                ILockdownManager $lockdownManager,
139
+                                ILogger $logger,
140
+                                IEventDispatcher $dispatcher
141
+    ) {
142
+        $this->manager = $manager;
143
+        $this->session = $session;
144
+        $this->timeFactory = $timeFactory;
145
+        $this->tokenProvider = $tokenProvider;
146
+        $this->config = $config;
147
+        $this->random = $random;
148
+        $this->lockdownManager = $lockdownManager;
149
+        $this->logger = $logger;
150
+        $this->dispatcher = $dispatcher;
151
+    }
152
+
153
+    /**
154
+     * @param IProvider $provider
155
+     */
156
+    public function setTokenProvider(IProvider $provider) {
157
+        $this->tokenProvider = $provider;
158
+    }
159
+
160
+    /**
161
+     * @param string $scope
162
+     * @param string $method
163
+     * @param callable $callback
164
+     */
165
+    public function listen($scope, $method, callable $callback) {
166
+        $this->manager->listen($scope, $method, $callback);
167
+    }
168
+
169
+    /**
170
+     * @param string $scope optional
171
+     * @param string $method optional
172
+     * @param callable $callback optional
173
+     */
174
+    public function removeListener($scope = null, $method = null, callable $callback = null) {
175
+        $this->manager->removeListener($scope, $method, $callback);
176
+    }
177
+
178
+    /**
179
+     * get the manager object
180
+     *
181
+     * @return Manager|PublicEmitter
182
+     */
183
+    public function getManager() {
184
+        return $this->manager;
185
+    }
186
+
187
+    /**
188
+     * get the session object
189
+     *
190
+     * @return ISession
191
+     */
192
+    public function getSession() {
193
+        return $this->session;
194
+    }
195
+
196
+    /**
197
+     * set the session object
198
+     *
199
+     * @param ISession $session
200
+     */
201
+    public function setSession(ISession $session) {
202
+        if ($this->session instanceof ISession) {
203
+            $this->session->close();
204
+        }
205
+        $this->session = $session;
206
+        $this->activeUser = null;
207
+    }
208
+
209
+    /**
210
+     * set the currently active user
211
+     *
212
+     * @param IUser|null $user
213
+     */
214
+    public function setUser($user) {
215
+        if (is_null($user)) {
216
+            $this->session->remove('user_id');
217
+        } else {
218
+            $this->session->set('user_id', $user->getUID());
219
+        }
220
+        $this->activeUser = $user;
221
+    }
222
+
223
+    /**
224
+     * get the current active user
225
+     *
226
+     * @return IUser|null Current user, otherwise null
227
+     */
228
+    public function getUser() {
229
+        // FIXME: This is a quick'n dirty work-around for the incognito mode as
230
+        // described at https://github.com/owncloud/core/pull/12912#issuecomment-67391155
231
+        if (OC_User::isIncognitoMode()) {
232
+            return null;
233
+        }
234
+        if (is_null($this->activeUser)) {
235
+            $uid = $this->session->get('user_id');
236
+            if (is_null($uid)) {
237
+                return null;
238
+            }
239
+            $this->activeUser = $this->manager->get($uid);
240
+            if (is_null($this->activeUser)) {
241
+                return null;
242
+            }
243
+            $this->validateSession();
244
+        }
245
+        return $this->activeUser;
246
+    }
247
+
248
+    /**
249
+     * Validate whether the current session is valid
250
+     *
251
+     * - For token-authenticated clients, the token validity is checked
252
+     * - For browsers, the session token validity is checked
253
+     */
254
+    protected function validateSession() {
255
+        $token = null;
256
+        $appPassword = $this->session->get('app_password');
257
+
258
+        if (is_null($appPassword)) {
259
+            try {
260
+                $token = $this->session->getId();
261
+            } catch (SessionNotAvailableException $ex) {
262
+                return;
263
+            }
264
+        } else {
265
+            $token = $appPassword;
266
+        }
267
+
268
+        if (!$this->validateToken($token)) {
269
+            // Session was invalidated
270
+            $this->logout();
271
+        }
272
+    }
273
+
274
+    /**
275
+     * Checks whether the user is logged in
276
+     *
277
+     * @return bool if logged in
278
+     */
279
+    public function isLoggedIn() {
280
+        $user = $this->getUser();
281
+        if (is_null($user)) {
282
+            return false;
283
+        }
284
+
285
+        return $user->isEnabled();
286
+    }
287
+
288
+    /**
289
+     * set the login name
290
+     *
291
+     * @param string|null $loginName for the logged in user
292
+     */
293
+    public function setLoginName($loginName) {
294
+        if (is_null($loginName)) {
295
+            $this->session->remove('loginname');
296
+        } else {
297
+            $this->session->set('loginname', $loginName);
298
+        }
299
+    }
300
+
301
+    /**
302
+     * get the login name of the current user
303
+     *
304
+     * @return string
305
+     */
306
+    public function getLoginName() {
307
+        if ($this->activeUser) {
308
+            return $this->session->get('loginname');
309
+        }
310
+
311
+        $uid = $this->session->get('user_id');
312
+        if ($uid) {
313
+            $this->activeUser = $this->manager->get($uid);
314
+            return $this->session->get('loginname');
315
+        }
316
+
317
+        return null;
318
+    }
319
+
320
+    /**
321
+     * @return null|string
322
+     */
323
+    public function getImpersonatingUserID(): ?string {
324
+        return $this->session->get('oldUserId');
325
+    }
326
+
327
+    public function setImpersonatingUserID(bool $useCurrentUser = true): void {
328
+        if ($useCurrentUser === false) {
329
+            $this->session->remove('oldUserId');
330
+            return;
331
+        }
332
+
333
+        $currentUser = $this->getUser();
334
+
335
+        if ($currentUser === null) {
336
+            throw new \OC\User\NoUserException();
337
+        }
338
+        $this->session->set('oldUserId', $currentUser->getUID());
339
+    }
340
+    /**
341
+     * set the token id
342
+     *
343
+     * @param int|null $token that was used to log in
344
+     */
345
+    protected function setToken($token) {
346
+        if ($token === null) {
347
+            $this->session->remove('token-id');
348
+        } else {
349
+            $this->session->set('token-id', $token);
350
+        }
351
+    }
352
+
353
+    /**
354
+     * try to log in with the provided credentials
355
+     *
356
+     * @param string $uid
357
+     * @param string $password
358
+     * @return boolean|null
359
+     * @throws LoginException
360
+     */
361
+    public function login($uid, $password) {
362
+        $this->session->regenerateId();
363
+        if ($this->validateToken($password, $uid)) {
364
+            return $this->loginWithToken($password);
365
+        }
366
+        return $this->loginWithPassword($uid, $password);
367
+    }
368
+
369
+    /**
370
+     * @param IUser $user
371
+     * @param array $loginDetails
372
+     * @param bool $regenerateSessionId
373
+     * @return true returns true if login successful or an exception otherwise
374
+     * @throws LoginException
375
+     */
376
+    public function completeLogin(IUser $user, array $loginDetails, $regenerateSessionId = true) {
377
+        if (!$user->isEnabled()) {
378
+            // disabled users can not log in
379
+            // injecting l10n does not work - there is a circular dependency between session and \OCP\L10N\IFactory
380
+            $message = \OC::$server->getL10N('lib')->t('User disabled');
381
+            throw new LoginException($message);
382
+        }
383
+
384
+        if ($regenerateSessionId) {
385
+            $this->session->regenerateId();
386
+        }
387
+
388
+        $this->setUser($user);
389
+        $this->setLoginName($loginDetails['loginName']);
390
+
391
+        $isToken = isset($loginDetails['token']) && $loginDetails['token'] instanceof IToken;
392
+        if ($isToken) {
393
+            $this->setToken($loginDetails['token']->getId());
394
+            $this->lockdownManager->setToken($loginDetails['token']);
395
+            $firstTimeLogin = false;
396
+        } else {
397
+            $this->setToken(null);
398
+            $firstTimeLogin = $user->updateLastLoginTimestamp();
399
+        }
400
+
401
+        $this->dispatcher->dispatchTyped(new PostLoginEvent(
402
+            $user,
403
+            $loginDetails['password'],
404
+            $isToken
405
+        ));
406
+        $this->manager->emit('\OC\User', 'postLogin', [
407
+            $user,
408
+            $loginDetails['password'],
409
+            $isToken,
410
+        ]);
411
+        if ($this->isLoggedIn()) {
412
+            $this->prepareUserLogin($firstTimeLogin, $regenerateSessionId);
413
+            return true;
414
+        }
415
+
416
+        $message = \OC::$server->getL10N('lib')->t('Login canceled by app');
417
+        throw new LoginException($message);
418
+    }
419
+
420
+    /**
421
+     * Tries to log in a client
422
+     *
423
+     * Checks token auth enforced
424
+     * Checks 2FA enabled
425
+     *
426
+     * @param string $user
427
+     * @param string $password
428
+     * @param IRequest $request
429
+     * @param OC\Security\Bruteforce\Throttler $throttler
430
+     * @throws LoginException
431
+     * @throws PasswordLoginForbiddenException
432
+     * @return boolean
433
+     */
434
+    public function logClientIn($user,
435
+                                $password,
436
+                                IRequest $request,
437
+                                OC\Security\Bruteforce\Throttler $throttler) {
438
+        $currentDelay = $throttler->sleepDelay($request->getRemoteAddress(), 'login');
439
+
440
+        if ($this->manager instanceof PublicEmitter) {
441
+            $this->manager->emit('\OC\User', 'preLogin', [$user, $password]);
442
+        }
443
+
444
+        try {
445
+            $isTokenPassword = $this->isTokenPassword($password);
446
+        } catch (ExpiredTokenException $e) {
447
+            // Just return on an expired token no need to check further or record a failed login
448
+            return false;
449
+        }
450
+
451
+        if (!$isTokenPassword && $this->isTokenAuthEnforced()) {
452
+            throw new PasswordLoginForbiddenException();
453
+        }
454
+        if (!$isTokenPassword && $this->isTwoFactorEnforced($user)) {
455
+            throw new PasswordLoginForbiddenException();
456
+        }
457
+
458
+        // Try to login with this username and password
459
+        if (!$this->login($user, $password)) {
460
+
461
+            // Failed, maybe the user used their email address
462
+            $users = $this->manager->getByEmail($user);
463
+            if (!(\count($users) === 1 && $this->login($users[0]->getUID(), $password))) {
464
+                $this->logger->warning('Login failed: \'' . $user . '\' (Remote IP: \'' . \OC::$server->getRequest()->getRemoteAddress() . '\')', ['app' => 'core']);
465
+
466
+                $throttler->registerAttempt('login', $request->getRemoteAddress(), ['user' => $user]);
467
+
468
+                $this->dispatcher->dispatchTyped(new OC\Authentication\Events\LoginFailed($user));
469
+
470
+                if ($currentDelay === 0) {
471
+                    $throttler->sleepDelay($request->getRemoteAddress(), 'login');
472
+                }
473
+                return false;
474
+            }
475
+        }
476
+
477
+        if ($isTokenPassword) {
478
+            $this->session->set('app_password', $password);
479
+        } elseif ($this->supportsCookies($request)) {
480
+            // Password login, but cookies supported -> create (browser) session token
481
+            $this->createSessionToken($request, $this->getUser()->getUID(), $user, $password);
482
+        }
483
+
484
+        return true;
485
+    }
486
+
487
+    protected function supportsCookies(IRequest $request) {
488
+        if (!is_null($request->getCookie('cookie_test'))) {
489
+            return true;
490
+        }
491
+        setcookie('cookie_test', 'test', $this->timeFactory->getTime() + 3600);
492
+        return false;
493
+    }
494
+
495
+    private function isTokenAuthEnforced() {
496
+        return $this->config->getSystemValue('token_auth_enforced', false);
497
+    }
498
+
499
+    protected function isTwoFactorEnforced($username) {
500
+        Util::emitHook(
501
+            '\OCA\Files_Sharing\API\Server2Server',
502
+            'preLoginNameUsedAsUserName',
503
+            ['uid' => &$username]
504
+        );
505
+        $user = $this->manager->get($username);
506
+        if (is_null($user)) {
507
+            $users = $this->manager->getByEmail($username);
508
+            if (empty($users)) {
509
+                return false;
510
+            }
511
+            if (count($users) !== 1) {
512
+                return true;
513
+            }
514
+            $user = $users[0];
515
+        }
516
+        // DI not possible due to cyclic dependencies :'-/
517
+        return OC::$server->getTwoFactorAuthManager()->isTwoFactorAuthenticated($user);
518
+    }
519
+
520
+    /**
521
+     * Check if the given 'password' is actually a device token
522
+     *
523
+     * @param string $password
524
+     * @return boolean
525
+     * @throws ExpiredTokenException
526
+     */
527
+    public function isTokenPassword($password) {
528
+        try {
529
+            $this->tokenProvider->getToken($password);
530
+            return true;
531
+        } catch (ExpiredTokenException $e) {
532
+            throw $e;
533
+        } catch (InvalidTokenException $ex) {
534
+            $this->logger->logException($ex, [
535
+                'level' => ILogger::DEBUG,
536
+                'message' => 'Token is not valid: ' . $ex->getMessage(),
537
+            ]);
538
+            return false;
539
+        }
540
+    }
541
+
542
+    protected function prepareUserLogin($firstTimeLogin, $refreshCsrfToken = true) {
543
+        if ($refreshCsrfToken) {
544
+            // TODO: mock/inject/use non-static
545
+            // Refresh the token
546
+            \OC::$server->getCsrfTokenManager()->refreshToken();
547
+        }
548
+
549
+        //we need to pass the user name, which may differ from login name
550
+        $user = $this->getUser()->getUID();
551
+        OC_Util::setupFS($user);
552
+
553
+        if ($firstTimeLogin) {
554
+            // TODO: lock necessary?
555
+            //trigger creation of user home and /files folder
556
+            $userFolder = \OC::$server->getUserFolder($user);
557
+
558
+            try {
559
+                // copy skeleton
560
+                \OC_Util::copySkeleton($user, $userFolder);
561
+            } catch (NotPermittedException $ex) {
562
+                // read only uses
563
+            }
564
+
565
+            // trigger any other initialization
566
+            \OC::$server->getEventDispatcher()->dispatch(IUser::class . '::firstLogin', new GenericEvent($this->getUser()));
567
+        }
568
+    }
569
+
570
+    /**
571
+     * Tries to login the user with HTTP Basic Authentication
572
+     *
573
+     * @todo do not allow basic auth if the user is 2FA enforced
574
+     * @param IRequest $request
575
+     * @param OC\Security\Bruteforce\Throttler $throttler
576
+     * @return boolean if the login was successful
577
+     */
578
+    public function tryBasicAuthLogin(IRequest $request,
579
+                                        OC\Security\Bruteforce\Throttler $throttler) {
580
+        if (!empty($request->server['PHP_AUTH_USER']) && !empty($request->server['PHP_AUTH_PW'])) {
581
+            try {
582
+                if ($this->logClientIn($request->server['PHP_AUTH_USER'], $request->server['PHP_AUTH_PW'], $request, $throttler)) {
583
+                    /**
584
+                     * Add DAV authenticated. This should in an ideal world not be
585
+                     * necessary but the iOS App reads cookies from anywhere instead
586
+                     * only the DAV endpoint.
587
+                     * This makes sure that the cookies will be valid for the whole scope
588
+                     * @see https://github.com/owncloud/core/issues/22893
589
+                     */
590
+                    $this->session->set(
591
+                        Auth::DAV_AUTHENTICATED, $this->getUser()->getUID()
592
+                    );
593
+
594
+                    // Set the last-password-confirm session to make the sudo mode work
595
+                    $this->session->set('last-password-confirm', $this->timeFactory->getTime());
596
+
597
+                    return true;
598
+                }
599
+            } catch (PasswordLoginForbiddenException $ex) {
600
+                // Nothing to do
601
+            }
602
+        }
603
+        return false;
604
+    }
605
+
606
+    /**
607
+     * Log an user in via login name and password
608
+     *
609
+     * @param string $uid
610
+     * @param string $password
611
+     * @return boolean
612
+     * @throws LoginException if an app canceld the login process or the user is not enabled
613
+     */
614
+    private function loginWithPassword($uid, $password) {
615
+        $user = $this->manager->checkPasswordNoLogging($uid, $password);
616
+        if ($user === false) {
617
+            // Password check failed
618
+            return false;
619
+        }
620
+
621
+        return $this->completeLogin($user, ['loginName' => $uid, 'password' => $password], false);
622
+    }
623
+
624
+    /**
625
+     * Log an user in with a given token (id)
626
+     *
627
+     * @param string $token
628
+     * @return boolean
629
+     * @throws LoginException if an app canceled the login process or the user is not enabled
630
+     */
631
+    private function loginWithToken($token) {
632
+        try {
633
+            $dbToken = $this->tokenProvider->getToken($token);
634
+        } catch (InvalidTokenException $ex) {
635
+            return false;
636
+        }
637
+        $uid = $dbToken->getUID();
638
+
639
+        // When logging in with token, the password must be decrypted first before passing to login hook
640
+        $password = '';
641
+        try {
642
+            $password = $this->tokenProvider->getPassword($dbToken, $token);
643
+        } catch (PasswordlessTokenException $ex) {
644
+            // Ignore and use empty string instead
645
+        }
646
+
647
+        $this->manager->emit('\OC\User', 'preLogin', [$uid, $password]);
648
+
649
+        $user = $this->manager->get($uid);
650
+        if (is_null($user)) {
651
+            // user does not exist
652
+            return false;
653
+        }
654
+
655
+        return $this->completeLogin(
656
+            $user,
657
+            [
658
+                'loginName' => $dbToken->getLoginName(),
659
+                'password' => $password,
660
+                'token' => $dbToken
661
+            ],
662
+            false);
663
+    }
664
+
665
+    /**
666
+     * Create a new session token for the given user credentials
667
+     *
668
+     * @param IRequest $request
669
+     * @param string $uid user UID
670
+     * @param string $loginName login name
671
+     * @param string $password
672
+     * @param int $remember
673
+     * @return boolean
674
+     */
675
+    public function createSessionToken(IRequest $request, $uid, $loginName, $password = null, $remember = IToken::DO_NOT_REMEMBER) {
676
+        if (is_null($this->manager->get($uid))) {
677
+            // User does not exist
678
+            return false;
679
+        }
680
+        $name = isset($request->server['HTTP_USER_AGENT']) ? $request->server['HTTP_USER_AGENT'] : 'unknown browser';
681
+        try {
682
+            $sessionId = $this->session->getId();
683
+            $pwd = $this->getPassword($password);
684
+            // Make sure the current sessionId has no leftover tokens
685
+            $this->tokenProvider->invalidateToken($sessionId);
686
+            $this->tokenProvider->generateToken($sessionId, $uid, $loginName, $pwd, $name, IToken::TEMPORARY_TOKEN, $remember);
687
+            return true;
688
+        } catch (SessionNotAvailableException $ex) {
689
+            // This can happen with OCC, where a memory session is used
690
+            // if a memory session is used, we shouldn't create a session token anyway
691
+            return false;
692
+        }
693
+    }
694
+
695
+    /**
696
+     * Checks if the given password is a token.
697
+     * If yes, the password is extracted from the token.
698
+     * If no, the same password is returned.
699
+     *
700
+     * @param string $password either the login password or a device token
701
+     * @return string|null the password or null if none was set in the token
702
+     */
703
+    private function getPassword($password) {
704
+        if (is_null($password)) {
705
+            // This is surely no token ;-)
706
+            return null;
707
+        }
708
+        try {
709
+            $token = $this->tokenProvider->getToken($password);
710
+            try {
711
+                return $this->tokenProvider->getPassword($token, $password);
712
+            } catch (PasswordlessTokenException $ex) {
713
+                return null;
714
+            }
715
+        } catch (InvalidTokenException $ex) {
716
+            return $password;
717
+        }
718
+    }
719
+
720
+    /**
721
+     * @param IToken $dbToken
722
+     * @param string $token
723
+     * @return boolean
724
+     */
725
+    private function checkTokenCredentials(IToken $dbToken, $token) {
726
+        // Check whether login credentials are still valid and the user was not disabled
727
+        // This check is performed each 5 minutes
728
+        $lastCheck = $dbToken->getLastCheck() ? : 0;
729
+        $now = $this->timeFactory->getTime();
730
+        if ($lastCheck > ($now - 60 * 5)) {
731
+            // Checked performed recently, nothing to do now
732
+            return true;
733
+        }
734
+
735
+        try {
736
+            $pwd = $this->tokenProvider->getPassword($dbToken, $token);
737
+        } catch (InvalidTokenException $ex) {
738
+            // An invalid token password was used -> log user out
739
+            return false;
740
+        } catch (PasswordlessTokenException $ex) {
741
+            // Token has no password
742
+
743
+            if (!is_null($this->activeUser) && !$this->activeUser->isEnabled()) {
744
+                $this->tokenProvider->invalidateToken($token);
745
+                return false;
746
+            }
747
+
748
+            $dbToken->setLastCheck($now);
749
+            return true;
750
+        }
751
+
752
+        // Invalidate token if the user is no longer active
753
+        if (!is_null($this->activeUser) && !$this->activeUser->isEnabled()) {
754
+            $this->tokenProvider->invalidateToken($token);
755
+            return false;
756
+        }
757
+
758
+        // If the token password is no longer valid mark it as such
759
+        if ($this->manager->checkPassword($dbToken->getLoginName(), $pwd) === false) {
760
+            $this->tokenProvider->markPasswordInvalid($dbToken, $token);
761
+            // User is logged out
762
+            return false;
763
+        }
764
+
765
+        $dbToken->setLastCheck($now);
766
+        return true;
767
+    }
768
+
769
+    /**
770
+     * Check if the given token exists and performs password/user-enabled checks
771
+     *
772
+     * Invalidates the token if checks fail
773
+     *
774
+     * @param string $token
775
+     * @param string $user login name
776
+     * @return boolean
777
+     */
778
+    private function validateToken($token, $user = null) {
779
+        try {
780
+            $dbToken = $this->tokenProvider->getToken($token);
781
+        } catch (InvalidTokenException $ex) {
782
+            return false;
783
+        }
784
+
785
+        // Check if login names match
786
+        if (!is_null($user) && $dbToken->getLoginName() !== $user) {
787
+            // TODO: this makes it imposssible to use different login names on browser and client
788
+            // e.g. login by e-mail '[email protected]' on browser for generating the token will not
789
+            //      allow to use the client token with the login name 'user'.
790
+            return false;
791
+        }
792
+
793
+        if (!$this->checkTokenCredentials($dbToken, $token)) {
794
+            return false;
795
+        }
796
+
797
+        // Update token scope
798
+        $this->lockdownManager->setToken($dbToken);
799
+
800
+        $this->tokenProvider->updateTokenActivity($dbToken);
801
+
802
+        return true;
803
+    }
804
+
805
+    /**
806
+     * Tries to login the user with auth token header
807
+     *
808
+     * @param IRequest $request
809
+     * @todo check remember me cookie
810
+     * @return boolean
811
+     */
812
+    public function tryTokenLogin(IRequest $request) {
813
+        $authHeader = $request->getHeader('Authorization');
814
+        if (strpos($authHeader, 'Bearer ') === false) {
815
+            // No auth header, let's try session id
816
+            try {
817
+                $token = $this->session->getId();
818
+            } catch (SessionNotAvailableException $ex) {
819
+                return false;
820
+            }
821
+        } else {
822
+            $token = substr($authHeader, 7);
823
+        }
824
+
825
+        if (!$this->loginWithToken($token)) {
826
+            return false;
827
+        }
828
+        if (!$this->validateToken($token)) {
829
+            return false;
830
+        }
831
+
832
+        // Set the session variable so we know this is an app password
833
+        $this->session->set('app_password', $token);
834
+
835
+        return true;
836
+    }
837
+
838
+    /**
839
+     * perform login using the magic cookie (remember login)
840
+     *
841
+     * @param string $uid the username
842
+     * @param string $currentToken
843
+     * @param string $oldSessionId
844
+     * @return bool
845
+     */
846
+    public function loginWithCookie($uid, $currentToken, $oldSessionId) {
847
+        $this->session->regenerateId();
848
+        $this->manager->emit('\OC\User', 'preRememberedLogin', [$uid]);
849
+        $user = $this->manager->get($uid);
850
+        if (is_null($user)) {
851
+            // user does not exist
852
+            return false;
853
+        }
854
+
855
+        // get stored tokens
856
+        $tokens = $this->config->getUserKeys($uid, 'login_token');
857
+        // test cookies token against stored tokens
858
+        if (!in_array($currentToken, $tokens, true)) {
859
+            return false;
860
+        }
861
+        // replace successfully used token with a new one
862
+        $this->config->deleteUserValue($uid, 'login_token', $currentToken);
863
+        $newToken = $this->random->generate(32);
864
+        $this->config->setUserValue($uid, 'login_token', $newToken, $this->timeFactory->getTime());
865
+
866
+        try {
867
+            $sessionId = $this->session->getId();
868
+            $token = $this->tokenProvider->renewSessionToken($oldSessionId, $sessionId);
869
+        } catch (SessionNotAvailableException $ex) {
870
+            return false;
871
+        } catch (InvalidTokenException $ex) {
872
+            \OC::$server->getLogger()->warning('Renewing session token failed', ['app' => 'core']);
873
+            return false;
874
+        }
875
+
876
+        $this->setMagicInCookie($user->getUID(), $newToken);
877
+
878
+        //login
879
+        $this->setUser($user);
880
+        $this->setLoginName($token->getLoginName());
881
+        $this->setToken($token->getId());
882
+        $this->lockdownManager->setToken($token);
883
+        $user->updateLastLoginTimestamp();
884
+        $password = null;
885
+        try {
886
+            $password = $this->tokenProvider->getPassword($token, $sessionId);
887
+        } catch (PasswordlessTokenException $ex) {
888
+            // Ignore
889
+        }
890
+        $this->manager->emit('\OC\User', 'postRememberedLogin', [$user, $password]);
891
+        return true;
892
+    }
893
+
894
+    /**
895
+     * @param IUser $user
896
+     */
897
+    public function createRememberMeToken(IUser $user) {
898
+        $token = $this->random->generate(32);
899
+        $this->config->setUserValue($user->getUID(), 'login_token', $token, $this->timeFactory->getTime());
900
+        $this->setMagicInCookie($user->getUID(), $token);
901
+    }
902
+
903
+    /**
904
+     * logout the user from the session
905
+     */
906
+    public function logout() {
907
+        $user = $this->getUser();
908
+        $this->manager->emit('\OC\User', 'logout', [$user]);
909
+        if ($user !== null) {
910
+            try {
911
+                $this->tokenProvider->invalidateToken($this->session->getId());
912
+            } catch (SessionNotAvailableException $ex) {
913
+            }
914
+        }
915
+        $this->setUser(null);
916
+        $this->setLoginName(null);
917
+        $this->setToken(null);
918
+        $this->unsetMagicInCookie();
919
+        $this->session->clear();
920
+        $this->manager->emit('\OC\User', 'postLogout', [$user]);
921
+    }
922
+
923
+    /**
924
+     * Set cookie value to use in next page load
925
+     *
926
+     * @param string $username username to be set
927
+     * @param string $token
928
+     */
929
+    public function setMagicInCookie($username, $token) {
930
+        $secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
931
+        $webRoot = \OC::$WEBROOT;
932
+        if ($webRoot === '') {
933
+            $webRoot = '/';
934
+        }
935
+
936
+        $maxAge = $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
937
+        \OC\Http\CookieHelper::setCookie(
938
+            'nc_username',
939
+            $username,
940
+            $maxAge,
941
+            $webRoot,
942
+            '',
943
+            $secureCookie,
944
+            true,
945
+            \OC\Http\CookieHelper::SAMESITE_LAX
946
+        );
947
+        \OC\Http\CookieHelper::setCookie(
948
+            'nc_token',
949
+            $token,
950
+            $maxAge,
951
+            $webRoot,
952
+            '',
953
+            $secureCookie,
954
+            true,
955
+            \OC\Http\CookieHelper::SAMESITE_LAX
956
+        );
957
+        try {
958
+            \OC\Http\CookieHelper::setCookie(
959
+                'nc_session_id',
960
+                $this->session->getId(),
961
+                $maxAge,
962
+                $webRoot,
963
+                '',
964
+                $secureCookie,
965
+                true,
966
+                \OC\Http\CookieHelper::SAMESITE_LAX
967
+            );
968
+        } catch (SessionNotAvailableException $ex) {
969
+            // ignore
970
+        }
971
+    }
972
+
973
+    /**
974
+     * Remove cookie for "remember username"
975
+     */
976
+    public function unsetMagicInCookie() {
977
+        //TODO: DI for cookies and IRequest
978
+        $secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
979
+
980
+        unset($_COOKIE['nc_username']); //TODO: DI
981
+        unset($_COOKIE['nc_token']);
982
+        unset($_COOKIE['nc_session_id']);
983
+        setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
984
+        setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
985
+        setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
986
+        // old cookies might be stored under /webroot/ instead of /webroot
987
+        // and Firefox doesn't like it!
988
+        setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
989
+        setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
990
+        setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
991
+    }
992
+
993
+    /**
994
+     * Update password of the browser session token if there is one
995
+     *
996
+     * @param string $password
997
+     */
998
+    public function updateSessionTokenPassword($password) {
999
+        try {
1000
+            $sessionId = $this->session->getId();
1001
+            $token = $this->tokenProvider->getToken($sessionId);
1002
+            $this->tokenProvider->setPassword($token, $sessionId, $password);
1003
+        } catch (SessionNotAvailableException $ex) {
1004
+            // Nothing to do
1005
+        } catch (InvalidTokenException $ex) {
1006
+            // Nothing to do
1007
+        }
1008
+    }
1009
+
1010
+    public function updateTokens(string $uid, string $password) {
1011
+        $this->tokenProvider->updatePasswords($uid, $password);
1012
+    }
1013 1013
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -461,7 +461,7 @@  discard block
 block discarded – undo
461 461
 			// Failed, maybe the user used their email address
462 462
 			$users = $this->manager->getByEmail($user);
463 463
 			if (!(\count($users) === 1 && $this->login($users[0]->getUID(), $password))) {
464
-				$this->logger->warning('Login failed: \'' . $user . '\' (Remote IP: \'' . \OC::$server->getRequest()->getRemoteAddress() . '\')', ['app' => 'core']);
464
+				$this->logger->warning('Login failed: \''.$user.'\' (Remote IP: \''.\OC::$server->getRequest()->getRemoteAddress().'\')', ['app' => 'core']);
465 465
 
466 466
 				$throttler->registerAttempt('login', $request->getRemoteAddress(), ['user' => $user]);
467 467
 
@@ -533,7 +533,7 @@  discard block
 block discarded – undo
533 533
 		} catch (InvalidTokenException $ex) {
534 534
 			$this->logger->logException($ex, [
535 535
 				'level' => ILogger::DEBUG,
536
-				'message' => 'Token is not valid: ' . $ex->getMessage(),
536
+				'message' => 'Token is not valid: '.$ex->getMessage(),
537 537
 			]);
538 538
 			return false;
539 539
 		}
@@ -563,7 +563,7 @@  discard block
 block discarded – undo
563 563
 			}
564 564
 
565 565
 			// trigger any other initialization
566
-			\OC::$server->getEventDispatcher()->dispatch(IUser::class . '::firstLogin', new GenericEvent($this->getUser()));
566
+			\OC::$server->getEventDispatcher()->dispatch(IUser::class.'::firstLogin', new GenericEvent($this->getUser()));
567 567
 		}
568 568
 	}
569 569
 
@@ -725,7 +725,7 @@  discard block
 block discarded – undo
725 725
 	private function checkTokenCredentials(IToken $dbToken, $token) {
726 726
 		// Check whether login credentials are still valid and the user was not disabled
727 727
 		// This check is performed each 5 minutes
728
-		$lastCheck = $dbToken->getLastCheck() ? : 0;
728
+		$lastCheck = $dbToken->getLastCheck() ?: 0;
729 729
 		$now = $this->timeFactory->getTime();
730 730
 		if ($lastCheck > ($now - 60 * 5)) {
731 731
 			// Checked performed recently, nothing to do now
@@ -985,9 +985,9 @@  discard block
 block discarded – undo
985 985
 		setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
986 986
 		// old cookies might be stored under /webroot/ instead of /webroot
987 987
 		// and Firefox doesn't like it!
988
-		setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
989
-		setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
990
-		setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
988
+		setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT.'/', '', $secureCookie, true);
989
+		setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT.'/', '', $secureCookie, true);
990
+		setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT.'/', '', $secureCookie, true);
991 991
 	}
992 992
 
993 993
 	/**
Please login to merge, or discard this patch.