Completed
Pull Request — master (#4704)
by Björn
16:36
created
apps/oauth2/lib/Settings/Admin.php 1 patch
Indentation   +33 added lines, -33 removed lines patch added patch discarded remove patch
@@ -27,41 +27,41 @@
 block discarded – undo
27 27
 use OCP\Settings\ISettings;
28 28
 
29 29
 class Admin implements ISettings {
30
-	/** @var ClientMapper */
31
-	private $clientMapper;
30
+    /** @var ClientMapper */
31
+    private $clientMapper;
32 32
 
33
-	/**
34
-	 * @param ClientMapper $clientMapper
35
-	 */
36
-	public function __construct(ClientMapper $clientMapper) {
37
-		$this->clientMapper = $clientMapper;
38
-	}
33
+    /**
34
+     * @param ClientMapper $clientMapper
35
+     */
36
+    public function __construct(ClientMapper $clientMapper) {
37
+        $this->clientMapper = $clientMapper;
38
+    }
39 39
 
40
-	/**
41
-	 * @return TemplateResponse
42
-	 */
43
-	public function getForm() {
44
-		return new TemplateResponse(
45
-			'oauth2',
46
-			'admin',
47
-			[
48
-				'clients' => $this->clientMapper->getClients(),
49
-			],
50
-			''
51
-		);
52
-	}
40
+    /**
41
+     * @return TemplateResponse
42
+     */
43
+    public function getForm() {
44
+        return new TemplateResponse(
45
+            'oauth2',
46
+            'admin',
47
+            [
48
+                'clients' => $this->clientMapper->getClients(),
49
+            ],
50
+            ''
51
+        );
52
+    }
53 53
 
54
-	/**
55
-	 * {@inheritdoc}
56
-	 */
57
-	public function getSection() {
58
-		return 'security';
59
-	}
54
+    /**
55
+     * {@inheritdoc}
56
+     */
57
+    public function getSection() {
58
+        return 'security';
59
+    }
60 60
 
61
-	/**
62
-	 * {@inheritdoc}
63
-	 */
64
-	public function getPriority() {
65
-		return 0;
66
-	}
61
+    /**
62
+     * {@inheritdoc}
63
+     */
64
+    public function getPriority() {
65
+        return 0;
66
+    }
67 67
 }
Please login to merge, or discard this patch.
apps/dav/lib/Connector/Sabre/Auth.php 2 patches
Indentation   +203 added lines, -203 removed lines patch added patch discarded remove patch
@@ -48,225 +48,225 @@
 block discarded – undo
48 48
 class Auth extends AbstractBasic {
49 49
 
50 50
 
51
-	const DAV_AUTHENTICATED = 'AUTHENTICATED_TO_DAV_BACKEND';
51
+    const DAV_AUTHENTICATED = 'AUTHENTICATED_TO_DAV_BACKEND';
52 52
 
53
-	/** @var ISession */
54
-	private $session;
55
-	/** @var Session */
56
-	private $userSession;
57
-	/** @var IRequest */
58
-	private $request;
59
-	/** @var string */
60
-	private $currentUser;
61
-	/** @var Manager */
62
-	private $twoFactorManager;
63
-	/** @var Throttler */
64
-	private $throttler;
53
+    /** @var ISession */
54
+    private $session;
55
+    /** @var Session */
56
+    private $userSession;
57
+    /** @var IRequest */
58
+    private $request;
59
+    /** @var string */
60
+    private $currentUser;
61
+    /** @var Manager */
62
+    private $twoFactorManager;
63
+    /** @var Throttler */
64
+    private $throttler;
65 65
 
66
-	/**
67
-	 * @param ISession $session
68
-	 * @param Session $userSession
69
-	 * @param IRequest $request
70
-	 * @param Manager $twoFactorManager
71
-	 * @param Throttler $throttler
72
-	 * @param string $principalPrefix
73
-	 */
74
-	public function __construct(ISession $session,
75
-								Session $userSession,
76
-								IRequest $request,
77
-								Manager $twoFactorManager,
78
-								Throttler $throttler,
79
-								$principalPrefix = 'principals/users/') {
80
-		$this->session = $session;
81
-		$this->userSession = $userSession;
82
-		$this->twoFactorManager = $twoFactorManager;
83
-		$this->request = $request;
84
-		$this->throttler = $throttler;
85
-		$this->principalPrefix = $principalPrefix;
66
+    /**
67
+     * @param ISession $session
68
+     * @param Session $userSession
69
+     * @param IRequest $request
70
+     * @param Manager $twoFactorManager
71
+     * @param Throttler $throttler
72
+     * @param string $principalPrefix
73
+     */
74
+    public function __construct(ISession $session,
75
+                                Session $userSession,
76
+                                IRequest $request,
77
+                                Manager $twoFactorManager,
78
+                                Throttler $throttler,
79
+                                $principalPrefix = 'principals/users/') {
80
+        $this->session = $session;
81
+        $this->userSession = $userSession;
82
+        $this->twoFactorManager = $twoFactorManager;
83
+        $this->request = $request;
84
+        $this->throttler = $throttler;
85
+        $this->principalPrefix = $principalPrefix;
86 86
 
87
-		// setup realm
88
-		$defaults = new \OCP\Defaults();
89
-		$this->realm = $defaults->getName();
90
-	}
87
+        // setup realm
88
+        $defaults = new \OCP\Defaults();
89
+        $this->realm = $defaults->getName();
90
+    }
91 91
 
92
-	/**
93
-	 * Whether the user has initially authenticated via DAV
94
-	 *
95
-	 * This is required for WebDAV clients that resent the cookies even when the
96
-	 * account was changed.
97
-	 *
98
-	 * @see https://github.com/owncloud/core/issues/13245
99
-	 *
100
-	 * @param string $username
101
-	 * @return bool
102
-	 */
103
-	public function isDavAuthenticated($username) {
104
-		return !is_null($this->session->get(self::DAV_AUTHENTICATED)) &&
105
-		$this->session->get(self::DAV_AUTHENTICATED) === $username;
106
-	}
92
+    /**
93
+     * Whether the user has initially authenticated via DAV
94
+     *
95
+     * This is required for WebDAV clients that resent the cookies even when the
96
+     * account was changed.
97
+     *
98
+     * @see https://github.com/owncloud/core/issues/13245
99
+     *
100
+     * @param string $username
101
+     * @return bool
102
+     */
103
+    public function isDavAuthenticated($username) {
104
+        return !is_null($this->session->get(self::DAV_AUTHENTICATED)) &&
105
+        $this->session->get(self::DAV_AUTHENTICATED) === $username;
106
+    }
107 107
 
108
-	/**
109
-	 * Validates a username and password
110
-	 *
111
-	 * This method should return true or false depending on if login
112
-	 * succeeded.
113
-	 *
114
-	 * @param string $username
115
-	 * @param string $password
116
-	 * @return bool
117
-	 * @throws PasswordLoginForbidden
118
-	 */
119
-	protected function validateUserPass($username, $password) {
120
-		if ($this->userSession->isLoggedIn() &&
121
-			$this->isDavAuthenticated($this->userSession->getUser()->getUID())
122
-		) {
123
-			\OC_Util::setupFS($this->userSession->getUser()->getUID());
124
-			$this->session->close();
125
-			return true;
126
-		} else {
127
-			\OC_Util::setupFS(); //login hooks may need early access to the filesystem
128
-			try {
129
-				if ($this->userSession->logClientIn($username, $password, $this->request, $this->throttler)) {
130
-					\OC_Util::setupFS($this->userSession->getUser()->getUID());
131
-					$this->session->set(self::DAV_AUTHENTICATED, $this->userSession->getUser()->getUID());
132
-					$this->session->close();
133
-					return true;
134
-				} else {
135
-					$this->session->close();
136
-					return false;
137
-				}
138
-			} catch (PasswordLoginForbiddenException $ex) {
139
-				$this->session->close();
140
-				throw new PasswordLoginForbidden();
141
-			}
142
-		}
143
-	}
108
+    /**
109
+     * Validates a username and password
110
+     *
111
+     * This method should return true or false depending on if login
112
+     * succeeded.
113
+     *
114
+     * @param string $username
115
+     * @param string $password
116
+     * @return bool
117
+     * @throws PasswordLoginForbidden
118
+     */
119
+    protected function validateUserPass($username, $password) {
120
+        if ($this->userSession->isLoggedIn() &&
121
+            $this->isDavAuthenticated($this->userSession->getUser()->getUID())
122
+        ) {
123
+            \OC_Util::setupFS($this->userSession->getUser()->getUID());
124
+            $this->session->close();
125
+            return true;
126
+        } else {
127
+            \OC_Util::setupFS(); //login hooks may need early access to the filesystem
128
+            try {
129
+                if ($this->userSession->logClientIn($username, $password, $this->request, $this->throttler)) {
130
+                    \OC_Util::setupFS($this->userSession->getUser()->getUID());
131
+                    $this->session->set(self::DAV_AUTHENTICATED, $this->userSession->getUser()->getUID());
132
+                    $this->session->close();
133
+                    return true;
134
+                } else {
135
+                    $this->session->close();
136
+                    return false;
137
+                }
138
+            } catch (PasswordLoginForbiddenException $ex) {
139
+                $this->session->close();
140
+                throw new PasswordLoginForbidden();
141
+            }
142
+        }
143
+    }
144 144
 
145
-	/**
146
-	 * @param RequestInterface $request
147
-	 * @param ResponseInterface $response
148
-	 * @return array
149
-	 * @throws NotAuthenticated
150
-	 * @throws ServiceUnavailable
151
-	 */
152
-	function check(RequestInterface $request, ResponseInterface $response) {
153
-		try {
154
-			$result = $this->auth($request, $response);
155
-			return $result;
156
-		} catch (NotAuthenticated $e) {
157
-			throw $e;
158
-		} catch (Exception $e) {
159
-			$class = get_class($e);
160
-			$msg = $e->getMessage();
161
-			\OC::$server->getLogger()->logException($e);
162
-			throw new ServiceUnavailable("$class: $msg");
163
-		}
164
-	}
145
+    /**
146
+     * @param RequestInterface $request
147
+     * @param ResponseInterface $response
148
+     * @return array
149
+     * @throws NotAuthenticated
150
+     * @throws ServiceUnavailable
151
+     */
152
+    function check(RequestInterface $request, ResponseInterface $response) {
153
+        try {
154
+            $result = $this->auth($request, $response);
155
+            return $result;
156
+        } catch (NotAuthenticated $e) {
157
+            throw $e;
158
+        } catch (Exception $e) {
159
+            $class = get_class($e);
160
+            $msg = $e->getMessage();
161
+            \OC::$server->getLogger()->logException($e);
162
+            throw new ServiceUnavailable("$class: $msg");
163
+        }
164
+    }
165 165
 
166
-	/**
167
-	 * Checks whether a CSRF check is required on the request
168
-	 *
169
-	 * @return bool
170
-	 */
171
-	private function requiresCSRFCheck() {
172
-		// GET requires no check at all
173
-		if($this->request->getMethod() === 'GET') {
174
-			return false;
175
-		}
166
+    /**
167
+     * Checks whether a CSRF check is required on the request
168
+     *
169
+     * @return bool
170
+     */
171
+    private function requiresCSRFCheck() {
172
+        // GET requires no check at all
173
+        if($this->request->getMethod() === 'GET') {
174
+            return false;
175
+        }
176 176
 
177
-		// Official Nextcloud clients require no checks
178
-		if($this->request->isUserAgent([
179
-			IRequest::USER_AGENT_CLIENT_DESKTOP,
180
-			IRequest::USER_AGENT_CLIENT_ANDROID,
181
-			IRequest::USER_AGENT_CLIENT_IOS,
182
-		])) {
183
-			return false;
184
-		}
177
+        // Official Nextcloud clients require no checks
178
+        if($this->request->isUserAgent([
179
+            IRequest::USER_AGENT_CLIENT_DESKTOP,
180
+            IRequest::USER_AGENT_CLIENT_ANDROID,
181
+            IRequest::USER_AGENT_CLIENT_IOS,
182
+        ])) {
183
+            return false;
184
+        }
185 185
 
186
-		// If not logged-in no check is required
187
-		if(!$this->userSession->isLoggedIn()) {
188
-			return false;
189
-		}
186
+        // If not logged-in no check is required
187
+        if(!$this->userSession->isLoggedIn()) {
188
+            return false;
189
+        }
190 190
 
191
-		// POST always requires a check
192
-		if($this->request->getMethod() === 'POST') {
193
-			return true;
194
-		}
191
+        // POST always requires a check
192
+        if($this->request->getMethod() === 'POST') {
193
+            return true;
194
+        }
195 195
 
196
-		// If logged-in AND DAV authenticated no check is required
197
-		if($this->userSession->isLoggedIn() &&
198
-			$this->isDavAuthenticated($this->userSession->getUser()->getUID())) {
199
-			return false;
200
-		}
196
+        // If logged-in AND DAV authenticated no check is required
197
+        if($this->userSession->isLoggedIn() &&
198
+            $this->isDavAuthenticated($this->userSession->getUser()->getUID())) {
199
+            return false;
200
+        }
201 201
 
202
-		return true;
203
-	}
202
+        return true;
203
+    }
204 204
 
205
-	/**
206
-	 * @param RequestInterface $request
207
-	 * @param ResponseInterface $response
208
-	 * @return array
209
-	 * @throws NotAuthenticated
210
-	 */
211
-	private function auth(RequestInterface $request, ResponseInterface $response) {
212
-		$forcedLogout = false;
205
+    /**
206
+     * @param RequestInterface $request
207
+     * @param ResponseInterface $response
208
+     * @return array
209
+     * @throws NotAuthenticated
210
+     */
211
+    private function auth(RequestInterface $request, ResponseInterface $response) {
212
+        $forcedLogout = false;
213 213
 
214
-		$authHeader = $request->getHeader('Authorization');
215
-		if (strpos($authHeader, 'Bearer ') !== false) {
216
-			if($this->userSession->tryTokenLogin($this->request)) {
217
-				$this->session->set(self::DAV_AUTHENTICATED, $this->userSession->getUser()->getUID());
218
-				$user = $this->userSession->getUser()->getUID();
219
-				\OC_Util::setupFS($user);
220
-				$this->currentUser = $user;
221
-				$this->session->close();
222
-				return [true, $this->principalPrefix . $user];
223
-			}
224
-		}
214
+        $authHeader = $request->getHeader('Authorization');
215
+        if (strpos($authHeader, 'Bearer ') !== false) {
216
+            if($this->userSession->tryTokenLogin($this->request)) {
217
+                $this->session->set(self::DAV_AUTHENTICATED, $this->userSession->getUser()->getUID());
218
+                $user = $this->userSession->getUser()->getUID();
219
+                \OC_Util::setupFS($user);
220
+                $this->currentUser = $user;
221
+                $this->session->close();
222
+                return [true, $this->principalPrefix . $user];
223
+            }
224
+        }
225 225
 
226
-		if(!$this->request->passesCSRFCheck() &&
227
-			$this->requiresCSRFCheck()) {
228
-			// In case of a fail with POST we need to recheck the credentials
229
-			if($this->request->getMethod() === 'POST') {
230
-				$forcedLogout = true;
231
-			} else {
232
-				$response->setStatus(401);
233
-				throw new \Sabre\DAV\Exception\NotAuthenticated('CSRF check not passed.');
234
-			}
235
-		}
226
+        if(!$this->request->passesCSRFCheck() &&
227
+            $this->requiresCSRFCheck()) {
228
+            // In case of a fail with POST we need to recheck the credentials
229
+            if($this->request->getMethod() === 'POST') {
230
+                $forcedLogout = true;
231
+            } else {
232
+                $response->setStatus(401);
233
+                throw new \Sabre\DAV\Exception\NotAuthenticated('CSRF check not passed.');
234
+            }
235
+        }
236 236
 
237
-		if($forcedLogout) {
238
-			$this->userSession->logout();
239
-		} else {
240
-			if($this->twoFactorManager->needsSecondFactor($this->userSession->getUser())) {
241
-				throw new \Sabre\DAV\Exception\NotAuthenticated('2FA challenge not passed.');
242
-			}
243
-			if (\OC_User::handleApacheAuth() ||
244
-				//Fix for broken webdav clients
245
-				($this->userSession->isLoggedIn() && is_null($this->session->get(self::DAV_AUTHENTICATED))) ||
246
-				//Well behaved clients that only send the cookie are allowed
247
-				($this->userSession->isLoggedIn() && $this->session->get(self::DAV_AUTHENTICATED) === $this->userSession->getUser()->getUID() && $request->getHeader('Authorization') === null)
248
-			) {
249
-				$user = $this->userSession->getUser()->getUID();
250
-				\OC_Util::setupFS($user);
251
-				$this->currentUser = $user;
252
-				$this->session->close();
253
-				return [true, $this->principalPrefix . $user];
254
-			}
255
-		}
237
+        if($forcedLogout) {
238
+            $this->userSession->logout();
239
+        } else {
240
+            if($this->twoFactorManager->needsSecondFactor($this->userSession->getUser())) {
241
+                throw new \Sabre\DAV\Exception\NotAuthenticated('2FA challenge not passed.');
242
+            }
243
+            if (\OC_User::handleApacheAuth() ||
244
+                //Fix for broken webdav clients
245
+                ($this->userSession->isLoggedIn() && is_null($this->session->get(self::DAV_AUTHENTICATED))) ||
246
+                //Well behaved clients that only send the cookie are allowed
247
+                ($this->userSession->isLoggedIn() && $this->session->get(self::DAV_AUTHENTICATED) === $this->userSession->getUser()->getUID() && $request->getHeader('Authorization') === null)
248
+            ) {
249
+                $user = $this->userSession->getUser()->getUID();
250
+                \OC_Util::setupFS($user);
251
+                $this->currentUser = $user;
252
+                $this->session->close();
253
+                return [true, $this->principalPrefix . $user];
254
+            }
255
+        }
256 256
 
257
-		if (!$this->userSession->isLoggedIn() && in_array('XMLHttpRequest', explode(',', $request->getHeader('X-Requested-With')))) {
258
-			// do not re-authenticate over ajax, use dummy auth name to prevent browser popup
259
-			$response->addHeader('WWW-Authenticate','DummyBasic realm="' . $this->realm . '"');
260
-			$response->setStatus(401);
261
-			throw new \Sabre\DAV\Exception\NotAuthenticated('Cannot authenticate over ajax calls');
262
-		}
257
+        if (!$this->userSession->isLoggedIn() && in_array('XMLHttpRequest', explode(',', $request->getHeader('X-Requested-With')))) {
258
+            // do not re-authenticate over ajax, use dummy auth name to prevent browser popup
259
+            $response->addHeader('WWW-Authenticate','DummyBasic realm="' . $this->realm . '"');
260
+            $response->setStatus(401);
261
+            throw new \Sabre\DAV\Exception\NotAuthenticated('Cannot authenticate over ajax calls');
262
+        }
263 263
 
264
-		$data = parent::check($request, $response);
265
-		if($data[0] === true) {
266
-			$startPos = strrpos($data[1], '/') + 1;
267
-			$user = $this->userSession->getUser()->getUID();
268
-			$data[1] = substr_replace($data[1], $user, $startPos);
269
-		}
270
-		return $data;
271
-	}
264
+        $data = parent::check($request, $response);
265
+        if($data[0] === true) {
266
+            $startPos = strrpos($data[1], '/') + 1;
267
+            $user = $this->userSession->getUser()->getUID();
268
+            $data[1] = substr_replace($data[1], $user, $startPos);
269
+        }
270
+        return $data;
271
+    }
272 272
 }
Please login to merge, or discard this patch.
Spacing   +14 added lines, -14 removed lines patch added patch discarded remove patch
@@ -170,12 +170,12 @@  discard block
 block discarded – undo
170 170
 	 */
171 171
 	private function requiresCSRFCheck() {
172 172
 		// GET requires no check at all
173
-		if($this->request->getMethod() === 'GET') {
173
+		if ($this->request->getMethod() === 'GET') {
174 174
 			return false;
175 175
 		}
176 176
 
177 177
 		// Official Nextcloud clients require no checks
178
-		if($this->request->isUserAgent([
178
+		if ($this->request->isUserAgent([
179 179
 			IRequest::USER_AGENT_CLIENT_DESKTOP,
180 180
 			IRequest::USER_AGENT_CLIENT_ANDROID,
181 181
 			IRequest::USER_AGENT_CLIENT_IOS,
@@ -184,17 +184,17 @@  discard block
 block discarded – undo
184 184
 		}
185 185
 
186 186
 		// If not logged-in no check is required
187
-		if(!$this->userSession->isLoggedIn()) {
187
+		if (!$this->userSession->isLoggedIn()) {
188 188
 			return false;
189 189
 		}
190 190
 
191 191
 		// POST always requires a check
192
-		if($this->request->getMethod() === 'POST') {
192
+		if ($this->request->getMethod() === 'POST') {
193 193
 			return true;
194 194
 		}
195 195
 
196 196
 		// If logged-in AND DAV authenticated no check is required
197
-		if($this->userSession->isLoggedIn() &&
197
+		if ($this->userSession->isLoggedIn() &&
198 198
 			$this->isDavAuthenticated($this->userSession->getUser()->getUID())) {
199 199
 			return false;
200 200
 		}
@@ -213,20 +213,20 @@  discard block
 block discarded – undo
213 213
 
214 214
 		$authHeader = $request->getHeader('Authorization');
215 215
 		if (strpos($authHeader, 'Bearer ') !== false) {
216
-			if($this->userSession->tryTokenLogin($this->request)) {
216
+			if ($this->userSession->tryTokenLogin($this->request)) {
217 217
 				$this->session->set(self::DAV_AUTHENTICATED, $this->userSession->getUser()->getUID());
218 218
 				$user = $this->userSession->getUser()->getUID();
219 219
 				\OC_Util::setupFS($user);
220 220
 				$this->currentUser = $user;
221 221
 				$this->session->close();
222
-				return [true, $this->principalPrefix . $user];
222
+				return [true, $this->principalPrefix.$user];
223 223
 			}
224 224
 		}
225 225
 
226
-		if(!$this->request->passesCSRFCheck() &&
226
+		if (!$this->request->passesCSRFCheck() &&
227 227
 			$this->requiresCSRFCheck()) {
228 228
 			// In case of a fail with POST we need to recheck the credentials
229
-			if($this->request->getMethod() === 'POST') {
229
+			if ($this->request->getMethod() === 'POST') {
230 230
 				$forcedLogout = true;
231 231
 			} else {
232 232
 				$response->setStatus(401);
@@ -234,10 +234,10 @@  discard block
 block discarded – undo
234 234
 			}
235 235
 		}
236 236
 
237
-		if($forcedLogout) {
237
+		if ($forcedLogout) {
238 238
 			$this->userSession->logout();
239 239
 		} else {
240
-			if($this->twoFactorManager->needsSecondFactor($this->userSession->getUser())) {
240
+			if ($this->twoFactorManager->needsSecondFactor($this->userSession->getUser())) {
241 241
 				throw new \Sabre\DAV\Exception\NotAuthenticated('2FA challenge not passed.');
242 242
 			}
243 243
 			if (\OC_User::handleApacheAuth() ||
@@ -250,19 +250,19 @@  discard block
 block discarded – undo
250 250
 				\OC_Util::setupFS($user);
251 251
 				$this->currentUser = $user;
252 252
 				$this->session->close();
253
-				return [true, $this->principalPrefix . $user];
253
+				return [true, $this->principalPrefix.$user];
254 254
 			}
255 255
 		}
256 256
 
257 257
 		if (!$this->userSession->isLoggedIn() && in_array('XMLHttpRequest', explode(',', $request->getHeader('X-Requested-With')))) {
258 258
 			// do not re-authenticate over ajax, use dummy auth name to prevent browser popup
259
-			$response->addHeader('WWW-Authenticate','DummyBasic realm="' . $this->realm . '"');
259
+			$response->addHeader('WWW-Authenticate', 'DummyBasic realm="'.$this->realm.'"');
260 260
 			$response->setStatus(401);
261 261
 			throw new \Sabre\DAV\Exception\NotAuthenticated('Cannot authenticate over ajax calls');
262 262
 		}
263 263
 
264 264
 		$data = parent::check($request, $response);
265
-		if($data[0] === true) {
265
+		if ($data[0] === true) {
266 266
 			$startPos = strrpos($data[1], '/') + 1;
267 267
 			$user = $this->userSession->getUser()->getUID();
268 268
 			$data[1] = substr_replace($data[1], $user, $startPos);
Please login to merge, or discard this patch.
lib/private/User/Session.php 1 patch
Indentation   +805 added lines, -805 removed lines patch added patch discarded remove patch
@@ -80,811 +80,811 @@
 block discarded – undo
80 80
  */
81 81
 class Session implements IUserSession, Emitter {
82 82
 
83
-	/** @var IUserManager|PublicEmitter $manager */
84
-	private $manager;
85
-
86
-	/** @var ISession $session */
87
-	private $session;
88
-
89
-	/** @var ITimeFactory */
90
-	private $timeFactory;
91
-
92
-	/** @var IProvider */
93
-	private $tokenProvider;
94
-
95
-	/** @var IConfig */
96
-	private $config;
97
-
98
-	/** @var User $activeUser */
99
-	protected $activeUser;
100
-
101
-	/** @var ISecureRandom */
102
-	private $random;
103
-
104
-	/** @var ILockdownManager  */
105
-	private $lockdownManager;
106
-
107
-	/**
108
-	 * @param IUserManager $manager
109
-	 * @param ISession $session
110
-	 * @param ITimeFactory $timeFactory
111
-	 * @param IProvider $tokenProvider
112
-	 * @param IConfig $config
113
-	 * @param ISecureRandom $random
114
-	 * @param ILockdownManager $lockdownManager
115
-	 */
116
-	public function __construct(IUserManager $manager,
117
-								ISession $session,
118
-								ITimeFactory $timeFactory,
119
-								$tokenProvider,
120
-								IConfig $config,
121
-								ISecureRandom $random,
122
-								ILockdownManager $lockdownManager
123
-	) {
124
-		$this->manager = $manager;
125
-		$this->session = $session;
126
-		$this->timeFactory = $timeFactory;
127
-		$this->tokenProvider = $tokenProvider;
128
-		$this->config = $config;
129
-		$this->random = $random;
130
-		$this->lockdownManager = $lockdownManager;
131
-	}
132
-
133
-	/**
134
-	 * @param IProvider $provider
135
-	 */
136
-	public function setTokenProvider(IProvider $provider) {
137
-		$this->tokenProvider = $provider;
138
-	}
139
-
140
-	/**
141
-	 * @param string $scope
142
-	 * @param string $method
143
-	 * @param callable $callback
144
-	 */
145
-	public function listen($scope, $method, callable $callback) {
146
-		$this->manager->listen($scope, $method, $callback);
147
-	}
148
-
149
-	/**
150
-	 * @param string $scope optional
151
-	 * @param string $method optional
152
-	 * @param callable $callback optional
153
-	 */
154
-	public function removeListener($scope = null, $method = null, callable $callback = null) {
155
-		$this->manager->removeListener($scope, $method, $callback);
156
-	}
157
-
158
-	/**
159
-	 * get the manager object
160
-	 *
161
-	 * @return Manager|PublicEmitter
162
-	 */
163
-	public function getManager() {
164
-		return $this->manager;
165
-	}
166
-
167
-	/**
168
-	 * get the session object
169
-	 *
170
-	 * @return ISession
171
-	 */
172
-	public function getSession() {
173
-		return $this->session;
174
-	}
175
-
176
-	/**
177
-	 * set the session object
178
-	 *
179
-	 * @param ISession $session
180
-	 */
181
-	public function setSession(ISession $session) {
182
-		if ($this->session instanceof ISession) {
183
-			$this->session->close();
184
-		}
185
-		$this->session = $session;
186
-		$this->activeUser = null;
187
-	}
188
-
189
-	/**
190
-	 * set the currently active user
191
-	 *
192
-	 * @param IUser|null $user
193
-	 */
194
-	public function setUser($user) {
195
-		if (is_null($user)) {
196
-			$this->session->remove('user_id');
197
-		} else {
198
-			$this->session->set('user_id', $user->getUID());
199
-		}
200
-		$this->activeUser = $user;
201
-	}
202
-
203
-	/**
204
-	 * get the current active user
205
-	 *
206
-	 * @return IUser|null Current user, otherwise null
207
-	 */
208
-	public function getUser() {
209
-		// FIXME: This is a quick'n dirty work-around for the incognito mode as
210
-		// described at https://github.com/owncloud/core/pull/12912#issuecomment-67391155
211
-		if (OC_User::isIncognitoMode()) {
212
-			return null;
213
-		}
214
-		if (is_null($this->activeUser)) {
215
-			$uid = $this->session->get('user_id');
216
-			if (is_null($uid)) {
217
-				return null;
218
-			}
219
-			$this->activeUser = $this->manager->get($uid);
220
-			if (is_null($this->activeUser)) {
221
-				return null;
222
-			}
223
-			$this->validateSession();
224
-		}
225
-		return $this->activeUser;
226
-	}
227
-
228
-	/**
229
-	 * Validate whether the current session is valid
230
-	 *
231
-	 * - For token-authenticated clients, the token validity is checked
232
-	 * - For browsers, the session token validity is checked
233
-	 */
234
-	protected function validateSession() {
235
-		$token = null;
236
-		$appPassword = $this->session->get('app_password');
237
-
238
-		if (is_null($appPassword)) {
239
-			try {
240
-				$token = $this->session->getId();
241
-			} catch (SessionNotAvailableException $ex) {
242
-				return;
243
-			}
244
-		} else {
245
-			$token = $appPassword;
246
-		}
247
-
248
-		if (!$this->validateToken($token)) {
249
-			// Session was invalidated
250
-			$this->logout();
251
-		}
252
-	}
253
-
254
-	/**
255
-	 * Checks whether the user is logged in
256
-	 *
257
-	 * @return bool if logged in
258
-	 */
259
-	public function isLoggedIn() {
260
-		$user = $this->getUser();
261
-		if (is_null($user)) {
262
-			return false;
263
-		}
264
-
265
-		return $user->isEnabled();
266
-	}
267
-
268
-	/**
269
-	 * set the login name
270
-	 *
271
-	 * @param string|null $loginName for the logged in user
272
-	 */
273
-	public function setLoginName($loginName) {
274
-		if (is_null($loginName)) {
275
-			$this->session->remove('loginname');
276
-		} else {
277
-			$this->session->set('loginname', $loginName);
278
-		}
279
-	}
280
-
281
-	/**
282
-	 * get the login name of the current user
283
-	 *
284
-	 * @return string
285
-	 */
286
-	public function getLoginName() {
287
-		if ($this->activeUser) {
288
-			return $this->session->get('loginname');
289
-		} else {
290
-			$uid = $this->session->get('user_id');
291
-			if ($uid) {
292
-				$this->activeUser = $this->manager->get($uid);
293
-				return $this->session->get('loginname');
294
-			} else {
295
-				return null;
296
-			}
297
-		}
298
-	}
299
-
300
-	/**
301
-	 * set the token id
302
-	 *
303
-	 * @param int|null $token that was used to log in
304
-	 */
305
-	protected function setToken($token) {
306
-		if ($token === null) {
307
-			$this->session->remove('token-id');
308
-		} else {
309
-			$this->session->set('token-id', $token);
310
-		}
311
-	}
312
-
313
-	/**
314
-	 * try to log in with the provided credentials
315
-	 *
316
-	 * @param string $uid
317
-	 * @param string $password
318
-	 * @return boolean|null
319
-	 * @throws LoginException
320
-	 */
321
-	public function login($uid, $password) {
322
-		$this->session->regenerateId();
323
-		if ($this->validateToken($password, $uid)) {
324
-			return $this->loginWithToken($password);
325
-		}
326
-		return $this->loginWithPassword($uid, $password);
327
-	}
328
-
329
-	/**
330
-	 * @param IUser $user
331
-	 * @param array $loginDetails
332
-	 * @param bool $regenerateSessionId
333
-	 * @return true returns true if login successful or an exception otherwise
334
-	 * @throws LoginException
335
-	 */
336
-	public function completeLogin(IUser $user, array $loginDetails, $regenerateSessionId = true) {
337
-		if (!$user->isEnabled()) {
338
-			// disabled users can not log in
339
-			// injecting l10n does not work - there is a circular dependency between session and \OCP\L10N\IFactory
340
-			$message = \OC::$server->getL10N('lib')->t('User disabled');
341
-			throw new LoginException($message);
342
-		}
343
-
344
-		if($regenerateSessionId) {
345
-			$this->session->regenerateId();
346
-		}
347
-
348
-		$this->setUser($user);
349
-		$this->setLoginName($loginDetails['loginName']);
350
-
351
-		if(isset($loginDetails['token']) && $loginDetails['token'] instanceof IToken) {
352
-			$this->setToken($loginDetails['token']->getId());
353
-			$this->lockdownManager->setToken($loginDetails['token']);
354
-			$firstTimeLogin = false;
355
-		} else {
356
-			$this->setToken(null);
357
-			$firstTimeLogin = $user->updateLastLoginTimestamp();
358
-		}
359
-		$this->manager->emit('\OC\User', 'postLogin', [$user, $loginDetails['password']]);
360
-		if($this->isLoggedIn()) {
361
-			$this->prepareUserLogin($firstTimeLogin);
362
-			return true;
363
-		} else {
364
-			$message = \OC::$server->getL10N('lib')->t('Login canceled by app');
365
-			throw new LoginException($message);
366
-		}
367
-	}
368
-
369
-	/**
370
-	 * Tries to log in a client
371
-	 *
372
-	 * Checks token auth enforced
373
-	 * Checks 2FA enabled
374
-	 *
375
-	 * @param string $user
376
-	 * @param string $password
377
-	 * @param IRequest $request
378
-	 * @param OC\Security\Bruteforce\Throttler $throttler
379
-	 * @throws LoginException
380
-	 * @throws PasswordLoginForbiddenException
381
-	 * @return boolean
382
-	 */
383
-	public function logClientIn($user,
384
-								$password,
385
-								IRequest $request,
386
-								OC\Security\Bruteforce\Throttler $throttler) {
387
-		$currentDelay = $throttler->sleepDelay($request->getRemoteAddress(), 'login');
388
-
389
-		if ($this->manager instanceof PublicEmitter) {
390
-			$this->manager->emit('\OC\User', 'preLogin', array($user, $password));
391
-		}
392
-
393
-		$isTokenPassword = $this->isTokenPassword($password);
394
-		if (!$isTokenPassword && $this->isTokenAuthEnforced()) {
395
-			throw new PasswordLoginForbiddenException();
396
-		}
397
-		if (!$isTokenPassword && $this->isTwoFactorEnforced($user)) {
398
-			throw new PasswordLoginForbiddenException();
399
-		}
400
-		if (!$this->login($user, $password) ) {
401
-			$users = $this->manager->getByEmail($user);
402
-			if (count($users) === 1) {
403
-				return $this->login($users[0]->getUID(), $password);
404
-			}
405
-
406
-			$throttler->registerAttempt('login', $request->getRemoteAddress(), ['uid' => $user]);
407
-			if($currentDelay === 0) {
408
-				$throttler->sleepDelay($request->getRemoteAddress(), 'login');
409
-			}
410
-			return false;
411
-		}
412
-
413
-		if ($isTokenPassword) {
414
-			$this->session->set('app_password', $password);
415
-		} else if($this->supportsCookies($request)) {
416
-			// Password login, but cookies supported -> create (browser) session token
417
-			$this->createSessionToken($request, $this->getUser()->getUID(), $user, $password);
418
-		}
419
-
420
-		return true;
421
-	}
422
-
423
-	protected function supportsCookies(IRequest $request) {
424
-		if (!is_null($request->getCookie('cookie_test'))) {
425
-			return true;
426
-		}
427
-		setcookie('cookie_test', 'test', $this->timeFactory->getTime() + 3600);
428
-		return false;
429
-	}
430
-
431
-	private function isTokenAuthEnforced() {
432
-		return $this->config->getSystemValue('token_auth_enforced', false);
433
-	}
434
-
435
-	protected function isTwoFactorEnforced($username) {
436
-		Util::emitHook(
437
-			'\OCA\Files_Sharing\API\Server2Server',
438
-			'preLoginNameUsedAsUserName',
439
-			array('uid' => &$username)
440
-		);
441
-		$user = $this->manager->get($username);
442
-		if (is_null($user)) {
443
-			$users = $this->manager->getByEmail($username);
444
-			if (empty($users)) {
445
-				return false;
446
-			}
447
-			if (count($users) !== 1) {
448
-				return true;
449
-			}
450
-			$user = $users[0];
451
-		}
452
-		// DI not possible due to cyclic dependencies :'-/
453
-		return OC::$server->getTwoFactorAuthManager()->isTwoFactorAuthenticated($user);
454
-	}
455
-
456
-	/**
457
-	 * Check if the given 'password' is actually a device token
458
-	 *
459
-	 * @param string $password
460
-	 * @return boolean
461
-	 */
462
-	public function isTokenPassword($password) {
463
-		try {
464
-			$this->tokenProvider->getToken($password);
465
-			return true;
466
-		} catch (InvalidTokenException $ex) {
467
-			return false;
468
-		}
469
-	}
470
-
471
-	protected function prepareUserLogin($firstTimeLogin) {
472
-		// TODO: mock/inject/use non-static
473
-		// Refresh the token
474
-		\OC::$server->getCsrfTokenManager()->refreshToken();
475
-		//we need to pass the user name, which may differ from login name
476
-		$user = $this->getUser()->getUID();
477
-		OC_Util::setupFS($user);
478
-
479
-		if ($firstTimeLogin) {
480
-			// TODO: lock necessary?
481
-			//trigger creation of user home and /files folder
482
-			$userFolder = \OC::$server->getUserFolder($user);
483
-
484
-			try {
485
-				// copy skeleton
486
-				\OC_Util::copySkeleton($user, $userFolder);
487
-			} catch (NotPermittedException $ex) {
488
-				// read only uses
489
-			}
490
-
491
-			// trigger any other initialization
492
-			\OC::$server->getEventDispatcher()->dispatch(IUser::class . '::firstLogin', new GenericEvent($this->getUser()));
493
-		}
494
-	}
495
-
496
-	/**
497
-	 * Tries to login the user with HTTP Basic Authentication
498
-	 *
499
-	 * @todo do not allow basic auth if the user is 2FA enforced
500
-	 * @param IRequest $request
501
-	 * @param OC\Security\Bruteforce\Throttler $throttler
502
-	 * @return boolean if the login was successful
503
-	 */
504
-	public function tryBasicAuthLogin(IRequest $request,
505
-									  OC\Security\Bruteforce\Throttler $throttler) {
506
-		if (!empty($request->server['PHP_AUTH_USER']) && !empty($request->server['PHP_AUTH_PW'])) {
507
-			try {
508
-				if ($this->logClientIn($request->server['PHP_AUTH_USER'], $request->server['PHP_AUTH_PW'], $request, $throttler)) {
509
-					/**
510
-					 * Add DAV authenticated. This should in an ideal world not be
511
-					 * necessary but the iOS App reads cookies from anywhere instead
512
-					 * only the DAV endpoint.
513
-					 * This makes sure that the cookies will be valid for the whole scope
514
-					 * @see https://github.com/owncloud/core/issues/22893
515
-					 */
516
-					$this->session->set(
517
-						Auth::DAV_AUTHENTICATED, $this->getUser()->getUID()
518
-					);
519
-
520
-					// Set the last-password-confirm session to make the sudo mode work
521
-					 $this->session->set('last-password-confirm', $this->timeFactory->getTime());
522
-
523
-					return true;
524
-				}
525
-			} catch (PasswordLoginForbiddenException $ex) {
526
-				// Nothing to do
527
-			}
528
-		}
529
-		return false;
530
-	}
531
-
532
-	/**
533
-	 * Log an user in via login name and password
534
-	 *
535
-	 * @param string $uid
536
-	 * @param string $password
537
-	 * @return boolean
538
-	 * @throws LoginException if an app canceld the login process or the user is not enabled
539
-	 */
540
-	private function loginWithPassword($uid, $password) {
541
-		$user = $this->manager->checkPassword($uid, $password);
542
-		if ($user === false) {
543
-			// Password check failed
544
-			return false;
545
-		}
546
-
547
-		return $this->completeLogin($user, ['loginName' => $uid, 'password' => $password], false);
548
-	}
549
-
550
-	/**
551
-	 * Log an user in with a given token (id)
552
-	 *
553
-	 * @param string $token
554
-	 * @return boolean
555
-	 * @throws LoginException if an app canceled the login process or the user is not enabled
556
-	 */
557
-	private function loginWithToken($token) {
558
-		try {
559
-			$dbToken = $this->tokenProvider->getToken($token);
560
-		} catch (InvalidTokenException $ex) {
561
-			return false;
562
-		}
563
-		$uid = $dbToken->getUID();
564
-
565
-		// When logging in with token, the password must be decrypted first before passing to login hook
566
-		$password = '';
567
-		try {
568
-			$password = $this->tokenProvider->getPassword($dbToken, $token);
569
-		} catch (PasswordlessTokenException $ex) {
570
-			// Ignore and use empty string instead
571
-		}
572
-
573
-		$this->manager->emit('\OC\User', 'preLogin', array($uid, $password));
574
-
575
-		$user = $this->manager->get($uid);
576
-		if (is_null($user)) {
577
-			// user does not exist
578
-			return false;
579
-		}
580
-
581
-		return $this->completeLogin(
582
-			$user,
583
-			[
584
-				'loginName' => $dbToken->getLoginName(),
585
-				'password' => $password,
586
-				'token' => $dbToken
587
-			],
588
-			false);
589
-	}
590
-
591
-	/**
592
-	 * Create a new session token for the given user credentials
593
-	 *
594
-	 * @param IRequest $request
595
-	 * @param string $uid user UID
596
-	 * @param string $loginName login name
597
-	 * @param string $password
598
-	 * @param int $remember
599
-	 * @return boolean
600
-	 */
601
-	public function createSessionToken(IRequest $request, $uid, $loginName, $password = null, $remember = IToken::DO_NOT_REMEMBER) {
602
-		if (is_null($this->manager->get($uid))) {
603
-			// User does not exist
604
-			return false;
605
-		}
606
-		$name = isset($request->server['HTTP_USER_AGENT']) ? $request->server['HTTP_USER_AGENT'] : 'unknown browser';
607
-		try {
608
-			$sessionId = $this->session->getId();
609
-			$pwd = $this->getPassword($password);
610
-			$this->tokenProvider->generateToken($sessionId, $uid, $loginName, $pwd, $name, IToken::TEMPORARY_TOKEN, $remember);
611
-			return true;
612
-		} catch (SessionNotAvailableException $ex) {
613
-			// This can happen with OCC, where a memory session is used
614
-			// if a memory session is used, we shouldn't create a session token anyway
615
-			return false;
616
-		}
617
-	}
618
-
619
-	/**
620
-	 * Checks if the given password is a token.
621
-	 * If yes, the password is extracted from the token.
622
-	 * If no, the same password is returned.
623
-	 *
624
-	 * @param string $password either the login password or a device token
625
-	 * @return string|null the password or null if none was set in the token
626
-	 */
627
-	private function getPassword($password) {
628
-		if (is_null($password)) {
629
-			// This is surely no token ;-)
630
-			return null;
631
-		}
632
-		try {
633
-			$token = $this->tokenProvider->getToken($password);
634
-			try {
635
-				return $this->tokenProvider->getPassword($token, $password);
636
-			} catch (PasswordlessTokenException $ex) {
637
-				return null;
638
-			}
639
-		} catch (InvalidTokenException $ex) {
640
-			return $password;
641
-		}
642
-	}
643
-
644
-	/**
645
-	 * @param IToken $dbToken
646
-	 * @param string $token
647
-	 * @return boolean
648
-	 */
649
-	private function checkTokenCredentials(IToken $dbToken, $token) {
650
-		// Check whether login credentials are still valid and the user was not disabled
651
-		// This check is performed each 5 minutes
652
-		$lastCheck = $dbToken->getLastCheck() ? : 0;
653
-		$now = $this->timeFactory->getTime();
654
-		if ($lastCheck > ($now - 60 * 5)) {
655
-			// Checked performed recently, nothing to do now
656
-			return true;
657
-		}
658
-
659
-		try {
660
-			$pwd = $this->tokenProvider->getPassword($dbToken, $token);
661
-		} catch (InvalidTokenException $ex) {
662
-			// An invalid token password was used -> log user out
663
-			return false;
664
-		} catch (PasswordlessTokenException $ex) {
665
-			// Token has no password
666
-
667
-			if (!is_null($this->activeUser) && !$this->activeUser->isEnabled()) {
668
-				$this->tokenProvider->invalidateToken($token);
669
-				return false;
670
-			}
671
-
672
-			$dbToken->setLastCheck($now);
673
-			return true;
674
-		}
675
-
676
-		if ($this->manager->checkPassword($dbToken->getLoginName(), $pwd) === false
677
-			|| (!is_null($this->activeUser) && !$this->activeUser->isEnabled())) {
678
-			$this->tokenProvider->invalidateToken($token);
679
-			// Password has changed or user was disabled -> log user out
680
-			return false;
681
-		}
682
-		$dbToken->setLastCheck($now);
683
-		return true;
684
-	}
685
-
686
-	/**
687
-	 * Check if the given token exists and performs password/user-enabled checks
688
-	 *
689
-	 * Invalidates the token if checks fail
690
-	 *
691
-	 * @param string $token
692
-	 * @param string $user login name
693
-	 * @return boolean
694
-	 */
695
-	private function validateToken($token, $user = null) {
696
-		try {
697
-			$dbToken = $this->tokenProvider->getToken($token);
698
-		} catch (InvalidTokenException $ex) {
699
-			return false;
700
-		}
701
-
702
-		// Check if login names match
703
-		if (!is_null($user) && $dbToken->getLoginName() !== $user) {
704
-			// TODO: this makes it imposssible to use different login names on browser and client
705
-			// e.g. login by e-mail '[email protected]' on browser for generating the token will not
706
-			//      allow to use the client token with the login name 'user'.
707
-			return false;
708
-		}
709
-
710
-		if (!$this->checkTokenCredentials($dbToken, $token)) {
711
-			return false;
712
-		}
713
-
714
-		$this->tokenProvider->updateTokenActivity($dbToken);
715
-
716
-		return true;
717
-	}
718
-
719
-	/**
720
-	 * Tries to login the user with auth token header
721
-	 *
722
-	 * @param IRequest $request
723
-	 * @todo check remember me cookie
724
-	 * @return boolean
725
-	 */
726
-	public function tryTokenLogin(IRequest $request) {
727
-		$authHeader = $request->getHeader('Authorization');
728
-		if (strpos($authHeader, 'Bearer ') === false) {
729
-			// No auth header, let's try session id
730
-			try {
731
-				$token = $this->session->getId();
732
-			} catch (SessionNotAvailableException $ex) {
733
-				return false;
734
-			}
735
-		} else {
736
-			$token = substr($authHeader, 7);
737
-		}
738
-
739
-		if (!$this->loginWithToken($token)) {
740
-			return false;
741
-		}
742
-		if(!$this->validateToken($token)) {
743
-			return false;
744
-		}
745
-		return true;
746
-	}
747
-
748
-	/**
749
-	 * perform login using the magic cookie (remember login)
750
-	 *
751
-	 * @param string $uid the username
752
-	 * @param string $currentToken
753
-	 * @param string $oldSessionId
754
-	 * @return bool
755
-	 */
756
-	public function loginWithCookie($uid, $currentToken, $oldSessionId) {
757
-		$this->session->regenerateId();
758
-		$this->manager->emit('\OC\User', 'preRememberedLogin', array($uid));
759
-		$user = $this->manager->get($uid);
760
-		if (is_null($user)) {
761
-			// user does not exist
762
-			return false;
763
-		}
764
-
765
-		// get stored tokens
766
-		$tokens = $this->config->getUserKeys($uid, 'login_token');
767
-		// test cookies token against stored tokens
768
-		if (!in_array($currentToken, $tokens, true)) {
769
-			return false;
770
-		}
771
-		// replace successfully used token with a new one
772
-		$this->config->deleteUserValue($uid, 'login_token', $currentToken);
773
-		$newToken = $this->random->generate(32);
774
-		$this->config->setUserValue($uid, 'login_token', $newToken, $this->timeFactory->getTime());
775
-
776
-		try {
777
-			$sessionId = $this->session->getId();
778
-			$this->tokenProvider->renewSessionToken($oldSessionId, $sessionId);
779
-		} catch (SessionNotAvailableException $ex) {
780
-			return false;
781
-		} catch (InvalidTokenException $ex) {
782
-			\OC::$server->getLogger()->warning('Renewing session token failed', ['app' => 'core']);
783
-			return false;
784
-		}
785
-
786
-		$this->setMagicInCookie($user->getUID(), $newToken);
787
-		$token = $this->tokenProvider->getToken($sessionId);
788
-
789
-		//login
790
-		$this->setUser($user);
791
-		$this->setLoginName($token->getLoginName());
792
-		$this->setToken($token->getId());
793
-		$this->lockdownManager->setToken($token);
794
-		$user->updateLastLoginTimestamp();
795
-		$this->manager->emit('\OC\User', 'postRememberedLogin', [$user]);
796
-		return true;
797
-	}
798
-
799
-	/**
800
-	 * @param IUser $user
801
-	 */
802
-	public function createRememberMeToken(IUser $user) {
803
-		$token = $this->random->generate(32);
804
-		$this->config->setUserValue($user->getUID(), 'login_token', $token, $this->timeFactory->getTime());
805
-		$this->setMagicInCookie($user->getUID(), $token);
806
-	}
807
-
808
-	/**
809
-	 * logout the user from the session
810
-	 */
811
-	public function logout() {
812
-		$this->manager->emit('\OC\User', 'logout');
813
-		$user = $this->getUser();
814
-		if (!is_null($user)) {
815
-			try {
816
-				$this->tokenProvider->invalidateToken($this->session->getId());
817
-			} catch (SessionNotAvailableException $ex) {
818
-
819
-			}
820
-		}
821
-		$this->setUser(null);
822
-		$this->setLoginName(null);
823
-		$this->setToken(null);
824
-		$this->unsetMagicInCookie();
825
-		$this->session->clear();
826
-		$this->manager->emit('\OC\User', 'postLogout');
827
-	}
828
-
829
-	/**
830
-	 * Set cookie value to use in next page load
831
-	 *
832
-	 * @param string $username username to be set
833
-	 * @param string $token
834
-	 */
835
-	public function setMagicInCookie($username, $token) {
836
-		$secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
837
-		$webRoot = \OC::$WEBROOT;
838
-		if ($webRoot === '') {
839
-			$webRoot = '/';
840
-		}
841
-
842
-		$expires = $this->timeFactory->getTime() + $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
843
-		setcookie('nc_username', $username, $expires, $webRoot, '', $secureCookie, true);
844
-		setcookie('nc_token', $token, $expires, $webRoot, '', $secureCookie, true);
845
-		try {
846
-			setcookie('nc_session_id', $this->session->getId(), $expires, $webRoot, '', $secureCookie, true);
847
-		} catch (SessionNotAvailableException $ex) {
848
-			// ignore
849
-		}
850
-	}
851
-
852
-	/**
853
-	 * Remove cookie for "remember username"
854
-	 */
855
-	public function unsetMagicInCookie() {
856
-		//TODO: DI for cookies and IRequest
857
-		$secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
858
-
859
-		unset($_COOKIE['nc_username']); //TODO: DI
860
-		unset($_COOKIE['nc_token']);
861
-		unset($_COOKIE['nc_session_id']);
862
-		setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
863
-		setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
864
-		setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
865
-		// old cookies might be stored under /webroot/ instead of /webroot
866
-		// and Firefox doesn't like it!
867
-		setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
868
-		setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
869
-		setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
870
-	}
871
-
872
-	/**
873
-	 * Update password of the browser session token if there is one
874
-	 *
875
-	 * @param string $password
876
-	 */
877
-	public function updateSessionTokenPassword($password) {
878
-		try {
879
-			$sessionId = $this->session->getId();
880
-			$token = $this->tokenProvider->getToken($sessionId);
881
-			$this->tokenProvider->setPassword($token, $sessionId, $password);
882
-		} catch (SessionNotAvailableException $ex) {
883
-			// Nothing to do
884
-		} catch (InvalidTokenException $ex) {
885
-			// Nothing to do
886
-		}
887
-	}
83
+    /** @var IUserManager|PublicEmitter $manager */
84
+    private $manager;
85
+
86
+    /** @var ISession $session */
87
+    private $session;
88
+
89
+    /** @var ITimeFactory */
90
+    private $timeFactory;
91
+
92
+    /** @var IProvider */
93
+    private $tokenProvider;
94
+
95
+    /** @var IConfig */
96
+    private $config;
97
+
98
+    /** @var User $activeUser */
99
+    protected $activeUser;
100
+
101
+    /** @var ISecureRandom */
102
+    private $random;
103
+
104
+    /** @var ILockdownManager  */
105
+    private $lockdownManager;
106
+
107
+    /**
108
+     * @param IUserManager $manager
109
+     * @param ISession $session
110
+     * @param ITimeFactory $timeFactory
111
+     * @param IProvider $tokenProvider
112
+     * @param IConfig $config
113
+     * @param ISecureRandom $random
114
+     * @param ILockdownManager $lockdownManager
115
+     */
116
+    public function __construct(IUserManager $manager,
117
+                                ISession $session,
118
+                                ITimeFactory $timeFactory,
119
+                                $tokenProvider,
120
+                                IConfig $config,
121
+                                ISecureRandom $random,
122
+                                ILockdownManager $lockdownManager
123
+    ) {
124
+        $this->manager = $manager;
125
+        $this->session = $session;
126
+        $this->timeFactory = $timeFactory;
127
+        $this->tokenProvider = $tokenProvider;
128
+        $this->config = $config;
129
+        $this->random = $random;
130
+        $this->lockdownManager = $lockdownManager;
131
+    }
132
+
133
+    /**
134
+     * @param IProvider $provider
135
+     */
136
+    public function setTokenProvider(IProvider $provider) {
137
+        $this->tokenProvider = $provider;
138
+    }
139
+
140
+    /**
141
+     * @param string $scope
142
+     * @param string $method
143
+     * @param callable $callback
144
+     */
145
+    public function listen($scope, $method, callable $callback) {
146
+        $this->manager->listen($scope, $method, $callback);
147
+    }
148
+
149
+    /**
150
+     * @param string $scope optional
151
+     * @param string $method optional
152
+     * @param callable $callback optional
153
+     */
154
+    public function removeListener($scope = null, $method = null, callable $callback = null) {
155
+        $this->manager->removeListener($scope, $method, $callback);
156
+    }
157
+
158
+    /**
159
+     * get the manager object
160
+     *
161
+     * @return Manager|PublicEmitter
162
+     */
163
+    public function getManager() {
164
+        return $this->manager;
165
+    }
166
+
167
+    /**
168
+     * get the session object
169
+     *
170
+     * @return ISession
171
+     */
172
+    public function getSession() {
173
+        return $this->session;
174
+    }
175
+
176
+    /**
177
+     * set the session object
178
+     *
179
+     * @param ISession $session
180
+     */
181
+    public function setSession(ISession $session) {
182
+        if ($this->session instanceof ISession) {
183
+            $this->session->close();
184
+        }
185
+        $this->session = $session;
186
+        $this->activeUser = null;
187
+    }
188
+
189
+    /**
190
+     * set the currently active user
191
+     *
192
+     * @param IUser|null $user
193
+     */
194
+    public function setUser($user) {
195
+        if (is_null($user)) {
196
+            $this->session->remove('user_id');
197
+        } else {
198
+            $this->session->set('user_id', $user->getUID());
199
+        }
200
+        $this->activeUser = $user;
201
+    }
202
+
203
+    /**
204
+     * get the current active user
205
+     *
206
+     * @return IUser|null Current user, otherwise null
207
+     */
208
+    public function getUser() {
209
+        // FIXME: This is a quick'n dirty work-around for the incognito mode as
210
+        // described at https://github.com/owncloud/core/pull/12912#issuecomment-67391155
211
+        if (OC_User::isIncognitoMode()) {
212
+            return null;
213
+        }
214
+        if (is_null($this->activeUser)) {
215
+            $uid = $this->session->get('user_id');
216
+            if (is_null($uid)) {
217
+                return null;
218
+            }
219
+            $this->activeUser = $this->manager->get($uid);
220
+            if (is_null($this->activeUser)) {
221
+                return null;
222
+            }
223
+            $this->validateSession();
224
+        }
225
+        return $this->activeUser;
226
+    }
227
+
228
+    /**
229
+     * Validate whether the current session is valid
230
+     *
231
+     * - For token-authenticated clients, the token validity is checked
232
+     * - For browsers, the session token validity is checked
233
+     */
234
+    protected function validateSession() {
235
+        $token = null;
236
+        $appPassword = $this->session->get('app_password');
237
+
238
+        if (is_null($appPassword)) {
239
+            try {
240
+                $token = $this->session->getId();
241
+            } catch (SessionNotAvailableException $ex) {
242
+                return;
243
+            }
244
+        } else {
245
+            $token = $appPassword;
246
+        }
247
+
248
+        if (!$this->validateToken($token)) {
249
+            // Session was invalidated
250
+            $this->logout();
251
+        }
252
+    }
253
+
254
+    /**
255
+     * Checks whether the user is logged in
256
+     *
257
+     * @return bool if logged in
258
+     */
259
+    public function isLoggedIn() {
260
+        $user = $this->getUser();
261
+        if (is_null($user)) {
262
+            return false;
263
+        }
264
+
265
+        return $user->isEnabled();
266
+    }
267
+
268
+    /**
269
+     * set the login name
270
+     *
271
+     * @param string|null $loginName for the logged in user
272
+     */
273
+    public function setLoginName($loginName) {
274
+        if (is_null($loginName)) {
275
+            $this->session->remove('loginname');
276
+        } else {
277
+            $this->session->set('loginname', $loginName);
278
+        }
279
+    }
280
+
281
+    /**
282
+     * get the login name of the current user
283
+     *
284
+     * @return string
285
+     */
286
+    public function getLoginName() {
287
+        if ($this->activeUser) {
288
+            return $this->session->get('loginname');
289
+        } else {
290
+            $uid = $this->session->get('user_id');
291
+            if ($uid) {
292
+                $this->activeUser = $this->manager->get($uid);
293
+                return $this->session->get('loginname');
294
+            } else {
295
+                return null;
296
+            }
297
+        }
298
+    }
299
+
300
+    /**
301
+     * set the token id
302
+     *
303
+     * @param int|null $token that was used to log in
304
+     */
305
+    protected function setToken($token) {
306
+        if ($token === null) {
307
+            $this->session->remove('token-id');
308
+        } else {
309
+            $this->session->set('token-id', $token);
310
+        }
311
+    }
312
+
313
+    /**
314
+     * try to log in with the provided credentials
315
+     *
316
+     * @param string $uid
317
+     * @param string $password
318
+     * @return boolean|null
319
+     * @throws LoginException
320
+     */
321
+    public function login($uid, $password) {
322
+        $this->session->regenerateId();
323
+        if ($this->validateToken($password, $uid)) {
324
+            return $this->loginWithToken($password);
325
+        }
326
+        return $this->loginWithPassword($uid, $password);
327
+    }
328
+
329
+    /**
330
+     * @param IUser $user
331
+     * @param array $loginDetails
332
+     * @param bool $regenerateSessionId
333
+     * @return true returns true if login successful or an exception otherwise
334
+     * @throws LoginException
335
+     */
336
+    public function completeLogin(IUser $user, array $loginDetails, $regenerateSessionId = true) {
337
+        if (!$user->isEnabled()) {
338
+            // disabled users can not log in
339
+            // injecting l10n does not work - there is a circular dependency between session and \OCP\L10N\IFactory
340
+            $message = \OC::$server->getL10N('lib')->t('User disabled');
341
+            throw new LoginException($message);
342
+        }
343
+
344
+        if($regenerateSessionId) {
345
+            $this->session->regenerateId();
346
+        }
347
+
348
+        $this->setUser($user);
349
+        $this->setLoginName($loginDetails['loginName']);
350
+
351
+        if(isset($loginDetails['token']) && $loginDetails['token'] instanceof IToken) {
352
+            $this->setToken($loginDetails['token']->getId());
353
+            $this->lockdownManager->setToken($loginDetails['token']);
354
+            $firstTimeLogin = false;
355
+        } else {
356
+            $this->setToken(null);
357
+            $firstTimeLogin = $user->updateLastLoginTimestamp();
358
+        }
359
+        $this->manager->emit('\OC\User', 'postLogin', [$user, $loginDetails['password']]);
360
+        if($this->isLoggedIn()) {
361
+            $this->prepareUserLogin($firstTimeLogin);
362
+            return true;
363
+        } else {
364
+            $message = \OC::$server->getL10N('lib')->t('Login canceled by app');
365
+            throw new LoginException($message);
366
+        }
367
+    }
368
+
369
+    /**
370
+     * Tries to log in a client
371
+     *
372
+     * Checks token auth enforced
373
+     * Checks 2FA enabled
374
+     *
375
+     * @param string $user
376
+     * @param string $password
377
+     * @param IRequest $request
378
+     * @param OC\Security\Bruteforce\Throttler $throttler
379
+     * @throws LoginException
380
+     * @throws PasswordLoginForbiddenException
381
+     * @return boolean
382
+     */
383
+    public function logClientIn($user,
384
+                                $password,
385
+                                IRequest $request,
386
+                                OC\Security\Bruteforce\Throttler $throttler) {
387
+        $currentDelay = $throttler->sleepDelay($request->getRemoteAddress(), 'login');
388
+
389
+        if ($this->manager instanceof PublicEmitter) {
390
+            $this->manager->emit('\OC\User', 'preLogin', array($user, $password));
391
+        }
392
+
393
+        $isTokenPassword = $this->isTokenPassword($password);
394
+        if (!$isTokenPassword && $this->isTokenAuthEnforced()) {
395
+            throw new PasswordLoginForbiddenException();
396
+        }
397
+        if (!$isTokenPassword && $this->isTwoFactorEnforced($user)) {
398
+            throw new PasswordLoginForbiddenException();
399
+        }
400
+        if (!$this->login($user, $password) ) {
401
+            $users = $this->manager->getByEmail($user);
402
+            if (count($users) === 1) {
403
+                return $this->login($users[0]->getUID(), $password);
404
+            }
405
+
406
+            $throttler->registerAttempt('login', $request->getRemoteAddress(), ['uid' => $user]);
407
+            if($currentDelay === 0) {
408
+                $throttler->sleepDelay($request->getRemoteAddress(), 'login');
409
+            }
410
+            return false;
411
+        }
412
+
413
+        if ($isTokenPassword) {
414
+            $this->session->set('app_password', $password);
415
+        } else if($this->supportsCookies($request)) {
416
+            // Password login, but cookies supported -> create (browser) session token
417
+            $this->createSessionToken($request, $this->getUser()->getUID(), $user, $password);
418
+        }
419
+
420
+        return true;
421
+    }
422
+
423
+    protected function supportsCookies(IRequest $request) {
424
+        if (!is_null($request->getCookie('cookie_test'))) {
425
+            return true;
426
+        }
427
+        setcookie('cookie_test', 'test', $this->timeFactory->getTime() + 3600);
428
+        return false;
429
+    }
430
+
431
+    private function isTokenAuthEnforced() {
432
+        return $this->config->getSystemValue('token_auth_enforced', false);
433
+    }
434
+
435
+    protected function isTwoFactorEnforced($username) {
436
+        Util::emitHook(
437
+            '\OCA\Files_Sharing\API\Server2Server',
438
+            'preLoginNameUsedAsUserName',
439
+            array('uid' => &$username)
440
+        );
441
+        $user = $this->manager->get($username);
442
+        if (is_null($user)) {
443
+            $users = $this->manager->getByEmail($username);
444
+            if (empty($users)) {
445
+                return false;
446
+            }
447
+            if (count($users) !== 1) {
448
+                return true;
449
+            }
450
+            $user = $users[0];
451
+        }
452
+        // DI not possible due to cyclic dependencies :'-/
453
+        return OC::$server->getTwoFactorAuthManager()->isTwoFactorAuthenticated($user);
454
+    }
455
+
456
+    /**
457
+     * Check if the given 'password' is actually a device token
458
+     *
459
+     * @param string $password
460
+     * @return boolean
461
+     */
462
+    public function isTokenPassword($password) {
463
+        try {
464
+            $this->tokenProvider->getToken($password);
465
+            return true;
466
+        } catch (InvalidTokenException $ex) {
467
+            return false;
468
+        }
469
+    }
470
+
471
+    protected function prepareUserLogin($firstTimeLogin) {
472
+        // TODO: mock/inject/use non-static
473
+        // Refresh the token
474
+        \OC::$server->getCsrfTokenManager()->refreshToken();
475
+        //we need to pass the user name, which may differ from login name
476
+        $user = $this->getUser()->getUID();
477
+        OC_Util::setupFS($user);
478
+
479
+        if ($firstTimeLogin) {
480
+            // TODO: lock necessary?
481
+            //trigger creation of user home and /files folder
482
+            $userFolder = \OC::$server->getUserFolder($user);
483
+
484
+            try {
485
+                // copy skeleton
486
+                \OC_Util::copySkeleton($user, $userFolder);
487
+            } catch (NotPermittedException $ex) {
488
+                // read only uses
489
+            }
490
+
491
+            // trigger any other initialization
492
+            \OC::$server->getEventDispatcher()->dispatch(IUser::class . '::firstLogin', new GenericEvent($this->getUser()));
493
+        }
494
+    }
495
+
496
+    /**
497
+     * Tries to login the user with HTTP Basic Authentication
498
+     *
499
+     * @todo do not allow basic auth if the user is 2FA enforced
500
+     * @param IRequest $request
501
+     * @param OC\Security\Bruteforce\Throttler $throttler
502
+     * @return boolean if the login was successful
503
+     */
504
+    public function tryBasicAuthLogin(IRequest $request,
505
+                                        OC\Security\Bruteforce\Throttler $throttler) {
506
+        if (!empty($request->server['PHP_AUTH_USER']) && !empty($request->server['PHP_AUTH_PW'])) {
507
+            try {
508
+                if ($this->logClientIn($request->server['PHP_AUTH_USER'], $request->server['PHP_AUTH_PW'], $request, $throttler)) {
509
+                    /**
510
+                     * Add DAV authenticated. This should in an ideal world not be
511
+                     * necessary but the iOS App reads cookies from anywhere instead
512
+                     * only the DAV endpoint.
513
+                     * This makes sure that the cookies will be valid for the whole scope
514
+                     * @see https://github.com/owncloud/core/issues/22893
515
+                     */
516
+                    $this->session->set(
517
+                        Auth::DAV_AUTHENTICATED, $this->getUser()->getUID()
518
+                    );
519
+
520
+                    // Set the last-password-confirm session to make the sudo mode work
521
+                        $this->session->set('last-password-confirm', $this->timeFactory->getTime());
522
+
523
+                    return true;
524
+                }
525
+            } catch (PasswordLoginForbiddenException $ex) {
526
+                // Nothing to do
527
+            }
528
+        }
529
+        return false;
530
+    }
531
+
532
+    /**
533
+     * Log an user in via login name and password
534
+     *
535
+     * @param string $uid
536
+     * @param string $password
537
+     * @return boolean
538
+     * @throws LoginException if an app canceld the login process or the user is not enabled
539
+     */
540
+    private function loginWithPassword($uid, $password) {
541
+        $user = $this->manager->checkPassword($uid, $password);
542
+        if ($user === false) {
543
+            // Password check failed
544
+            return false;
545
+        }
546
+
547
+        return $this->completeLogin($user, ['loginName' => $uid, 'password' => $password], false);
548
+    }
549
+
550
+    /**
551
+     * Log an user in with a given token (id)
552
+     *
553
+     * @param string $token
554
+     * @return boolean
555
+     * @throws LoginException if an app canceled the login process or the user is not enabled
556
+     */
557
+    private function loginWithToken($token) {
558
+        try {
559
+            $dbToken = $this->tokenProvider->getToken($token);
560
+        } catch (InvalidTokenException $ex) {
561
+            return false;
562
+        }
563
+        $uid = $dbToken->getUID();
564
+
565
+        // When logging in with token, the password must be decrypted first before passing to login hook
566
+        $password = '';
567
+        try {
568
+            $password = $this->tokenProvider->getPassword($dbToken, $token);
569
+        } catch (PasswordlessTokenException $ex) {
570
+            // Ignore and use empty string instead
571
+        }
572
+
573
+        $this->manager->emit('\OC\User', 'preLogin', array($uid, $password));
574
+
575
+        $user = $this->manager->get($uid);
576
+        if (is_null($user)) {
577
+            // user does not exist
578
+            return false;
579
+        }
580
+
581
+        return $this->completeLogin(
582
+            $user,
583
+            [
584
+                'loginName' => $dbToken->getLoginName(),
585
+                'password' => $password,
586
+                'token' => $dbToken
587
+            ],
588
+            false);
589
+    }
590
+
591
+    /**
592
+     * Create a new session token for the given user credentials
593
+     *
594
+     * @param IRequest $request
595
+     * @param string $uid user UID
596
+     * @param string $loginName login name
597
+     * @param string $password
598
+     * @param int $remember
599
+     * @return boolean
600
+     */
601
+    public function createSessionToken(IRequest $request, $uid, $loginName, $password = null, $remember = IToken::DO_NOT_REMEMBER) {
602
+        if (is_null($this->manager->get($uid))) {
603
+            // User does not exist
604
+            return false;
605
+        }
606
+        $name = isset($request->server['HTTP_USER_AGENT']) ? $request->server['HTTP_USER_AGENT'] : 'unknown browser';
607
+        try {
608
+            $sessionId = $this->session->getId();
609
+            $pwd = $this->getPassword($password);
610
+            $this->tokenProvider->generateToken($sessionId, $uid, $loginName, $pwd, $name, IToken::TEMPORARY_TOKEN, $remember);
611
+            return true;
612
+        } catch (SessionNotAvailableException $ex) {
613
+            // This can happen with OCC, where a memory session is used
614
+            // if a memory session is used, we shouldn't create a session token anyway
615
+            return false;
616
+        }
617
+    }
618
+
619
+    /**
620
+     * Checks if the given password is a token.
621
+     * If yes, the password is extracted from the token.
622
+     * If no, the same password is returned.
623
+     *
624
+     * @param string $password either the login password or a device token
625
+     * @return string|null the password or null if none was set in the token
626
+     */
627
+    private function getPassword($password) {
628
+        if (is_null($password)) {
629
+            // This is surely no token ;-)
630
+            return null;
631
+        }
632
+        try {
633
+            $token = $this->tokenProvider->getToken($password);
634
+            try {
635
+                return $this->tokenProvider->getPassword($token, $password);
636
+            } catch (PasswordlessTokenException $ex) {
637
+                return null;
638
+            }
639
+        } catch (InvalidTokenException $ex) {
640
+            return $password;
641
+        }
642
+    }
643
+
644
+    /**
645
+     * @param IToken $dbToken
646
+     * @param string $token
647
+     * @return boolean
648
+     */
649
+    private function checkTokenCredentials(IToken $dbToken, $token) {
650
+        // Check whether login credentials are still valid and the user was not disabled
651
+        // This check is performed each 5 minutes
652
+        $lastCheck = $dbToken->getLastCheck() ? : 0;
653
+        $now = $this->timeFactory->getTime();
654
+        if ($lastCheck > ($now - 60 * 5)) {
655
+            // Checked performed recently, nothing to do now
656
+            return true;
657
+        }
658
+
659
+        try {
660
+            $pwd = $this->tokenProvider->getPassword($dbToken, $token);
661
+        } catch (InvalidTokenException $ex) {
662
+            // An invalid token password was used -> log user out
663
+            return false;
664
+        } catch (PasswordlessTokenException $ex) {
665
+            // Token has no password
666
+
667
+            if (!is_null($this->activeUser) && !$this->activeUser->isEnabled()) {
668
+                $this->tokenProvider->invalidateToken($token);
669
+                return false;
670
+            }
671
+
672
+            $dbToken->setLastCheck($now);
673
+            return true;
674
+        }
675
+
676
+        if ($this->manager->checkPassword($dbToken->getLoginName(), $pwd) === false
677
+            || (!is_null($this->activeUser) && !$this->activeUser->isEnabled())) {
678
+            $this->tokenProvider->invalidateToken($token);
679
+            // Password has changed or user was disabled -> log user out
680
+            return false;
681
+        }
682
+        $dbToken->setLastCheck($now);
683
+        return true;
684
+    }
685
+
686
+    /**
687
+     * Check if the given token exists and performs password/user-enabled checks
688
+     *
689
+     * Invalidates the token if checks fail
690
+     *
691
+     * @param string $token
692
+     * @param string $user login name
693
+     * @return boolean
694
+     */
695
+    private function validateToken($token, $user = null) {
696
+        try {
697
+            $dbToken = $this->tokenProvider->getToken($token);
698
+        } catch (InvalidTokenException $ex) {
699
+            return false;
700
+        }
701
+
702
+        // Check if login names match
703
+        if (!is_null($user) && $dbToken->getLoginName() !== $user) {
704
+            // TODO: this makes it imposssible to use different login names on browser and client
705
+            // e.g. login by e-mail '[email protected]' on browser for generating the token will not
706
+            //      allow to use the client token with the login name 'user'.
707
+            return false;
708
+        }
709
+
710
+        if (!$this->checkTokenCredentials($dbToken, $token)) {
711
+            return false;
712
+        }
713
+
714
+        $this->tokenProvider->updateTokenActivity($dbToken);
715
+
716
+        return true;
717
+    }
718
+
719
+    /**
720
+     * Tries to login the user with auth token header
721
+     *
722
+     * @param IRequest $request
723
+     * @todo check remember me cookie
724
+     * @return boolean
725
+     */
726
+    public function tryTokenLogin(IRequest $request) {
727
+        $authHeader = $request->getHeader('Authorization');
728
+        if (strpos($authHeader, 'Bearer ') === false) {
729
+            // No auth header, let's try session id
730
+            try {
731
+                $token = $this->session->getId();
732
+            } catch (SessionNotAvailableException $ex) {
733
+                return false;
734
+            }
735
+        } else {
736
+            $token = substr($authHeader, 7);
737
+        }
738
+
739
+        if (!$this->loginWithToken($token)) {
740
+            return false;
741
+        }
742
+        if(!$this->validateToken($token)) {
743
+            return false;
744
+        }
745
+        return true;
746
+    }
747
+
748
+    /**
749
+     * perform login using the magic cookie (remember login)
750
+     *
751
+     * @param string $uid the username
752
+     * @param string $currentToken
753
+     * @param string $oldSessionId
754
+     * @return bool
755
+     */
756
+    public function loginWithCookie($uid, $currentToken, $oldSessionId) {
757
+        $this->session->regenerateId();
758
+        $this->manager->emit('\OC\User', 'preRememberedLogin', array($uid));
759
+        $user = $this->manager->get($uid);
760
+        if (is_null($user)) {
761
+            // user does not exist
762
+            return false;
763
+        }
764
+
765
+        // get stored tokens
766
+        $tokens = $this->config->getUserKeys($uid, 'login_token');
767
+        // test cookies token against stored tokens
768
+        if (!in_array($currentToken, $tokens, true)) {
769
+            return false;
770
+        }
771
+        // replace successfully used token with a new one
772
+        $this->config->deleteUserValue($uid, 'login_token', $currentToken);
773
+        $newToken = $this->random->generate(32);
774
+        $this->config->setUserValue($uid, 'login_token', $newToken, $this->timeFactory->getTime());
775
+
776
+        try {
777
+            $sessionId = $this->session->getId();
778
+            $this->tokenProvider->renewSessionToken($oldSessionId, $sessionId);
779
+        } catch (SessionNotAvailableException $ex) {
780
+            return false;
781
+        } catch (InvalidTokenException $ex) {
782
+            \OC::$server->getLogger()->warning('Renewing session token failed', ['app' => 'core']);
783
+            return false;
784
+        }
785
+
786
+        $this->setMagicInCookie($user->getUID(), $newToken);
787
+        $token = $this->tokenProvider->getToken($sessionId);
788
+
789
+        //login
790
+        $this->setUser($user);
791
+        $this->setLoginName($token->getLoginName());
792
+        $this->setToken($token->getId());
793
+        $this->lockdownManager->setToken($token);
794
+        $user->updateLastLoginTimestamp();
795
+        $this->manager->emit('\OC\User', 'postRememberedLogin', [$user]);
796
+        return true;
797
+    }
798
+
799
+    /**
800
+     * @param IUser $user
801
+     */
802
+    public function createRememberMeToken(IUser $user) {
803
+        $token = $this->random->generate(32);
804
+        $this->config->setUserValue($user->getUID(), 'login_token', $token, $this->timeFactory->getTime());
805
+        $this->setMagicInCookie($user->getUID(), $token);
806
+    }
807
+
808
+    /**
809
+     * logout the user from the session
810
+     */
811
+    public function logout() {
812
+        $this->manager->emit('\OC\User', 'logout');
813
+        $user = $this->getUser();
814
+        if (!is_null($user)) {
815
+            try {
816
+                $this->tokenProvider->invalidateToken($this->session->getId());
817
+            } catch (SessionNotAvailableException $ex) {
818
+
819
+            }
820
+        }
821
+        $this->setUser(null);
822
+        $this->setLoginName(null);
823
+        $this->setToken(null);
824
+        $this->unsetMagicInCookie();
825
+        $this->session->clear();
826
+        $this->manager->emit('\OC\User', 'postLogout');
827
+    }
828
+
829
+    /**
830
+     * Set cookie value to use in next page load
831
+     *
832
+     * @param string $username username to be set
833
+     * @param string $token
834
+     */
835
+    public function setMagicInCookie($username, $token) {
836
+        $secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
837
+        $webRoot = \OC::$WEBROOT;
838
+        if ($webRoot === '') {
839
+            $webRoot = '/';
840
+        }
841
+
842
+        $expires = $this->timeFactory->getTime() + $this->config->getSystemValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
843
+        setcookie('nc_username', $username, $expires, $webRoot, '', $secureCookie, true);
844
+        setcookie('nc_token', $token, $expires, $webRoot, '', $secureCookie, true);
845
+        try {
846
+            setcookie('nc_session_id', $this->session->getId(), $expires, $webRoot, '', $secureCookie, true);
847
+        } catch (SessionNotAvailableException $ex) {
848
+            // ignore
849
+        }
850
+    }
851
+
852
+    /**
853
+     * Remove cookie for "remember username"
854
+     */
855
+    public function unsetMagicInCookie() {
856
+        //TODO: DI for cookies and IRequest
857
+        $secureCookie = OC::$server->getRequest()->getServerProtocol() === 'https';
858
+
859
+        unset($_COOKIE['nc_username']); //TODO: DI
860
+        unset($_COOKIE['nc_token']);
861
+        unset($_COOKIE['nc_session_id']);
862
+        setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
863
+        setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
864
+        setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT, '', $secureCookie, true);
865
+        // old cookies might be stored under /webroot/ instead of /webroot
866
+        // and Firefox doesn't like it!
867
+        setcookie('nc_username', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
868
+        setcookie('nc_token', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
869
+        setcookie('nc_session_id', '', $this->timeFactory->getTime() - 3600, OC::$WEBROOT . '/', '', $secureCookie, true);
870
+    }
871
+
872
+    /**
873
+     * Update password of the browser session token if there is one
874
+     *
875
+     * @param string $password
876
+     */
877
+    public function updateSessionTokenPassword($password) {
878
+        try {
879
+            $sessionId = $this->session->getId();
880
+            $token = $this->tokenProvider->getToken($sessionId);
881
+            $this->tokenProvider->setPassword($token, $sessionId, $password);
882
+        } catch (SessionNotAvailableException $ex) {
883
+            // Nothing to do
884
+        } catch (InvalidTokenException $ex) {
885
+            // Nothing to do
886
+        }
887
+    }
888 888
 
889 889
 
890 890
 }
Please login to merge, or discard this patch.
apps/oauth2/templates/admin.php 1 patch
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -49,8 +49,8 @@
 block discarded – undo
49 49
 			<tr>
50 50
 				<td><?php p($client->getName()); ?></td>
51 51
 				<td><?php p($client->getRedirectUri()); ?></td>
52
-				<td data-value="<?php p($client->getClientIdentifier()); ?>"><code>****</code><img class='show-oauth-credentials' src="<?php p($urlGenerator->imagePath('core', 'actions/toggle.svg'));?>"/></td>
53
-				<td data-value="<?php p($client->getSecret()); ?>"><code>****</code><img class='show-oauth-credentials' src="<?php p($urlGenerator->imagePath('core', 'actions/toggle.svg'));?>"/></td>
52
+				<td data-value="<?php p($client->getClientIdentifier()); ?>"><code>****</code><img class='show-oauth-credentials' src="<?php p($urlGenerator->imagePath('core', 'actions/toggle.svg')); ?>"/></td>
53
+				<td data-value="<?php p($client->getSecret()); ?>"><code>****</code><img class='show-oauth-credentials' src="<?php p($urlGenerator->imagePath('core', 'actions/toggle.svg')); ?>"/></td>
54 54
 				<td>
55 55
 					<form id="form-inline" class="delete" action="<?php p($urlGenerator->linkToRoute('oauth2.Settings.deleteClient', ['id' => $client->getId()])); ?>" method="POST">
56 56
 						<input type="hidden" name="requesttoken" value="<?php p($_['requesttoken']) ?>" />
Please login to merge, or discard this patch.