SessionTest.php 29.8 KB
Newer Older
Robin Appelman's avatar
Robin Appelman committed
1
2
3
4
5
6
7
8
9
10
11
<?php

/**
 * Copyright (c) 2013 Robin Appelman <icewind@owncloud.com>
 * This file is licensed under the Affero General Public License version 3 or
 * later.
 * See the COPYING-README file.
 */

namespace Test\User;

Robin Appelman's avatar
Robin Appelman committed
12
13
14
use OC\Session\Memory;
use OC\User\User;

Lukas Reschke's avatar
Lukas Reschke committed
15
16
17
18
/**
 * @group DB
 * @package Test\User
 */
Joas Schilling's avatar
Joas Schilling committed
19
class SessionTest extends \Test\TestCase {
Robin Appelman's avatar
Robin Appelman committed
20

Christoph Wurst's avatar
Christoph Wurst committed
21
22
23
	/** @var \OCP\AppFramework\Utility\ITimeFactory */
	private $timeFactory;

Christoph Wurst's avatar
Christoph Wurst committed
24
	/** @var \OC\Authentication\Token\DefaultTokenProvider */
25
	protected $tokenProvider;
Robin Appelman's avatar
Robin Appelman committed
26

27
28
29
	/** @var \OCP\IConfig */
	private $config;

Christoph Wurst's avatar
Christoph Wurst committed
30
31
	protected function setUp() {
		parent::setUp();
Robin Appelman's avatar
Robin Appelman committed
32

Christoph Wurst's avatar
Christoph Wurst committed
33
34
35
36
		$this->timeFactory = $this->getMock('\OCP\AppFramework\Utility\ITimeFactory');
		$this->timeFactory->expects($this->any())
			->method('getTime')
			->will($this->returnValue(10000));
37
		$this->tokenProvider = $this->getMock('\OC\Authentication\Token\IProvider');
38
		$this->config = $this->getMock('\OCP\IConfig');
Robin Appelman's avatar
Robin Appelman committed
39
40
	}

Christoph Wurst's avatar
Christoph Wurst committed
41
42
	public function testGetUser() {
		$token = new \OC\Authentication\Token\DefaultToken();
43
		$token->setLoginName('User123');
Christoph Wurst's avatar
Christoph Wurst committed
44
		$token->setLastCheck(200);
Christoph Wurst's avatar
Christoph Wurst committed
45

46
47
48
49
		$expectedUser = $this->getMock('\OCP\IUser');
		$expectedUser->expects($this->any())
			->method('getUID')
			->will($this->returnValue('user123'));
50
		$session = $this->getMock('\OC\Session\Memory', array(), array(''));
Christoph Wurst's avatar
Christoph Wurst committed
51
		$session->expects($this->at(0))
52
53
			->method('get')
			->with('user_id')
Christoph Wurst's avatar
Christoph Wurst committed
54
			->will($this->returnValue($expectedUser->getUID()));
55
		$sessionId = 'abcdef12345';
56

Christoph Wurst's avatar
Christoph Wurst committed
57
58
59
		$manager = $this->getMockBuilder('\OC\User\Manager')
			->disableOriginalConstructor()
			->getMock();
Christoph Wurst's avatar
Christoph Wurst committed
60
61
62
63
		$session->expects($this->at(1))
			->method('get')
			->with('app_password')
			->will($this->returnValue(null)); // No password set -> browser session
64
65
66
		$session->expects($this->once())
			->method('getId')
			->will($this->returnValue($sessionId));
67
		$this->tokenProvider->expects($this->once())
Christoph Wurst's avatar
Christoph Wurst committed
68
			->method('getToken')
Christoph Wurst's avatar
Christoph Wurst committed
69
			->with($sessionId)
Christoph Wurst's avatar
Christoph Wurst committed
70
			->will($this->returnValue($token));
71
		$this->tokenProvider->expects($this->once())
Christoph Wurst's avatar
Christoph Wurst committed
72
			->method('getPassword')
73
			->with($token, $sessionId)
Christoph Wurst's avatar
Christoph Wurst committed
74
			->will($this->returnValue('passme'));
Christoph Wurst's avatar
Christoph Wurst committed
75
76
		$manager->expects($this->once())
			->method('checkPassword')
Christoph Wurst's avatar
Christoph Wurst committed
77
			->with('User123', 'passme')
78
79
80
			->will($this->returnValue(true));
		$expectedUser->expects($this->once())
			->method('isEnabled')
81
82
			->will($this->returnValue(true));

83
		$this->tokenProvider->expects($this->once())
Christoph Wurst's avatar
Christoph Wurst committed
84
			->method('updateTokenActivity')
Christoph Wurst's avatar
Christoph Wurst committed
85
			->with($token);
86

Christoph Wurst's avatar
Christoph Wurst committed
87
88
89
90
91
		$manager->expects($this->any())
			->method('get')
			->with($expectedUser->getUID())
			->will($this->returnValue($expectedUser));

92
		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);
Christoph Wurst's avatar
Christoph Wurst committed
93
94
		$user = $userSession->getUser();
		$this->assertSame($expectedUser, $user);
Christoph Wurst's avatar
Christoph Wurst committed
95
		$this->assertSame(10000, $token->getLastCheck());
96
	}
97

Christoph Wurst's avatar
Christoph Wurst committed
98
99
100
101
102
103
	public function isLoggedInData() {
		return [
			[true],
			[false],
		];
	}
