Passed
Push — master ( f3738e...2212a6 )
by Daniel
12:27 queued 11s
created
public/Authentication/TwoFactorAuth/TwoFactorProviderForUserDisabled.php 1 patch
Indentation   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -33,33 +33,33 @@
 block discarded – undo
33 33
  * @since 22.0.0
34 34
  */
35 35
 class TwoFactorProviderForUserDisabled extends Event {
36
-	/** @var IProvider */
37
-	private $provider;
36
+    /** @var IProvider */
37
+    private $provider;
38 38
 
39
-	/** @var IUser */
40
-	private $user;
39
+    /** @var IUser */
40
+    private $user;
41 41
 
42
-	/**
43
-	 * @since 22.0.0
44
-	 */
45
-	public function __construct(IUser $user, IProvider $provider) {
46
-		$this->user = $user;
47
-		$this->provider = $provider;
48
-	}
42
+    /**
43
+     * @since 22.0.0
44
+     */
45
+    public function __construct(IUser $user, IProvider $provider) {
46
+        $this->user = $user;
47
+        $this->provider = $provider;
48
+    }
49 49
 
50
-	/**
51
-	 * @return IUser
52
-	 * @since 22.0.0
53
-	 */
54
-	public function getUser(): IUser {
55
-		return $this->user;
56
-	}
50
+    /**
51
+     * @return IUser
52
+     * @since 22.0.0
53
+     */
54
+    public function getUser(): IUser {
55
+        return $this->user;
56
+    }
57 57
 
58
-	/**
59
-	 * @return IProvider
60
-	 * @since 22.0.0
61
-	 */
62
-	public function getProvider(): IProvider {
63
-		return $this->provider;
64
-	}
58
+    /**
59
+     * @return IProvider
60
+     * @since 22.0.0
61
+     */
62
+    public function getProvider(): IProvider {
63
+        return $this->provider;
64
+    }
65 65
 }
Please login to merge, or discard this patch.
lib/public/Authentication/TwoFactorAuth/TwoFactorProviderForUserEnabled.php 1 patch
Indentation   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -33,33 +33,33 @@
 block discarded – undo
33 33
  * @since 22.0.0
34 34
  */
35 35
 class TwoFactorProviderForUserEnabled extends Event {
36
-	/** @var IProvider */
37
-	private $provider;
36
+    /** @var IProvider */
37
+    private $provider;
38 38
 
39
-	/** @var IUser */
40
-	private $user;
39
+    /** @var IUser */
40
+    private $user;
41 41
 
42
-	/**
43
-	 * @since 22.0.0
44
-	 */
45
-	public function __construct(IUser $user, IProvider $provider) {
46
-		$this->user = $user;
47
-		$this->provider = $provider;
48
-	}
42
+    /**
43
+     * @since 22.0.0
44
+     */
45
+    public function __construct(IUser $user, IProvider $provider) {
46
+        $this->user = $user;
47
+        $this->provider = $provider;
48
+    }
49 49
 
50
-	/**
51
-	 * @return IUser
52
-	 * @since 22.0.0
53
-	 */
54
-	public function getUser(): IUser {
55
-		return $this->user;
56
-	}
50
+    /**
51
+     * @return IUser
52
+     * @since 22.0.0
53
+     */
54
+    public function getUser(): IUser {
55
+        return $this->user;
56
+    }
57 57
 
58
-	/**
59
-	 * @return IProvider
60
-	 * @since 22.0.0
61
-	 */
62
-	public function getProvider(): IProvider {
63
-		return $this->provider;
64
-	}
58
+    /**
59
+     * @return IProvider
60
+     * @since 22.0.0
61
+     */
62
+    public function getProvider(): IProvider {
63
+        return $this->provider;
64
+    }
65 65
 }
Please login to merge, or discard this patch.
lib/private/Authentication/TwoFactorAuth/Manager.php 1 patch
Indentation   +345 added lines, -345 removed lines patch added patch discarded remove patch
@@ -50,352 +50,352 @@
 block discarded – undo