104

Christoph Wurst's avatar
Christoph Wurst committed
105
106
107
108
109
	/**
	 * @dataProvider isLoggedInData
	 */
	public function testIsLoggedIn($isLoggedIn) {
		$session = $this->getMock('\OC\Session\Memory', array(), array(''));
110

Christoph Wurst's avatar
Christoph Wurst committed
111
112
113
		$manager = $this->getMockBuilder('\OC\User\Manager')
			->disableOriginalConstructor()
			->getMock();
114

Christoph Wurst's avatar
Christoph Wurst committed
115
		$userSession = $this->getMockBuilder('\OC\User\Session')
116
			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config])
Christoph Wurst's avatar
Christoph Wurst committed
117
118
119
120
121
122
123
124
125
			->setMethods([
				'getUser'
			])
			->getMock();
		$user = new User('sepp', null);
		$userSession->expects($this->once())
			->method('getUser')
			->will($this->returnValue($isLoggedIn ? $user : null));
		$this->assertEquals($isLoggedIn, $userSession->isLoggedIn());
126
127
	}

Robin Appelman's avatar
Robin Appelman committed
128
129
130
131
132
133
134
135
	public function testSetUser() {
		$session = $this->getMock('\OC\Session\Memory', array(), array(''));
		$session->expects($this->once())
			->method('set')
			->with('user_id', 'foo');

		$manager = $this->getMock('\OC\User\Manager');

136
		$backend = $this->getMock('\Test\Util\User\Dummy');
Robin Appelman's avatar
Robin Appelman committed
137
138
139
140
141
142

		$user = $this->getMock('\OC\User\User', array(), array('foo', $backend));
		$user->expects($this->once())
			->method('getUID')
			->will($this->returnValue('foo'));

143
		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);
Robin Appelman's avatar
Robin Appelman committed
144
145
146
147
148
		$userSession->setUser($user);
	}

	public function testLoginValidPasswordEnabled() {
		$session = $this->getMock('\OC\Session\Memory', array(), array(''));
149
150
		$session->expects($this->once())
			->method('regenerateId');
Christoph Wurst's avatar
Christoph Wurst committed
151
152
153
		$this->tokenProvider->expects($this->once())
			->method('getToken')
			->with('bar')
Christoph Wurst's avatar
Christoph Wurst committed
154
			->will($this->throwException(new \OC\Authentication\Exceptions\InvalidTokenException()));
Arthur Schiwon's avatar
Arthur Schiwon committed
155
		$session->expects($this->exactly(2))
Robin Appelman's avatar
Robin Appelman committed
156
			->method('set')
Robin Appelman's avatar
Robin Appelman committed
157
158
159
160
161
162
163
164
165
166
			->with($this->callback(function ($key) {
					switch ($key) {
						case 'user_id':
						case 'loginname':
							return true;
							break;
						default:
							return false;
							break;
					}
Christoph Wurst's avatar
Christoph Wurst committed
167
				}, 'foo'));
Robin Appelman's avatar
Robin Appelman committed
168

Arthur Schiwon's avatar
Arthur Schiwon committed
169
170
171
172
		$managerMethods = get_class_methods('\OC\User\Manager');
		//keep following methods intact in order to ensure hooks are
		//working
		$doNotMock = array('__construct', 'emit', 'listen');
Robin Appelman's avatar
Robin Appelman committed
173
		foreach ($doNotMock as $methodName) {
Arthur Schiwon's avatar
Arthur Schiwon committed
174
			$i = array_search($methodName, $managerMethods, true);
Robin Appelman's avatar
Robin Appelman committed
175
			if ($i !== false) {
Arthur Schiwon's avatar
Arthur Schiwon committed
176
177
178
179
				unset($managerMethods[$i]);
			}
		}
		$manager = $this->getMock('\OC\User\Manager', $managerMethods, array());
Robin Appelman's avatar
Robin Appelman committed
180

181
		$backend = $this->getMock('\Test\Util\User\Dummy');
Robin Appelman's avatar
Robin Appelman committed
182
183

		$user = $this->getMock('\OC\User\User', array(), array('foo', $backend));
184
		$user->expects($this->any())
Robin Appelman's avatar
Robin Appelman committed
185
186
187
188
189
			->method('isEnabled')
			->will($this->returnValue(true));
		$user->expects($this->any())
			->method('getUID')
			->will($this->returnValue('foo'));
Arthur Schiwon's avatar
Arthur Schiwon committed
190
191
		$user->expects($this->once())
			->method('updateLastLoginTimestamp');
Robin Appelman's avatar
Robin Appelman committed
192
193

		$manager->expects($this->once())
194
195
			->method('checkPassword')
			->with('foo', 'bar')
Robin Appelman's avatar
Robin Appelman committed
196
197
			->will($this->returnValue($user));

Christoph Wurst's avatar
Christoph Wurst committed
198
		$userSession = $this->getMockBuilder('\OC\User\Session')
199
			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config])
Christoph Wurst's avatar
Christoph Wurst committed
200
201
202
203
204
205
			->setMethods([
				'prepareUserLogin'
			])
			->getMock();
		$userSession->expects($this->once())
			->method('prepareUserLogin');
Robin Appelman's avatar
Robin Appelman committed
206
207
208
209
		$userSession->login('foo', 'bar');
		$this->assertEquals($user, $userSession->getUser());
	}

210
211
212
	/**
	 * @expectedException \OC\User\LoginException
	 */
Robin Appelman's avatar
Robin Appelman committed
213
214
215
216
	public function testLoginValidPasswordDisabled() {
		$session = $this->getMock('\OC\Session\Memory', array(), array(''));
		$session->expects($this->never())
			->method('set');
217
		$session->expects($this->once())
Christoph Wurst's avatar
Christoph Wurst committed
218
			->method('regenerateId');
Christoph Wurst's avatar
Christoph Wurst committed
219
220
221
222
		$this->tokenProvider->expects($this->once())
			->method('getToken')
			->with('bar')
			->will($this->throwException(new \OC\Authentication\Exceptions\InvalidTokenException()));
Robin Appelman's avatar
Robin Appelman committed
223

Arthur Schiwon's avatar
Arthur Schiwon committed
224
225
226
227
		$managerMethods = get_class_methods('\OC\User\Manager');
		//keep following methods intact in order to ensure hooks are
		//working
		$doNotMock = array('__construct', 'emit', 'listen');
Robin Appelman's avatar
Robin Appelman committed
228
		foreach ($doNotMock as $methodName) {
Arthur Schiwon's avatar
Arthur Schiwon committed
229
			$i = array_search($methodName, $managerMethods, true);
Robin Appelman's avatar
Robin Appelman committed
230
			if ($i !== false) {
Arthur Schiwon's avatar
Arthur Schiwon committed
231
232
233
234
				unset($managerMethods[$i]);
			}
		}
		$manager = $this->getMock('\OC\User\Manager', $managerMethods, array());
Robin Appelman's avatar
Robin Appelman committed
235

236
		$backend = $this->getMock('\Test\Util\User\Dummy');
Robin Appelman's avatar
Robin Appelman committed
237
238

		$user = $this->getMock('\OC\User\User', array(), array('foo', $backend));
239
		$user->expects($this->any())
Robin Appelman's avatar
Robin Appelman committed
240
241
			->method('isEnabled')
			->will($this->returnValue(false));
Arthur Schiwon's avatar
Arthur Schiwon committed
242
243
		$user->expects($this->never())
			->method('updateLastLoginTimestamp');
Robin Appelman's avatar
Robin Appelman committed
244
245

		$manager->expects($this->once())
246
247
			->method('checkPassword')
			->with('foo', 'bar')
Robin Appelman's avatar
Robin Appelman committed
248
249
			->will($this->returnValue($user));

250
		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);
Robin Appelman's avatar
Robin Appelman committed
251
252
253
		$userSession->login('foo', 'bar');
	}

254
	public function testLoginInvalidPassword() {
Robin Appelman's avatar
Robin Appelman committed
255
		$session = $this->getMock('\OC\Session\Memory', array(), array(''));
Arthur Schiwon's avatar
Arthur Schiwon committed
256
257
258
259
		$managerMethods = get_class_methods('\OC\User\Manager');
		//keep following methods intact in order to ensure hooks are
		//working
		$doNotMock = array('__construct', 'emit', 'listen');
Robin Appelman's avatar
Robin Appelman committed
260
		foreach ($doNotMock as $methodName) {
Arthur Schiwon's avatar
Arthur Schiwon committed
261
			$i = array_search($methodName, $managerMethods, true);
Robin Appelman's avatar
Robin Appelman committed
262
			if ($i !== false) {
Arthur Schiwon's avatar
Arthur Schiwon committed
263
264
265
266
				unset($managerMethods[$i]);
			}
		}
		$manager = $this->getMock('\OC\User\Manager', $managerMethods, array());
267
		$backend = $this->getMock('\Test\Util\User\Dummy');
Christoph Wurst's avatar
Christoph Wurst committed
268
		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);
Robin Appelman's avatar
Robin Appelman committed
269
270

		$user = $this->getMock('\OC\User\User', array(), array('foo', $backend));
Christoph Wurst's avatar
Christoph Wurst committed
271
272
273
274
275
276
277
278
279
280

		$session->expects($this->never())
			->method('set');
		$session->expects($this->once())
			->method('regenerateId');
		$this->tokenProvider->expects($this->once())
			->method('getToken')
			->with('bar')
			->will($this->throwException(new \OC\Authentication\Exceptions\InvalidTokenException()));

Robin Appelman's avatar
Robin Appelman committed
281
282
		$user->expects($this->never())
			->method('isEnabled');
Arthur Schiwon's avatar
Arthur Schiwon committed
283
284
		$user->expects($this->never())
			->method('updateLastLoginTimestamp');
Robin Appelman's avatar
Robin Appelman committed
285
286

		$manager->expects($this->once())
287
288
289
			->method('checkPassword')
			->with('foo', 'bar')
			->will($this->returnValue(false));
Robin Appelman's avatar
Robin Appelman committed
290
291
292
293
294
295

		$userSession->login('foo', 'bar');
	}

	public function testLoginNonExisting() {
		$session = $this->getMock('\OC\Session\Memory', array(), array(''));
Christoph Wurst's avatar
Christoph Wurst committed
296
297
298
299
		$manager = $this->getMock('\OC\User\Manager');
		$backend = $this->getMock('\Test\Util\User\Dummy');
		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);

Robin Appelman's avatar
Robin Appelman committed
300
301
		$session->expects($this->never())
			->method('set');
302
		$session->expects($this->once())