50 50
 use function array_filter;
51 51
 
52 52
 class Manager {
53
-	public const SESSION_UID_KEY = 'two_factor_auth_uid';
54
-	public const SESSION_UID_DONE = 'two_factor_auth_passed';
55
-	public const REMEMBER_LOGIN = 'two_factor_remember_login';
56
-	public const BACKUP_CODES_PROVIDER_ID = 'backup_codes';
57
-
58
-	/** @var ProviderLoader */
59
-	private $providerLoader;
60
-
61
-	/** @var IRegistry */
62
-	private $providerRegistry;
63
-
64
-	/** @var MandatoryTwoFactor */
65
-	private $mandatoryTwoFactor;
66
-
67
-	/** @var ISession */
68
-	private $session;
69
-
70
-	/** @var IConfig */
71
-	private $config;
72
-
73
-	/** @var IManager */
74
-	private $activityManager;
75
-
76
-	/** @var LoggerInterface */
77
-	private $logger;
78
-
79
-	/** @var TokenProvider */
80
-	private $tokenProvider;
81
-
82
-	/** @var ITimeFactory */
83
-	private $timeFactory;
84
-
85
-	/** @var IEventDispatcher */
86
-	private $dispatcher;
87
-
88
-	/** @var EventDispatcherInterface */
89
-	private $legacyDispatcher;
90
-
91
-	public function __construct(ProviderLoader $providerLoader,
92
-								IRegistry $providerRegistry,
93
-								MandatoryTwoFactor $mandatoryTwoFactor,
94
-								ISession $session,
95
-								IConfig $config,
96
-								IManager $activityManager,
97
-								LoggerInterface $logger,
98
-								TokenProvider $tokenProvider,
99
-								ITimeFactory $timeFactory,
100
-								IEventDispatcher $eventDispatcher,
101
-								EventDispatcherInterface $legacyDispatcher) {
102
-		$this->providerLoader = $providerLoader;
103
-		$this->providerRegistry = $providerRegistry;
104
-		$this->mandatoryTwoFactor = $mandatoryTwoFactor;
105
-		$this->session = $session;
106
-		$this->config = $config;
107
-		$this->activityManager = $activityManager;
108
-		$this->logger = $logger;
109
-		$this->tokenProvider = $tokenProvider;
110
-		$this->timeFactory = $timeFactory;
111
-		$this->dispatcher = $eventDispatcher;
112
-		$this->legacyDispatcher = $legacyDispatcher;
113
-	}
114
-
115
-	/**
116
-	 * Determine whether the user must provide a second factor challenge
117
-	 *
118
-	 * @param IUser $user
119
-	 * @return boolean
120
-	 */
121
-	public function isTwoFactorAuthenticated(IUser $user): bool {
122
-		if ($this->mandatoryTwoFactor->isEnforcedFor($user)) {
123
-			return true;
124
-		}
125
-
126
-		$providerStates = $this->providerRegistry->getProviderStates($user);
127
-		$providers = $this->providerLoader->getProviders($user);
128
-		$fixedStates = $this->fixMissingProviderStates($providerStates, $providers, $user);
129
-		$enabled = array_filter($fixedStates);
130
-		$providerIds = array_keys($enabled);
131
-		$providerIdsWithoutBackupCodes = array_diff($providerIds, [self::BACKUP_CODES_PROVIDER_ID]);
132
-
133
-		return !empty($providerIdsWithoutBackupCodes);
134
-	}
135
-
136
-	/**
137
-	 * Get a 2FA provider by its ID
138
-	 *
139
-	 * @param IUser $user
140
-	 * @param string $challengeProviderId
141
-	 * @return IProvider|null
142
-	 */
143
-	public function getProvider(IUser $user, string $challengeProviderId) {
144
-		$providers = $this->getProviderSet($user)->getProviders();
145
-		return $providers[$challengeProviderId] ?? null;
146
-	}
147
-
148
-	/**
149
-	 * @param IUser $user
150
-	 * @return IActivatableAtLogin[]
151
-	 * @throws Exception
152
-	 */
153
-	public function getLoginSetupProviders(IUser $user): array {
154
-		$providers = $this->providerLoader->getProviders($user);
155
-		return array_filter($providers, function (IProvider $provider) {
156
-			return ($provider instanceof IActivatableAtLogin);
157
-		});
158
-	}
159
-
160
-	/**
161
-	 * Check if the persistant mapping of enabled/disabled state of each available
162
-	 * provider is missing an entry and add it to the registry in that case.
163
-	 *
164
-	 * @todo remove in Nextcloud 17 as by then all providers should have been updated
165
-	 *
166
-	 * @param string[] $providerStates
167
-	 * @param IProvider[] $providers
168
-	 * @param IUser $user
169
-	 * @return string[] the updated $providerStates variable
170
-	 */
171
-	private function fixMissingProviderStates(array $providerStates,
172
-		array $providers, IUser $user): array {
173
-		foreach ($providers as $provider) {
174
-			if (isset($providerStates[$provider->getId()])) {
175
-				// All good
176
-				continue;
177
-			}
178
-
179
-			$enabled = $provider->isTwoFactorAuthEnabledForUser($user);
180
-			if ($enabled) {
181
-				$this->providerRegistry->enableProviderFor($provider, $user);
182
-			} else {
183
-				$this->providerRegistry->disableProviderFor($provider, $user);
184
-			}
185
-			$providerStates[$provider->getId()] = $enabled;
186
-		}
187
-
188
-		return $providerStates;
189
-	}
190
-
191
-	/**
192
-	 * @param array $states
193
-	 * @param IProvider[] $providers
194
-	 */
195
-	private function isProviderMissing(array $states, array $providers): bool {
196
-		$indexed = [];
197
-		foreach ($providers as $provider) {
198
-			$indexed[$provider->getId()] = $provider;
199
-		}
200
-
201
-		$missing = [];
202
-		foreach ($states as $providerId => $enabled) {
203
-			if (!$enabled) {
204
-				// Don't care
205
-				continue;
206
-			}
207
-
208
-			if (!isset($indexed[$providerId])) {
209
-				$missing[] = $providerId;
210
-				$this->logger->alert("two-factor auth provider '$providerId' failed to load",
211
-					[
212
-						'app' => 'core',
213
-					]);
214
-			}
215
-		}
216
-
217
-		if (!empty($missing)) {
218
-			// There was at least one provider missing
219
-			$this->logger->alert(count($missing) . " two-factor auth providers failed to load", ['app' => 'core']);
220
-
221
-			return true;
222
-		}
223
-
224
-		// If we reach this, there was not a single provider missing
225
-		return false;
226
-	}
227
-
228
-	/**
229
-	 * Get the list of 2FA providers for the given user
230
-	 *
231
-	 * @param IUser $user
232
-	 * @throws Exception
233
-	 */
234
-	public function getProviderSet(IUser $user): ProviderSet {
235
-		$providerStates = $this->providerRegistry->getProviderStates($user);
236
-		$providers = $this->providerLoader->getProviders($user);
237
-
238
-		$fixedStates = $this->fixMissingProviderStates($providerStates, $providers, $user);
239
-		$isProviderMissing = $this->isProviderMissing($fixedStates, $providers);
240
-
241
-		$enabled = array_filter($providers, function (IProvider $provider) use ($fixedStates) {
242
-			return $fixedStates[$provider->getId()];
243
-		});
244
-		return new ProviderSet($enabled, $isProviderMissing);
245
-	}
246
-
247
-	/**
248
-	 * Verify the given challenge
249
-	 *
250
-	 * @param string $providerId
251
-	 * @param IUser $user
252
-	 * @param string $challenge
253
-	 * @return boolean
254
-	 */
255
-	public function verifyChallenge(string $providerId, IUser $user, string $challenge): bool {
256
-		$provider = $this->getProvider($user, $providerId);
257
-		if ($provider === null) {
258
-			return false;
259
-		}
260
-
261
-		$passed = $provider->verifyChallenge($user, $challenge);
262
-		if ($passed) {
263
-			if ($this->session->get(self::REMEMBER_LOGIN) === true) {
264
-				// TODO: resolve cyclic dependency and use DI
265
-				\OC::$server->getUserSession()->createRememberMeToken($user);
266
-			}
267
-			$this->session->remove(self::SESSION_UID_KEY);
268
-			$this->session->remove(self::REMEMBER_LOGIN);
269
-			$this->session->set(self::SESSION_UID_DONE, $user->getUID());
270
-
271
-			// Clear token from db
272
-			$sessionId = $this->session->getId();
273
-			$token = $this->tokenProvider->getToken($sessionId);
274
-			$tokenId = $token->getId();
275
-			$this->config->deleteUserValue($user->getUID(), 'login_token_2fa', $tokenId);
276
-
277
-			$dispatchEvent = new GenericEvent($user, ['provider' => $provider->getDisplayName()]);
278
-			$this->legacyDispatcher->dispatch(IProvider::EVENT_SUCCESS, $dispatchEvent);
279
-
280
-			$this->dispatcher->dispatchTyped(new TwoFactorProviderForUserEnabled($user, $provider));
281
-
282
-			$this->publishEvent($user, 'twofactor_success', [
283
-				'provider' => $provider->getDisplayName(),
284
-			]);
285
-		} else {
286
-			$dispatchEvent = new GenericEvent($user, ['provider' => $provider->getDisplayName()]);
287
-			$this->legacyDispatcher->dispatch(IProvider::EVENT_FAILED, $dispatchEvent);
288
-
289
-			$this->dispatcher->dispatchTyped(new TwoFactorProviderForUserDisabled($user, $provider));
290
-
291
-			$this->publishEvent($user, 'twofactor_failed', [
292
-				'provider' => $provider->getDisplayName(),
293
-			]);
294
-		}
295
-		return $passed;
296
-	}
297
-
298
-	/**
299
-	 * Push a 2fa event the user's activity stream
300
-	 *
301
-	 * @param IUser $user
302
-	 * @param string $event
303
-	 * @param array $params
304
-	 */
305
-	private function publishEvent(IUser $user, string $event, array $params) {
306
-		$activity = $this->activityManager->generateEvent();
307
-		$activity->setApp('core')
308
-			->setType('security')
309
-			->setAuthor($user->getUID())
310
-			->setAffectedUser($user->getUID())
311
-			->setSubject($event, $params);
312
-		try {
313
-			$this->activityManager->publish($activity);
314
-		} catch (BadMethodCallException $e) {
315
-			$this->logger->warning('could not publish activity', ['app' => 'core', 'exception' => $e]);
316
-		}
317
-	}
318
-
319
-	/**
320
-	 * Check if the currently logged in user needs to pass 2FA
321
-	 *
322
-	 * @param IUser $user the currently logged in user
323
-	 * @return boolean
324
-	 */
325
-	public function needsSecondFactor(IUser $user = null): bool {
326
-		if ($user === null) {
327
-			return false;
328
-		}
329
-
330
-		// If we are authenticated using an app password skip all this
331
-		if ($this->session->exists('app_password')) {
332
-			return false;
333
-		}
334
-
335
-		// First check if the session tells us we should do 2FA (99% case)
336
-		if (!$this->session->exists(self::SESSION_UID_KEY)) {
337
-
338
-			// Check if the session tells us it is 2FA authenticated already
339
-			if ($this->session->exists(self::SESSION_UID_DONE) &&
340
-				$this->session->get(self::SESSION_UID_DONE) === $user->getUID()) {
341
-				return false;
342
-			}
343
-
344
-			/*
53
+    public const SESSION_UID_KEY = 'two_factor_auth_uid';
54
+    public const SESSION_UID_DONE = 'two_factor_auth_passed';
55
+    public const REMEMBER_LOGIN = 'two_factor_remember_login';
56
+    public const BACKUP_CODES_PROVIDER_ID = 'backup_codes';
57
+
58
+    /** @var ProviderLoader */
59
+    private $providerLoader;
60
+
61
+    /** @var IRegistry */
62
+    private $providerRegistry;
63
+
64
+    /** @var MandatoryTwoFactor */
65
+    private $mandatoryTwoFactor;
66
+
67
+    /** @var ISession */
68
+    private $session;
69
+
70
+    /** @var IConfig */
71
+    private $config;
72
+
73
+    /** @var IManager */
74
+    private $activityManager;
75
+
76
+    /** @var LoggerInterface */
77
+    private $logger;
78
+
79
+    /** @var TokenProvider */
80
+    private $tokenProvider;
81
+
82
+    /** @var ITimeFactory */
83
+    private $timeFactory;
84
+
85
+    /** @var IEventDispatcher */
86
+    private $dispatcher;
87
+
88
+    /** @var EventDispatcherInterface */
89
+    private $legacyDispatcher;
90
+
91
+    public function __construct(ProviderLoader $providerLoader,
92
+                                IRegistry $providerRegistry,
93
+                                MandatoryTwoFactor $mandatoryTwoFactor,
94
+                                ISession $session,
95
+                                IConfig $config,
96
+                                IManager $activityManager,
97
+                                LoggerInterface $logger,
98
+                                TokenProvider $tokenProvider,
99
+                                ITimeFactory $timeFactory,
100
+                                IEventDispatcher $eventDispatcher,
101
+                                EventDispatcherInterface $legacyDispatcher) {
102
+        $this->providerLoader = $providerLoader;
103
+        $this->providerRegistry = $providerRegistry;
104
+        $this->mandatoryTwoFactor = $mandatoryTwoFactor;
105
+        $this->session = $session;
106
+        $this->config = $config;
107
+        $this->activityManager = $activityManager;
108
+        $this->logger = $logger;
109
+        $this->tokenProvider = $tokenProvider;
110
+        $this->timeFactory = $timeFactory;
111
+        $this->dispatcher = $eventDispatcher;
112
+        $this->legacyDispatcher = $legacyDispatcher;
113
+    }
114
+
115
+    /**
116
+     * Determine whether the user must provide a second factor challenge
117
+     *
118
+     * @param IUser $user
119
+     * @return boolean
120
+     */
121
+    public function isTwoFactorAuthenticated(IUser $user): bool {
122
+        if ($this->mandatoryTwoFactor->isEnforcedFor($user)) {
123
+            return true;
124
+        }
125
+
126
+        $providerStates = $this->providerRegistry->getProviderStates($user);
127
+        $providers = $this->providerLoader->getProviders($user);
128
+        $fixedStates = $this->fixMissingProviderStates($providerStates, $providers, $user);
129
+        $enabled = array_filter($fixedStates);
130
+        $providerIds = array_keys($enabled);
131
+        $providerIdsWithoutBackupCodes = array_diff($providerIds, [self::BACKUP_CODES_PROVIDER_ID]);
132
+
133
+        return !empty($providerIdsWithoutBackupCodes);
134
+    }
135
+
136
+    /**
137
+     * Get a 2FA provider by its ID
138
+     *
139
+     * @param IUser $user
140
+     * @param string $challengeProviderId
141
+     * @return IProvider|null
142
+     */
143
+    public function getProvider(IUser $user, string $challengeProviderId) {
144
+        $providers = $this->getProviderSet($user)->getProviders();
145
+        return $providers[$challengeProviderId] ?? null;
146
+    }
147
+
148
+    /**
149
+     * @param IUser $user
150
+     * @return IActivatableAtLogin[]
151
+     * @throws Exception
152
+     */
153
+    public function getLoginSetupProviders(IUser $user): array {
154
+        $providers = $this->providerLoader->getProviders($user);
155
+        return array_filter($providers, function (IProvider $provider) {
156
+            return ($provider instanceof IActivatableAtLogin);
157
+        });
158
+    }
159
+
160
+    /**
161
+     * Check if the persistant mapping of enabled/disabled state of each available
162
+     * provider is missing an entry and add it to the registry in that case.
163
+     *
164
+     * @todo remove in Nextcloud 17 as by then all providers should have been updated
165
+     *
166
+     * @param string[] $providerStates
167
+     * @param IProvider[] $providers
168
+     * @param IUser $user
169
+     * @return string[] the updated $providerStates variable
170
+     */
171
+    private function fixMissingProviderStates(array $providerStates,
172
+        array $providers, IUser $user): array {
173
+        foreach ($providers as $provider) {
174
+            if (isset($providerStates[$provider->getId()])) {
175
+                // All good
176
+                continue;
177
+            }
178
+
179
+            $enabled = $provider->isTwoFactorAuthEnabledForUser($user);
180
+            if ($enabled) {
181
+                $this->providerRegistry->enableProviderFor($provider, $user);
182
+            } else {
183
+                $this->providerRegistry->disableProviderFor($provider, $user);
184
+            }
185
+            $providerStates[$provider->getId()] = $enabled;
186
+        }
187
+
188
+        return $providerStates;
189
+    }
190
+
191
+    /**
192
+     * @param array $states
193
+     * @param IProvider[] $providers
194
+     */
195
+    private function isProviderMissing(array $states, array $providers): bool {
196
+        $indexed = [];
197
+        foreach ($providers as $provider) {
198
+            $indexed[$provider->getId()] = $provider;
199
+        }
200
+
201
+        $missing = [];
202
+        foreach ($states as $providerId => $enabled) {
203
+            if (!$enabled) {
204
+                // Don't care
205
+                continue;
206
+            }
207
+
208
+            if (!isset($indexed[$providerId])) {
209
+                $missing[] = $providerId;
210
+                $this->logger->alert("two-factor auth provider '$providerId' failed to load",
211
+                    [
212
+                        'app' => 'core',
213
+                    ]);
214
+            }
215
+        }
216
+
217
+        if (!empty($missing)) {
218
+            // There was at least one provider missing
219
+            $this->logger->alert(count($missing) . " two-factor auth providers failed to load", ['app' => 'core']);
220
+
221
+            return true;
222
+        }
223
+
224
+        // If we reach this, there was not a single provider missing
225
+        return false;
226
+    }
227
+
228
+    /**
229
+     * Get the list of 2FA providers for the given user
230
+     *
231
+     * @param IUser $user
232
+     * @throws Exception
233
+     */
234
+    public function getProviderSet(IUser $user): ProviderSet {
235
+        $providerStates = $this->providerRegistry->getProviderStates($user);
236
+        $providers = $this->providerLoader->getProviders($user);
237
+
238
+        $fixedStates = $this->fixMissingProviderStates($providerStates, $providers, $user);
239
+        $isProviderMissing = $this->isProviderMissing($fixedStates, $providers);
240
+
241
+        $enabled = array_filter($providers, function (IProvider $provider) use ($fixedStates) {
242
+            return $fixedStates[$provider->getId()];
243
+        });
244
+        return new ProviderSet($enabled, $isProviderMissing);
245
+    }
246
+
247
+    /**
248
+     * Verify the given challenge
249
+     *
250
+     * @param string $providerId
251
+     * @param IUser $user
252
+     * @param string $challenge
253
+     * @return boolean
254
+     */
255
+    public function verifyChallenge(string $providerId, IUser $user, string $challenge): bool {
256
+        $provider = $this->getProvider($user, $providerId);
257
+        if ($provider === null) {
258
+            return false;
259
+        }
260
+
261
+        $passed = $provider->verifyChallenge($user, $challenge);
262
+        if ($passed) {
263
+            if ($this->session->get(self::REMEMBER_LOGIN) === true) {
264
+                // TODO: resolve cyclic dependency and use DI
265
+                \OC::$server->getUserSession()->createRememberMeToken($user);
266
+            }
267
+            $this->session->remove(self::SESSION_UID_KEY);
268
+            $this->session->remove(self::REMEMBER_LOGIN);
269
+            $this->session->set(self::SESSION_UID_DONE, $user->getUID());
270
+
271
+            // Clear token from db
272
+            $sessionId = $this->session->getId();
273
+            $token = $this->tokenProvider->getToken($sessionId);
274
+            $tokenId = $token->getId();
275
+            $this->config->deleteUserValue($user->getUID(), 'login_token_2fa', $tokenId);
276
+
277
+            $dispatchEvent = new GenericEvent($user, ['provider' => $provider->getDisplayName()]);
278
+            $this->legacyDispatcher->dispatch(IProvider::EVENT_SUCCESS, $dispatchEvent);
279
+
280
+            $this->dispatcher->dispatchTyped(new TwoFactorProviderForUserEnabled($user, $provider));
281
+
282
+            $this->publishEvent($user, 'twofactor_success', [
283
+                'provider' => $provider->getDisplayName(),
284
+            ]);
285
+        } else {
286
+            $dispatchEvent = new GenericEvent($user, ['provider' => $provider->getDisplayName()]);
287
+            $this->legacyDispatcher->dispatch(IProvider::EVENT_FAILED, $dispatchEvent);
288
+
289
+            $this->dispatcher->dispatchTyped(new TwoFactorProviderForUserDisabled($user, $provider));
290
+
291
+            $this->publishEvent($user, 'twofactor_failed', [
292
+                'provider' => $provider->getDisplayName(),
293
+            ]);
294
+        }
295
+        return $passed;
296
+    }
297
+
298
+    /**
299
+     * Push a 2fa event the user's activity stream
300
+     *
301
+     * @param IUser $user
302
+     * @param string $event
303
+     * @param array $params
304
+     */
305
+    private function publishEvent(IUser $user, string $event, array $params) {
306
+        $activity = $this->activityManager->generateEvent();
307
+        $activity->setApp('core')
308
+            ->setType('security')
309
+            ->setAuthor($user->getUID())
310
+            ->setAffectedUser($user->getUID())
311
+            ->setSubject($event, $params);
312
+        try {
313
+            $this->activityManager->publish($activity);
314
+        } catch (BadMethodCallException $e) {
315
+            $this->logger->warning('could not publish activity', ['app' => 'core', 'exception' => $e]);
316
+        }
317
+    }
318
+
319
+    /**
320
+     * Check if the currently logged in user needs to pass 2FA
321
+     *
322
+     * @param IUser $user the currently logged in user
323
+     * @return boolean
324
+     */
325
+    public function needsSecondFactor(IUser $user = null): bool {
326
+        if ($user === null) {
327
+            return false;
328
+        }
329
+
330
+        // If we are authenticated using an app password skip all this
331
+        if ($this->session->exists('app_password')) {
332
+            return false;
333
+        }
334
+
335
+        // First check if the session tells us we should do 2FA (99% case)
336
+        if (!$this->session->exists(self::SESSION_UID_KEY)) {
337
+
338
+            // Check if the session tells us it is 2FA authenticated already
339
+            if ($this->session->exists(self::SESSION_UID_DONE) &&
340
+                $this->session->get(self::SESSION_UID_DONE) === $user->getUID()) {
341
+                return false;
342
+            }
343
+
344
+            /*
345 345
 			 * If the session is expired check if we are not logged in by a token
346 346
 			 * that still needs 2FA auth
347 347
 			 */
348
-			try {
349
-				$sessionId = $this->session->getId();
350
-				$token = $this->tokenProvider->getToken($sessionId);
351
-				$tokenId = $token->getId();
352
-				$tokensNeeding2FA = $this->config->getUserKeys($user->getUID(), 'login_token_2fa');
353
-
354
-				if (!\in_array((string) $tokenId, $tokensNeeding2FA, true)) {
355
-					$this->session->set(self::SESSION_UID_DONE, $user->getUID());
356
-					return false;
357
-				}
358
-			} catch (InvalidTokenException $e) {
359
-			}
360
-		}
361
-
362
-		if (!$this->isTwoFactorAuthenticated($user)) {
363
-			// There is no second factor any more -> let the user pass
364
-			//   This prevents infinite redirect loops when a user is about
365
-			//   to solve the 2FA challenge, and the provider app is
366
-			//   disabled the same time
367
-			$this->session->remove(self::SESSION_UID_KEY);
368
-
369
-			$keys = $this->config->getUserKeys($user->getUID(), 'login_token_2fa');
370
-			foreach ($keys as $key) {
371
-				$this->config->deleteUserValue($user->getUID(), 'login_token_2fa', $key);
372
-			}
373
-			return false;
374
-		}
375
-
376
-		return true;
377
-	}
378
-
379
-	/**
380
-	 * Prepare the 2FA login
381
-	 *
382
-	 * @param IUser $user
383
-	 * @param boolean $rememberMe
384
-	 */
385
-	public function prepareTwoFactorLogin(IUser $user, bool $rememberMe) {
386
-		$this->session->set(self::SESSION_UID_KEY, $user->getUID());
387
-		$this->session->set(self::REMEMBER_LOGIN, $rememberMe);
388
-
389
-		$id = $this->session->getId();
390
-		$token = $this->tokenProvider->getToken($id);
391
-		$this->config->setUserValue($user->getUID(), 'login_token_2fa', (string) $token->getId(), $this->timeFactory->getTime());
392
-	}
393
-
394
-	public function clearTwoFactorPending(string $userId) {
395
-		$tokensNeeding2FA = $this->config->getUserKeys($userId, 'login_token_2fa');
396
-
397
-		foreach ($tokensNeeding2FA as $tokenId) {
398
-			$this->tokenProvider->invalidateTokenById($userId, (int)$tokenId);
399
-		}
400
-	}
348
+            try {
349
+                $sessionId = $this->session->getId();
350
+                $token = $this->tokenProvider->getToken($sessionId);
351
+                $tokenId = $token->getId();
352
+                $tokensNeeding2FA = $this->config->getUserKeys($user->getUID(), 'login_token_2fa');
353
+
354
+                if (!\in_array((string) $tokenId, $tokensNeeding2FA, true)) {
355
+                    $this->session->set(self::SESSION_UID_DONE, $user->getUID());
356
+                    return false;
357
+                }
358
+            } catch (InvalidTokenException $e) {
359
+            }
360
+        }
361
+
362
+        if (!$this->isTwoFactorAuthenticated($user)) {
363
+            // There is no second factor any more -> let the user pass
364
+            //   This prevents infinite redirect loops when a user is about
365
+            //   to solve the 2FA challenge, and the provider app is
366
+            //   disabled the same time
367
+            $this->session->remove(self::SESSION_UID_KEY);
368
+
369
+            $keys = $this->config->getUserKeys($user->getUID(), 'login_token_2fa');
370
+            foreach ($keys as $key) {
371
+                $this->config->deleteUserValue($user->getUID(), 'login_token_2fa', $key);
372
+            }
373
+            return false;
374
+        }
375
+
376
+        return true;
377
+    }
378
+
379
+    /**
380
+     * Prepare the 2FA login
381
+     *
382
+     * @param IUser $user
383
+     * @param boolean $rememberMe
384
+     */
385
+    public function prepareTwoFactorLogin(IUser $user, bool $rememberMe) {
386
+        $this->session->set(self::SESSION_UID_KEY, $user->getUID());
387
+        $this->session->set(self::REMEMBER_LOGIN, $rememberMe);
388
+
389
+        $id = $this->session->getId();
390
+        $token = $this->tokenProvider->getToken($id);
391
+        $this->config->setUserValue($user->getUID(), 'login_token_2fa', (string) $token->getId(), $this->timeFactory->getTime());
392
+    }
393
+
394
+    public function clearTwoFactorPending(string $userId) {
395
+        $tokensNeeding2FA = $this->config->getUserKeys($userId, 'login_token_2fa');
396
+
397
+        foreach ($tokensNeeding2FA as $tokenId) {
398
+            $this->tokenProvider->invalidateTokenById($userId, (int)$tokenId);
399
+        }
400
+    }
401 401
 }
Please login to merge, or discard this patch.