Christoph Wurst's avatar
Christoph Wurst committed
303
			->method('regenerateId');
Christoph Wurst's avatar
Christoph Wurst committed
304
305
306
307
		$this->tokenProvider->expects($this->once())
			->method('getToken')
			->with('bar')
			->will($this->throwException(new \OC\Authentication\Exceptions\InvalidTokenException()));
Christoph Wurst's avatar
Christoph Wurst committed
308

Robin Appelman's avatar
Robin Appelman committed
309
		$manager->expects($this->once())
310
311
312
			->method('checkPassword')
			->with('foo', 'bar')
			->will($this->returnValue(false));
Robin Appelman's avatar
Robin Appelman committed
313
314
315

		$userSession->login('foo', 'bar');
	}
316

317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
	/**
	 * When using a device token, the loginname must match the one that was used
	 * when generating the token on the browser.
	 */
	public function testLoginWithDifferentTokenLoginName() {
		$session = $this->getMock('\OC\Session\Memory', array(), array(''));
		$manager = $this->getMock('\OC\User\Manager');
		$backend = $this->getMock('\Test\Util\User\Dummy');
		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);
		$username = 'user123';
		$token = new \OC\Authentication\Token\DefaultToken();
		$token->setLoginName($username);

		$session->expects($this->never())
			->method('set');
		$session->expects($this->once())
			->method('regenerateId');
		$this->tokenProvider->expects($this->once())
			->method('getToken')
			->with('bar')
			->will($this->returnValue($token));

		$manager->expects($this->once())
			->method('checkPassword')
			->with('foo', 'bar')
			->will($this->returnValue(false));

		$userSession->login('foo', 'bar');
	}

347
348
349
	/**
	 * @expectedException \OC\Authentication\Exceptions\PasswordLoginForbiddenException
	 */
350
351
352
353
354
	public function testLogClientInNoTokenPasswordWith2fa() {
		$manager = $this->getMockBuilder('\OC\User\Manager')
			->disableOriginalConstructor()
			->getMock();
		$session = $this->getMock('\OCP\ISession');
355
356
		$request = $this->getMock('\OCP\IRequest');
		$user = $this->getMock('\OCP\IUser');
357
358
359

		/** @var \OC\User\Session $userSession */
		$userSession = $this->getMockBuilder('\OC\User\Session')
360
			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config])
361
			->setMethods(['login', 'supportsCookies', 'createSessionToken', 'getUser'])
362
363
			->getMock();

364
		$this->tokenProvider->expects($this->once())
365
366
367
368
369
370
371
372
			->method('getToken')
			->with('doe')
			->will($this->throwException(new \OC\Authentication\Exceptions\InvalidTokenException()));
		$this->config->expects($this->once())
			->method('getSystemValue')
			->with('token_auth_enforced', false)
			->will($this->returnValue(true));

373
		$userSession->logClientIn('john', 'doe', $request);
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
	}

	public function testLogClientInWithTokenPassword() {
		$manager = $this->getMockBuilder('\OC\User\Manager')
			->disableOriginalConstructor()
			->getMock();
		$session = $this->getMock('\OCP\ISession');
		$request = $this->getMock('\OCP\IRequest');
		$user = $this->getMock('\OCP\IUser');

		/** @var \OC\User\Session $userSession */
		$userSession = $this->getMockBuilder('\OC\User\Session')
			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config])
			->setMethods(['isTokenPassword', 'login', 'supportsCookies', 'createSessionToken', 'getUser'])
			->getMock();

		$userSession->expects($this->once())
			->method('isTokenPassword')
			->will($this->returnValue(true));
		$userSession->expects($this->once())
			->method('login')
Christoph Wurst's avatar
Christoph Wurst committed
395
			->with('john', 'I-AM-AN-APP-PASSWORD')
396
397
			->will($this->returnValue(true));

Christoph Wurst's avatar
Christoph Wurst committed
398
399
400
401
402
		$session->expects($this->once())
			->method('set')
			->with('app_password', 'I-AM-AN-APP-PASSWORD');

		$this->assertTrue($userSession->logClientIn('john', 'I-AM-AN-APP-PASSWORD', $request));
403
404
	}

405
406
407
	/**
	 * @expectedException \OC\Authentication\Exceptions\PasswordLoginForbiddenException
	 */
408
409
410
411
412
413
	public function testLogClientInNoTokenPasswordNo2fa() {
		$manager = $this->getMockBuilder('\OC\User\Manager')
			->disableOriginalConstructor()
			->getMock();
		$session = $this->getMock('\OCP\ISession');
		$user = $this->getMock('\OCP\IUser');
414
		$request = $this->getMock('\OCP\IRequest');
415
416
417

		/** @var \OC\User\Session $userSession */
		$userSession = $this->getMockBuilder('\OC\User\Session')
418
			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config])
419
420
421
			->setMethods(['login', 'isTwoFactorEnforced'])
			->getMock();

422
		$this->tokenProvider->expects($this->once())
423
424
425
426
427
428
429
430
431
432
433
434
435
			->method('getToken')
			->with('doe')
			->will($this->throwException(new \OC\Authentication\Exceptions\InvalidTokenException()));
		$this->config->expects($this->once())
			->method('getSystemValue')
			->with('token_auth_enforced', false)
			->will($this->returnValue(false));

		$userSession->expects($this->once())
			->method('isTwoFactorEnforced')
			->with('john')
			->will($this->returnValue(true));

436
		$userSession->logClientIn('john', 'doe', $request);
437
438
	}

439
440
441
442
	public function testRememberLoginValidToken() {
		$session = $this->getMock('\OC\Session\Memory', array(), array(''));
		$session->expects($this->exactly(1))
			->method('set')
Robin Appelman's avatar
Robin Appelman committed
443
444
445
446
447
448
449
			->with($this->callback(function ($key) {
					switch ($key) {
						case 'user_id':
							return true;
						default:
							return false;
					}
Christoph Wurst's avatar
Christoph Wurst committed
450
				}, 'foo'));
451
		$session->expects($this->once())
Christoph Wurst's avatar
Christoph Wurst committed
452
			->method('regenerateId');
453

Arthur Schiwon's avatar
Arthur Schiwon committed
454
455
456
457
		$managerMethods = get_class_methods('\OC\User\Manager');
		//keep following methods intact in order to ensure hooks are
		//working
		$doNotMock = array('__construct', 'emit', 'listen');
Robin Appelman's avatar
Robin Appelman committed
458
		foreach ($doNotMock as $methodName) {
Arthur Schiwon's avatar
Arthur Schiwon committed
459
			$i = array_search($methodName, $managerMethods, true);
Robin Appelman's avatar
Robin Appelman committed
460
			if ($i !== false) {
Arthur Schiwon's avatar
Arthur Schiwon committed
461
462
463
464
				unset($managerMethods[$i]);
			}
		}
		$manager = $this->getMock('\OC\User\Manager', $managerMethods, array());
465

466
		$backend = $this->getMock('\Test\Util\User\Dummy');
467
468
469
470
471
472

		$user = $this->getMock('\OC\User\User', array(), array('foo', $backend));

		$user->expects($this->any())
			->method('getUID')
			->will($this->returnValue('foo'));
Arthur Schiwon's avatar
Arthur Schiwon committed
473
474
		$user->expects($this->once())
			->method('updateLastLoginTimestamp');
475
476
477
478
479
480
481
482

		$manager->expects($this->once())
			->method('get')
			->with('foo')
			->will($this->returnValue($user));

		//prepare login token
		$token = 'goodToken';
483
		\OC::$server->getConfig()->setUserValue('foo', 'login_token', $token, time());
484
485
486
487
488
489

		$userSession = $this->getMock(
			'\OC\User\Session',
			//override, otherwise tests will fail because of setcookie()
			array('setMagicInCookie'),
			//there  are passed as parameters to the constructor
490
			array($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config));
491
492
493
494
495
496
497
498
499
500

		$granted = $userSession->loginWithCookie('foo', $token);

		$this->assertSame($granted, true);
	}

	public function testRememberLoginInvalidToken() {
		$session = $this->getMock('\OC\Session\Memory', array(), array(''));
		$session->expects($this->never())
			->method('set');
501
		$session->expects($this->once())
Christoph Wurst's avatar
Christoph Wurst committed
502
			->method('regenerateId');
503

Arthur Schiwon's avatar
Arthur Schiwon committed
504
505
506
507
		$managerMethods = get_class_methods('\OC\User\Manager');
		//keep following methods intact in order to ensure hooks are
		//working
		$doNotMock = array('__construct', 'emit', 'listen');
Robin Appelman's avatar
Robin Appelman committed
508
		foreach ($doNotMock as $methodName) {
Arthur Schiwon's avatar
Arthur Schiwon committed
509
			$i = array_search($methodName, $managerMethods, true);
Robin Appelman's avatar
Robin Appelman committed
510
			if ($i !== false) {
Arthur Schiwon's avatar
Arthur Schiwon committed
511
512
513
514
				unset($managerMethods[$i]);
			}
		}
		$manager = $this->getMock('\OC\User\Manager', $managerMethods, array());
515

516
		$backend = $this->getMock('\Test\Util\User\Dummy');
517
518
519
520
521
522

		$user = $this->getMock('\OC\User\User', array(), array('foo', $backend));

		$user->expects($this->any())
			->method('getUID')
			->will($this->returnValue('foo'));
Arthur Schiwon's avatar
Arthur Schiwon committed
523
524
		$user->expects($this->never())
			->method('updateLastLoginTimestamp');
525
526
527
528
529
530
531
532

		$manager->expects($this->once())
			->method('get')
			->with('foo')
			->will($this->returnValue($user));

		//prepare login token
		$token = 'goodToken';
533
		\OC::$server->getConfig()->setUserValue('foo', 'login_token', $token, time());
534

535
		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);
536
537
538
539
540
541
542
543
544
		$granted = $userSession->loginWithCookie('foo', 'badToken');

		$this->assertSame($granted, false);
	}

	public function testRememberLoginInvalidUser() {
		$session = $this->getMock('\OC\Session\Memory', array(), array(''));
		$session->expects($this->never())
			->method('set');
545
		$session->expects($this->once())
Christoph Wurst's avatar
Christoph Wurst committed
546
			->method('regenerateId');
547

Arthur Schiwon's avatar
Arthur Schiwon committed
548
549
550
551
		$managerMethods = get_class_methods('\OC\User\Manager');
		//keep following methods intact in order to ensure hooks are
		//working
		$doNotMock = array('__construct', 'emit', 'listen');
Robin Appelman's avatar
Robin Appelman committed
552
		foreach ($doNotMock as $methodName) {
Arthur Schiwon's avatar
Arthur Schiwon committed
553
			$i = array_search($methodName, $managerMethods, true);
Robin Appelman's avatar
Robin Appelman committed
554
			if ($i !== false) {
Arthur Schiwon's avatar
Arthur Schiwon committed
555
556
557
558
				unset($managerMethods[$i]);
			}
		}
		$manager = $this->getMock('\OC\User\Manager', $managerMethods, array());
559

560
		$backend = $this->getMock('\Test\Util\User\Dummy');
561
562
563
564
565

		$user = $this->getMock('\OC\User\User', array(), array('foo', $backend));

		$user->expects($this->never())
			->method('getUID');
Arthur Schiwon's avatar
Arthur Schiwon committed
566
567
		$user->expects($this->never())
			->method('updateLastLoginTimestamp');
568
569
570
571
572
573
574
575

		$manager->expects($this->once())
			->method('get')
			->with('foo')
			->will($this->returnValue(null));

		//prepare login token
		$token = 'goodToken';
576
		\OC::$server->getConfig()->setUserValue('foo', 'login_token', $token, time());
577

578
		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);
579
580
581
582
		$granted = $userSession->loginWithCookie('foo', $token);

		$this->assertSame($granted, false);
	}
Robin Appelman's avatar
Robin Appelman committed
583
584
585
586
587
588
589
590
591
592
593
594
595
596

	public function testActiveUserAfterSetSession() {
		$users = array(
			'foo' => new User('foo', null),
			'bar' => new User('bar', null)
		);

		$manager = $this->getMockBuilder('\OC\User\Manager')
			->disableOriginalConstructor()
			->getMock();

		$manager->expects($this->any())
			->method('get')
			->will($this->returnCallback(function ($uid) use ($users) {
Christoph Wurst's avatar
Christoph Wurst committed
597
598
					return $users[$uid];
				}));
Robin Appelman's avatar
Robin Appelman committed
599
600
601

		$session = new Memory('');
		$session->set('user_id', 'foo');
Christoph Wurst's avatar
Christoph Wurst committed
602
		$userSession = $this->getMockBuilder('\OC\User\Session')
603
			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config])
Christoph Wurst's avatar
Christoph Wurst committed
604
605
606
607
608
609
610
			->setMethods([
				'validateSession'
			])
			->getMock();
		$userSession->expects($this->any())
			->method('validateSession');

Robin Appelman's avatar
Robin Appelman committed
611
612
613
614
615
616
617
		$this->assertEquals($users['foo'], $userSession->getUser());

		$session2 = new Memory('');
		$session2->set('user_id', 'bar');
		$userSession->setSession($session2);
		$this->assertEquals($users['bar'], $userSession->getUser());
	}
Christoph Wurst's avatar
Christoph Wurst committed
618

619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
	public function testCreateSessionToken() {
		$manager = $this->getMockBuilder('\OC\User\Manager')
			->disableOriginalConstructor()
			->getMock();
		$session = $this->getMock('\OCP\ISession');
		$token = $this->getMock('\OC\Authentication\Token\IToken');
		$user = $this->getMock('\OCP\IUser');
		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);

		$random = $this->getMock('\OCP\Security\ISecureRandom');
		$config = $this->getMock('\OCP\IConfig');
		$csrf = $this->getMockBuilder('\OC\Security\CSRF\CsrfTokenManager')
			->disableOriginalConstructor()
			->getMock();
		$request = new \OC\AppFramework\Http\Request([
			'server' => [
				'HTTP_USER_AGENT' => 'Firefox',
			]
		], $random, $config, $csrf);

		$uid = 'user123';
		$loginName = 'User123';
		$password = 'passme';
		$sessionId = 'abcxyz';

		$manager->expects($this->once())
			->method('get')
			->with($uid)
			->will($this->returnValue($user));
		$session->expects($this->once())
			->method('getId')
			->will($this->returnValue($sessionId));
		$this->tokenProvider->expects($this->once())
			->method('getToken')
			->with($password)
			->will($this->throwException(new \OC\Authentication\Exceptions\InvalidTokenException()));
		
		$this->tokenProvider->expects($this->once())
			->method('generateToken')
			->with($sessionId, $uid, $loginName, $password, 'Firefox');

		$this->assertTrue($userSession->createSessionToken($request, $uid, $loginName, $password));
	}

	public function testCreateSessionTokenWithTokenPassword() {
		$manager = $this->getMockBuilder('\OC\User\Manager')
			->disableOriginalConstructor()
			->getMock();
		$session = $this->getMock('\OCP\ISession');
		$token = $this->getMock('\OC\Authentication\Token\IToken');
		$user = $this->getMock('\OCP\IUser');
		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);

		$random = $this->getMock('\OCP\Security\ISecureRandom');
		$config = $this->getMock('\OCP\IConfig');
		$csrf = $this->getMockBuilder('\OC\Security\CSRF\CsrfTokenManager')
			->disableOriginalConstructor()
			->getMock();
		$request = new \OC\AppFramework\Http\Request([
			'server' => [
				'HTTP_USER_AGENT' => 'Firefox',
			]
		], $random, $config, $csrf);

		$uid = 'user123';
		$loginName = 'User123';
		$password = 'iamatoken';
		$realPassword = 'passme';
		$sessionId = 'abcxyz';

		$manager->expects($this->once())
			->method('get')
			->with($uid)
			->will($this->returnValue($user));
		$session->expects($this->once())
			->method('getId')
			->will($this->returnValue($sessionId));
		$this->tokenProvider->expects($this->once())
			->method('getToken')
			->with($password)
			->will($this->returnValue($token));
		$this->tokenProvider->expects($this->once())
			->method('getPassword')
			->with($token, $password)
			->will($this->returnValue($realPassword));
		
		$this->tokenProvider->expects($this->once())
			->method('generateToken')
			->with($sessionId, $uid, $loginName, $realPassword, 'Firefox');

		$this->assertTrue($userSession->createSessionToken($request, $uid, $loginName, $password));
	}

	public function testCreateSessionTokenWithNonExistentUser() {
		$manager = $this->getMockBuilder('\OC\User\Manager')
			->disableOriginalConstructor()
			->getMock();
		$session = $this->getMock('\OCP\ISession');
		$userSession = new \OC\User\Session($manager, $session, $this->timeFactory, $this->tokenProvider, $this->config);
		$request = $this->getMock('\OCP\IRequest');

		$uid = 'user123';
		$loginName = 'User123';
		$password = 'passme';

		$manager->expects($this->once())
			->method('get')
			->with($uid)
			->will($this->returnValue(null));
		
		$this->assertFalse($userSession->createSessionToken($request, $uid, $loginName, $password));
	}

Christoph Wurst's avatar
Christoph Wurst committed
732
733
734
	/**
	 * @expectedException \OC\User\LoginException
	 */
735
736
737
738
739
	public function testTryTokenLoginWithDisabledUser() {
		$manager = $this->getMockBuilder('\OC\User\Manager')
			->disableOriginalConstructor()
			->getMock();
		$session = new Memory('');
Christoph Wurst's avatar
Christoph Wurst committed
740
741
742
743
		$token = new \OC\Authentication\Token\DefaultToken();
		$token->setLoginName('fritz');
		$token->setUid('fritz0');
		$token->setLastCheck(100); // Needs check
744
		$user = $this->getMock('\OCP\IUser');
Christoph Wurst's avatar
Christoph Wurst committed
745
746
747
748
		$userSession = $this->getMockBuilder('\OC\User\Session')
			->setMethods(['logout'])
			->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config])
			->getMock();
749
750
751
752
753
754
		$request = $this->getMock('\OCP\IRequest');

		$request->expects($this->once())
			->method('getHeader')
			->with('Authorization')
			->will($this->returnValue('token xxxxx'));
755
		$this->tokenProvider->expects($this->once())
Christoph Wurst's avatar
Christoph Wurst committed
756
			->method('getToken')
757
758
759
760
			->with('xxxxx')
			->will($this->returnValue($token));
		$manager->expects($this->once())
			->method('get')
Christoph Wurst's avatar
Christoph Wurst committed
761
			->with('fritz0')
762
763
764
765
766
			->will($this->returnValue($user));
		$user->expects($this->once())
			->method('isEnabled')
			->will($this->returnValue(false));

Christoph Wurst's avatar
Christoph Wurst committed
767
		$userSession->tryTokenLogin($request);
768
769
	}

770
771
772
773
774
775
	public function testValidateSessionDisabledUser() {
		$userManager = $this->getMock('\OCP\IUserManager');
		$session = $this->getMock('\OCP\ISession');
		$timeFactory = $this->getMock('\OCP\AppFramework\Utility\ITimeFactory');
		$tokenProvider = $this->getMock('\OC\Authentication\Token\IProvider');
		$userSession = $this->getMockBuilder('\OC\User\Session')
776
			->setConstructorArgs([$userManager, $session, $timeFactory, $tokenProvider, $this->config])
777
778
779
780
			->setMethods(['logout'])
			->getMock();

		$user = $this->getMock('\OCP\IUser');
Christoph Wurst's avatar
Christoph Wurst committed
781
782
783
		$token = new \OC\Authentication\Token\DefaultToken();
		$token->setLoginName('susan');
		$token->setLastCheck(20);
784
785

		$session->expects($this->once())
Christoph Wurst's avatar
Christoph Wurst committed
786
787
788
			->method('get')
			->with('app_password')
			->will($this->returnValue('APP-PASSWORD'));
789
790
		$tokenProvider->expects($this->once())
			->method('getToken')
Christoph Wurst's avatar
Christoph Wurst committed
791
			->with('APP-PASSWORD')
792
793
794
			->will($this->returnValue($token));
		$timeFactory->expects($this->once())
			->method('getTime')
Christoph Wurst's avatar
Christoph Wurst committed
795
			->will($this->returnValue(1000)); // more than 5min since last check
796
797
		$tokenProvider->expects($this->once())
			->method('getPassword')
Christoph Wurst's avatar
Christoph Wurst committed
798
			->with($token, 'APP-PASSWORD')
799
800
801
			->will($this->returnValue('123456'));
		$userManager->expects($this->once())
			->method('checkPassword')
Christoph Wurst's avatar
Christoph Wurst committed
802
			->with('susan', '123456')
803
804
805
806
			->will($this->returnValue(true));
		$user->expects($this->once())
			->method('isEnabled')
			->will($this->returnValue(false));
Christoph Wurst's avatar
Christoph Wurst committed
807
		$tokenProvider->expects($this->once())
Christoph Wurst's avatar
Christoph Wurst committed
808
			->method('invalidateToken')
Christoph Wurst's avatar
Christoph Wurst committed
809
			->with('APP-PASSWORD');
810
811
812
		$userSession->expects($this->once())
			->method('logout');

Christoph Wurst's avatar
Christoph Wurst committed
813
814
		$userSession->setUser($user);
		$this->invokePrivate($userSession, 'validateSession');
815
816
	}

817
818
819
820
821
822
823
824
825
826
827
	public function testValidateSessionNoPassword() {
		$userManager = $this->getMock('\OCP\IUserManager');
		$session = $this->getMock('\OCP\ISession');
		$timeFactory = $this->getMock('\OCP\AppFramework\Utility\ITimeFactory');
		$tokenProvider = $this->getMock('\OC\Authentication\Token\IProvider');
		$userSession = $this->getMockBuilder('\OC\User\Session')
			->setConstructorArgs([$userManager, $session, $timeFactory, $tokenProvider, $this->config])
			->setMethods(['logout'])
			->getMock();

		$user = $this->getMock('\OCP\IUser');
Christoph Wurst's avatar
Christoph Wurst committed
828
829
		$token = new \OC\Authentication\Token\DefaultToken();
		$token->setLastCheck(20);
830
831

		$session->expects($this->once())
Christoph Wurst's avatar
Christoph Wurst committed
832
833
834
			->method('get')
			->with('app_password')
			->will($this->returnValue('APP-PASSWORD'));
835
836
		$tokenProvider->expects($this->once())
			->method('getToken')
Christoph Wurst's avatar
Christoph Wurst committed
837
			->with('APP-PASSWORD')
838
839
840
			->will($this->returnValue($token));
		$timeFactory->expects($this->once())
			->method('getTime')
Christoph Wurst's avatar
Christoph Wurst committed
841
			->will($this->returnValue(1000)); // more than 5min since last check
842
843
		$tokenProvider->expects($this->once())
			->method('getPassword')
Christoph Wurst's avatar
Christoph Wurst committed
844
			->with($token, 'APP-PASSWORD')
845
			->will($this->throwException(new \OC\Authentication\Exceptions\PasswordlessTokenException()));
Christoph Wurst's avatar
Christoph Wurst committed
846
847
848
		$tokenProvider->expects($this->once())
			->method('updateToken')
			->with($token);
849
850

		$this->invokePrivate($userSession, 'validateSession', [$user]);
Christoph Wurst's avatar
Christoph Wurst committed
851
852

		$this->assertEquals(1000, $token->getLastCheck());
853
854
	}

855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
	public function testUpdateSessionTokenPassword() {
		$userManager = $this->getMock('\OCP\IUserManager');
		$session = $this->getMock('\OCP\ISession');
		$timeFactory = $this->getMock('\OCP\AppFramework\Utility\ITimeFactory');
		$tokenProvider = $this->getMock('\OC\Authentication\Token\IProvider');
		$userSession = new \OC\User\Session($userManager, $session, $timeFactory, $tokenProvider, $this->config);

		$password = '123456';
		$sessionId ='session1234';
		$token = new \OC\Authentication\Token\DefaultToken();

		$session->expects($this->once())
			->method('getId')
			->will($this->returnValue($sessionId));
		$tokenProvider->expects($this->once())
			->method('getToken')
			->with($sessionId)
			->will($this->returnValue($token));
		$tokenProvider->expects($this->once())
			->method('setPassword')
			->with($token, $sessionId, $password);

		$userSession->updateSessionTokenPassword($password);
	}

	public function testUpdateSessionTokenPasswordNoSessionAvailable() {
		$userManager = $this->getMock('\OCP\IUserManager');
		$session = $this->getMock('\OCP\ISession');
		$timeFactory = $this->getMock('\OCP\AppFramework\Utility\ITimeFactory');
		$tokenProvider = $this->getMock('\OC\Authentication\Token\IProvider');
		$userSession = new \OC\User\Session($userManager, $session, $timeFactory, $tokenProvider, $this->config);

		$session->expects($this->once())
			->method('getId')
			->will($this->throwException(new \OCP\Session\Exceptions\SessionNotAvailableException()));

		$userSession->updateSessionTokenPassword('1234');
	}

	public function testUpdateSessionTokenPasswordInvalidTokenException() {
		$userManager = $this->getMock('\OCP\IUserManager');
		$session = $this->getMock('\OCP\ISession');
		$timeFactory = $this->getMock('\OCP\AppFramework\Utility\ITimeFactory');
		$tokenProvider = $this->getMock('\OC\Authentication\Token\IProvider');
		$userSession = new \OC\User\Session($userManager, $session, $timeFactory, $tokenProvider, $this->config);

		$password = '123456';
		$sessionId ='session1234';
		$token = new \OC\Authentication\Token\DefaultToken();

		$session->expects($this->once())
			->method('getId')
			->will($this->returnValue($sessionId));
		$tokenProvider->expects($this->once())
			->method('getToken')
			->with($sessionId)
			->will($this->returnValue($token));
		$tokenProvider->expects($this->once())
			->method('setPassword')
			->with($token, $sessionId, $password)
			->will($this->throwException(new \OC\Authentication\Exceptions\InvalidTokenException()));

		$userSession->updateSessionTokenPassword($password);
	}

Robin Appelman's avatar
Robin Appelman committed
920
}