Test Setup Failed
Push — dependabot/composer/twbs/boots... ( 3e72c6 )
by
unknown
13:19
created
includes/Pages/PageMain.php 1 patch
Indentation   +157 added lines, -157 removed lines patch added patch discarded remove patch
@@ -20,54 +20,54 @@  discard block
 block discarded – undo
20 20
 
21 21
 class PageMain extends InternalPageBase
22 22
 {
23
-    use RequestListData;
24
-
25
-    /**
26
-     * Main function for this page, when no actions are called.
27
-     */
28
-    protected function main()
29
-    {
30
-        $this->assignCSRFToken();
31
-
32
-        $config = $this->getSiteConfiguration();
33
-        $database = $this->getDatabase();
34
-        $currentUser = User::getCurrent($database);
35
-
36
-        // general template configuration
37
-        $this->assign('defaultRequestState', $config->getDefaultRequestStateKey());
38
-        $this->assign('requestLimitShowOnly', $config->getMiserModeLimit());
39
-
40
-        $seeAllRequests = $this->barrierTest('seeAllRequests', $currentUser, PageViewRequest::class);
41
-
42
-        // Fetch request data
43
-        $requestSectionData = array();
44
-        if ($seeAllRequests) {
45
-            $this->setupStatusSections($database, $config, $requestSectionData);
46
-            $this->setupHospitalQueue($database, $config, $requestSectionData);
47
-            $this->setupJobQueue($database, $config, $requestSectionData);
48
-        }
49
-        $this->setupLastFiveClosedData($database, $seeAllRequests);
50
-
51
-        // Assign data to template
52
-        $this->assign('requestSectionData', $requestSectionData);
53
-
54
-        $this->setTemplate('mainpage/mainpage.tpl');
55
-    }
56
-
57
-    /**
58
-     * @param PdoDatabase $database
59
-     * @param bool        $seeAllRequests
60
-     *
61
-     * @internal param User $currentUser
62
-     */
63
-    private function setupLastFiveClosedData(PdoDatabase $database, $seeAllRequests)
64
-    {
65
-        $this->assign('showLastFive', $seeAllRequests);
66
-        if (!$seeAllRequests) {
67
-            return;
68
-        }
69
-
70
-        $query = <<<SQL
23
+	use RequestListData;
24
+
25
+	/**
26
+	 * Main function for this page, when no actions are called.
27
+	 */
28
+	protected function main()
29
+	{
30
+		$this->assignCSRFToken();
31
+
32
+		$config = $this->getSiteConfiguration();
33
+		$database = $this->getDatabase();
34
+		$currentUser = User::getCurrent($database);
35
+
36
+		// general template configuration
37
+		$this->assign('defaultRequestState', $config->getDefaultRequestStateKey());
38
+		$this->assign('requestLimitShowOnly', $config->getMiserModeLimit());
39
+
40
+		$seeAllRequests = $this->barrierTest('seeAllRequests', $currentUser, PageViewRequest::class);
41
+
42
+		// Fetch request data
43
+		$requestSectionData = array();
44
+		if ($seeAllRequests) {
45
+			$this->setupStatusSections($database, $config, $requestSectionData);
46
+			$this->setupHospitalQueue($database, $config, $requestSectionData);
47
+			$this->setupJobQueue($database, $config, $requestSectionData);
48
+		}
49
+		$this->setupLastFiveClosedData($database, $seeAllRequests);
50
+
51
+		// Assign data to template
52
+		$this->assign('requestSectionData', $requestSectionData);
53
+
54
+		$this->setTemplate('mainpage/mainpage.tpl');
55
+	}
56
+
57
+	/**
58
+	 * @param PdoDatabase $database
59
+	 * @param bool        $seeAllRequests
60
+	 *
61
+	 * @internal param User $currentUser
62
+	 */
63
+	private function setupLastFiveClosedData(PdoDatabase $database, $seeAllRequests)
64
+	{
65
+		$this->assign('showLastFive', $seeAllRequests);
66
+		if (!$seeAllRequests) {
67
+			return;
68
+		}
69
+
70
+		$query = <<<SQL
71 71
 		SELECT request.id, request.name, request.updateversion
72 72
 		FROM request /* PageMain::main() */
73 73
 		JOIN log ON log.objectid = request.id AND log.objecttype = 'Request'
@@ -76,113 +76,113 @@  discard block
 block discarded – undo
76 76
 		LIMIT 5;
77 77
 SQL;
78 78
 
79
-        $statement = $database->prepare($query);
80
-        $statement->execute();
81
-
82
-        $last5result = $statement->fetchAll(PDO::FETCH_ASSOC);
83
-
84
-        $this->assign('lastFive', $last5result);
85
-    }
86
-
87
-    /**
88
-     * @param PdoDatabase       $database
89
-     * @param SiteConfiguration $config
90
-     * @param                   $requestSectionData
91
-     */
92
-    private function setupHospitalQueue(
93
-        PdoDatabase $database,
94
-        SiteConfiguration $config,
95
-        &$requestSectionData
96
-    ) {
97
-        $search = RequestSearchHelper::get($database)
98
-            ->limit($config->getMiserModeLimit())
99
-            ->excludingStatus('Closed')
100
-            ->isHospitalised();
101
-
102
-        if ($config->getEmailConfirmationEnabled()) {
103
-            $search->withConfirmedEmail();
104
-        }
105
-
106
-        /** @var Request[] $results */
107
-        $results = $search->getRecordCount($requestCount)->fetch();
108
-
109
-        if($requestCount > 0) {
110
-            $requestSectionData['Hospital - Requests failed auto-creation'] = array(
111
-                'requests' => $this->prepareRequestData($results),
112
-                'total'    => $requestCount,
113
-                'api'      => 'hospital',
114
-                'type'     => 'hospital',
115
-                'special'  => 'Job Queue',
116
-                'help'     => 'This queue lists all the requests which have been attempted to be created in the background, but for which this has failed for one reason or another. Check the job queue to find the error. Requests here may need to be created manually, or it may be possible to re-queue the request for auto-creation by the tool, or it may have been created already. Use your own technical discretion here.',
117
-                'showAll'  => false
118
-            );
119
-        }
120
-    }
121
-
122
-    /**
123
-     * @param PdoDatabase       $database
124
-     * @param SiteConfiguration $config
125
-     * @param                   $requestSectionData
126
-     */
127
-    private function setupJobQueue(
128
-        PdoDatabase $database,
129
-        SiteConfiguration $config,
130
-        &$requestSectionData
131
-    ) {
132
-        $search = RequestSearchHelper::get($database)
133
-            ->limit($config->getMiserModeLimit())
134
-            ->byStatus(RequestStatus::JOBQUEUE);
135
-
136
-        if ($config->getEmailConfirmationEnabled()) {
137
-            $search->withConfirmedEmail();
138
-        }
139
-
140
-        /** @var Request[] $results */
141
-        $results = $search->getRecordCount($requestCount)->fetch();
142
-
143
-        if($requestCount > 0) {
144
-            $requestSectionData['Requests queued in the Job Queue'] = array(
145
-                'requests' => $this->prepareRequestData($results),
146
-                'total'    => $requestCount,
147
-                'api'      => 'JobQueue',
148
-                'type'     => 'JobQueue',
149
-                'special'  => 'Job Queue',
150
-                'help'     => 'This section lists all the requests which are currently waiting to be created by the tool. Requests should automatically disappear from here within a few minutes.',
151
-                'showAll'  => false
152
-            );
153
-        }
154
-    }
155
-
156
-    /**
157
-     * @param PdoDatabase       $database
158
-     * @param SiteConfiguration $config
159
-     * @param                   $requestSectionData
160
-     */
161
-    private function setupStatusSections(
162
-        PdoDatabase $database,
163
-        SiteConfiguration $config,
164
-        &$requestSectionData
165
-    ) {
166
-        $search = RequestSearchHelper::get($database)->limit($config->getMiserModeLimit())->notHospitalised();
167
-
168
-        if ($config->getEmailConfirmationEnabled()) {
169
-            $search->withConfirmedEmail();
170
-        }
171
-
172
-        $allRequestStates = $config->getRequestStates();
173
-        $requestsByStatus = $search->fetchByStatus(array_keys($allRequestStates));
174
-
175
-        foreach ($allRequestStates as $requestState => $requestStateConfig) {
176
-
177
-            $requestSectionData[$requestStateConfig['header']] = array(
178
-                'requests' => $this->prepareRequestData($requestsByStatus[$requestState]['data']),
179
-                'total'    => $requestsByStatus[$requestState]['count'],
180
-                'api'      => $requestStateConfig['api'],
181
-                'type'     => $requestState,
182
-                'special'  => null,
183
-                'help'     => $requestStateConfig['queuehelp'],
184
-                'showAll'  => true
185
-            );
186
-        }
187
-    }
79
+		$statement = $database->prepare($query);
80
+		$statement->execute();
81
+
82
+		$last5result = $statement->fetchAll(PDO::FETCH_ASSOC);
83
+
84
+		$this->assign('lastFive', $last5result);
85
+	}
86
+
87
+	/**
88
+	 * @param PdoDatabase       $database
89
+	 * @param SiteConfiguration $config
90
+	 * @param                   $requestSectionData
91
+	 */
92
+	private function setupHospitalQueue(
93
+		PdoDatabase $database,
94
+		SiteConfiguration $config,
95
+		&$requestSectionData
96
+	) {
97
+		$search = RequestSearchHelper::get($database)
98
+			->limit($config->getMiserModeLimit())
99
+			->excludingStatus('Closed')
100
+			->isHospitalised();
101
+
102
+		if ($config->getEmailConfirmationEnabled()) {
103
+			$search->withConfirmedEmail();
104
+		}
105
+
106
+		/** @var Request[] $results */
107
+		$results = $search->getRecordCount($requestCount)->fetch();
108
+
109
+		if($requestCount > 0) {
110
+			$requestSectionData['Hospital - Requests failed auto-creation'] = array(
111
+				'requests' => $this->prepareRequestData($results),
112
+				'total'    => $requestCount,
113
+				'api'      => 'hospital',
114
+				'type'     => 'hospital',
115
+				'special'  => 'Job Queue',
116
+				'help'     => 'This queue lists all the requests which have been attempted to be created in the background, but for which this has failed for one reason or another. Check the job queue to find the error. Requests here may need to be created manually, or it may be possible to re-queue the request for auto-creation by the tool, or it may have been created already. Use your own technical discretion here.',
117
+				'showAll'  => false
118
+			);
119
+		}
120
+	}
121
+
122
+	/**
123
+	 * @param PdoDatabase       $database
124
+	 * @param SiteConfiguration $config
125
+	 * @param                   $requestSectionData
126
+	 */
127
+	private function setupJobQueue(
128
+		PdoDatabase $database,
129
+		SiteConfiguration $config,
130
+		&$requestSectionData
131
+	) {
132
+		$search = RequestSearchHelper::get($database)
133
+			->limit($config->getMiserModeLimit())
134
+			->byStatus(RequestStatus::JOBQUEUE);
135
+
136
+		if ($config->getEmailConfirmationEnabled()) {
137
+			$search->withConfirmedEmail();
138
+		}
139
+
140
+		/** @var Request[] $results */
141
+		$results = $search->getRecordCount($requestCount)->fetch();
142
+
143
+		if($requestCount > 0) {
144
+			$requestSectionData['Requests queued in the Job Queue'] = array(
145
+				'requests' => $this->prepareRequestData($results),
146
+				'total'    => $requestCount,
147
+				'api'      => 'JobQueue',
148
+				'type'     => 'JobQueue',
149
+				'special'  => 'Job Queue',
150
+				'help'     => 'This section lists all the requests which are currently waiting to be created by the tool. Requests should automatically disappear from here within a few minutes.',
151
+				'showAll'  => false
152
+			);
153
+		}
154
+	}
155
+
156
+	/**
157
+	 * @param PdoDatabase       $database
158
+	 * @param SiteConfiguration $config
159
+	 * @param                   $requestSectionData
160
+	 */
161
+	private function setupStatusSections(
162
+		PdoDatabase $database,
163
+		SiteConfiguration $config,
164
+		&$requestSectionData
165
+	) {
166
+		$search = RequestSearchHelper::get($database)->limit($config->getMiserModeLimit())->notHospitalised();
167
+
168
+		if ($config->getEmailConfirmationEnabled()) {
169
+			$search->withConfirmedEmail();
170
+		}
171
+
172
+		$allRequestStates = $config->getRequestStates();
173
+		$requestsByStatus = $search->fetchByStatus(array_keys($allRequestStates));
174
+
175
+		foreach ($allRequestStates as $requestState => $requestStateConfig) {
176
+
177
+			$requestSectionData[$requestStateConfig['header']] = array(
178
+				'requests' => $this->prepareRequestData($requestsByStatus[$requestState]['data']),
179
+				'total'    => $requestsByStatus[$requestState]['count'],
180
+				'api'      => $requestStateConfig['api'],
181
+				'type'     => $requestState,
182
+				'special'  => null,
183
+				'help'     => $requestStateConfig['queuehelp'],
184
+				'showAll'  => true
185
+			);
186
+		}
187
+	}
188 188
 }
Please login to merge, or discard this patch.
includes/Pages/UserAuth/Login/PagePasswordLogin.php 1 patch
Indentation   +27 added lines, -27 removed lines patch added patch discarded remove patch
@@ -13,31 +13,31 @@
 block discarded – undo
13 13
 
14 14
 class PagePasswordLogin extends LoginCredentialPageBase
15 15
 {
16
-    protected function providerSpecificSetup()
17
-    {
18
-        list($partialId, $partialStage) = WebRequest::getAuthPartialLogin();
19
-
20
-        if($partialId !== null && $partialStage > 1) {
21
-            $sql = 'SELECT type FROM credential WHERE user = :user AND factor = :stage AND disabled = 0 ORDER BY priority';
22
-            $statement = $this->getDatabase()->prepare($sql);
23
-            $statement->execute(array(':user' => $partialId, ':stage' => $partialStage));
24
-            $nextStage = $statement->fetchColumn();
25
-            $statement->closeCursor();
26
-
27
-            $this->redirect("login/" . $this->nextPageMap[$nextStage]);
28
-            return;
29
-        }
30
-
31
-        $this->setTemplate('login/password.tpl');
32
-    }
33
-
34
-    protected function getProviderCredentials()
35
-    {
36
-        $password = WebRequest::postString("password");
37
-        if ($password === null || $password === "") {
38
-            throw new ApplicationLogicException("No password specified");
39
-        }
40
-
41
-        return $password;
42
-    }
16
+	protected function providerSpecificSetup()
17
+	{
18
+		list($partialId, $partialStage) = WebRequest::getAuthPartialLogin();
19
+
20
+		if($partialId !== null && $partialStage > 1) {
21
+			$sql = 'SELECT type FROM credential WHERE user = :user AND factor = :stage AND disabled = 0 ORDER BY priority';
22
+			$statement = $this->getDatabase()->prepare($sql);
23
+			$statement->execute(array(':user' => $partialId, ':stage' => $partialStage));
24
+			$nextStage = $statement->fetchColumn();
25
+			$statement->closeCursor();
26
+
27
+			$this->redirect("login/" . $this->nextPageMap[$nextStage]);
28
+			return;
29
+		}
30
+
31
+		$this->setTemplate('login/password.tpl');
32
+	}
33
+
34
+	protected function getProviderCredentials()
35
+	{
36
+		$password = WebRequest::postString("password");
37
+		if ($password === null || $password === "") {
38
+			throw new ApplicationLogicException("No password specified");
39
+		}
40
+
41
+		return $password;
42
+	}
43 43
 }
44 44
\ No newline at end of file
Please login to merge, or discard this patch.
includes/Pages/UserAuth/Login/LoginCredentialPageBase.php 1 patch
Indentation   +311 added lines, -311 removed lines patch added patch discarded remove patch
@@ -21,315 +21,315 @@
 block discarded – undo
21 21
 
22 22
 abstract class LoginCredentialPageBase extends InternalPageBase
23 23
 {
24
-    /** @var User */
25
-    protected $partialUser = null;
26
-    protected $nextPageMap = array(
27
-        'yubikeyotp' => 'otp',
28
-        'totp'       => 'otp',
29
-        'scratch'    => 'otp',
30
-        'u2f'        => 'u2f',
31
-    );
32
-    protected $names = array(
33
-        'yubikeyotp' => 'Yubikey OTP',
34
-        'totp'       => 'TOTP (phone code generator)',
35
-        'scratch'    => 'scratch token',
36
-        'u2f'        => 'U2F security token',
37
-    );
38
-
39
-    /**
40
-     * Main function for this page, when no specific actions are called.
41
-     * @return void
42
-     */
43
-    protected function main()
44
-    {
45
-        if (!$this->enforceHttps()) {
46
-            return;
47
-        }
48
-
49
-        if (WebRequest::wasPosted()) {
50
-            $this->validateCSRFToken();
51
-
52
-            $database = $this->getDatabase();
53
-            try {
54
-                list($partialId, $partialStage) = WebRequest::getAuthPartialLogin();
55
-
56
-                if ($partialStage === null) {
57
-                    $partialStage = 1;
58
-                }
59
-
60
-                if ($partialId === null) {
61
-                    $username = WebRequest::postString('username');
62
-
63
-                    if ($username === null || trim($username) === '') {
64
-                        throw new ApplicationLogicException('No username specified.');
65
-                    }
66
-
67
-                    $user = User::getByUsername($username, $database);
68
-                }
69
-                else {
70
-                    $user = User::getById($partialId, $database);
71
-                }
72
-
73
-                if ($user === false) {
74
-                    throw new ApplicationLogicException("Authentication failed");
75
-                }
76
-
77
-                $authMan = new AuthenticationManager($database, $this->getSiteConfiguration(),
78
-                    $this->getHttpHelper());
79
-
80
-                $credential = $this->getProviderCredentials();
81
-
82
-                $authResult = $authMan->authenticate($user, $credential, $partialStage);
83
-
84
-                if ($authResult === AuthenticationManager::AUTH_FAIL) {
85
-                    throw new ApplicationLogicException("Authentication failed");
86
-                }
87
-
88
-                if ($authResult === AuthenticationManager::AUTH_REQUIRE_NEXT_STAGE) {
89
-                    $this->processJumpNextStage($user, $partialStage, $database);
90
-
91
-                    return;
92
-                }
93
-
94
-                if ($authResult === AuthenticationManager::AUTH_OK) {
95
-                    $this->processLoginSuccess($user);
96
-
97
-                    return;
98
-                }
99
-            }
100
-            catch (ApplicationLogicException $ex) {
101
-                WebRequest::clearAuthPartialLogin();
102
-
103
-                SessionAlert::error($ex->getMessage());
104
-                $this->redirect('login');
105
-
106
-                return;
107
-            }
108
-        }
109
-        else {
110
-            $this->assign('showSignIn', true);
111
-
112
-            $this->setupPartial();
113
-            $this->assignCSRFToken();
114
-            $this->providerSpecificSetup();
115
-        }
116
-    }
117
-
118
-    protected function isProtectedPage()
119
-    {
120
-        return false;
121
-    }
122
-
123
-    /**
124
-     * Enforces HTTPS on the login form
125
-     *
126
-     * @return bool
127
-     */
128
-    private function enforceHttps()
129
-    {
130
-        if ($this->getSiteConfiguration()->getUseStrictTransportSecurity() !== false) {
131
-            if (WebRequest::isHttps()) {
132
-                // Client can clearly use HTTPS, so let's enforce it for all connections.
133
-                $this->headerQueue[] = "Strict-Transport-Security: max-age=15768000";
134
-            }
135
-            else {
136
-                // This is the login form, not the request form. We need protection here.
137
-                $this->redirectUrl('https://' . WebRequest::serverName() . WebRequest::requestUri());
138
-
139
-                return false;
140
-            }
141
-        }
142
-
143
-        return true;
144
-    }
145
-
146
-    protected abstract function providerSpecificSetup();
147
-
148
-    protected function setupPartial()
149
-    {
150
-        $database = $this->getDatabase();
151
-
152
-        // default stuff
153
-        $this->assign('alternatives', array()); // 'u2f' => array('U2F token'), 'otp' => array('TOTP', 'scratch', 'yubiotp')));
154
-
155
-        // is this stage one?
156
-        list($partialId, $partialStage) = WebRequest::getAuthPartialLogin();
157
-        if ($partialStage === null || $partialId === null) {
158
-            WebRequest::clearAuthPartialLogin();
159
-        }
160
-
161
-        // Check to see if we have a partial login in progress
162
-        $username = null;
163
-        if ($partialId !== null) {
164
-            // Yes, enforce this username
165
-            $this->partialUser = User::getById($partialId, $database);
166
-            $username = $this->partialUser->getUsername();
167
-
168
-            $this->setupAlternates($this->partialUser, $partialStage, $database);
169
-        }
170
-        else {
171
-            // No, see if we've preloaded a username
172
-            $preloadUsername = WebRequest::getString('tplUsername');
173
-            if ($preloadUsername !== null) {
174
-                $username = $preloadUsername;
175
-            }
176
-        }
177
-
178
-        if ($partialStage === null) {
179
-            $partialStage = 1;
180
-        }
181
-
182
-        $this->assign('partialStage', $partialStage);
183
-        $this->assign('username', $username);
184
-    }
185
-
186
-    /**
187
-     * Redirect the user back to wherever they came from after a successful login
188
-     *
189
-     * @param User $user
190
-     */
191
-    protected function goBackWhenceYouCame(User $user)
192
-    {
193
-        // Redirect to wherever the user came from
194
-        $redirectDestination = WebRequest::clearPostLoginRedirect();
195
-        if ($redirectDestination !== null) {
196
-            $this->redirectUrl($redirectDestination);
197
-        }
198
-        else {
199
-            if ($user->isNewUser()) {
200
-                // home page isn't allowed, go to preferences instead
201
-                $this->redirect('preferences');
202
-            }
203
-            else {
204
-                // go to the home page
205
-                $this->redirect('');
206
-            }
207
-        }
208
-    }
209
-
210
-    private function processLoginSuccess(User $user)
211
-    {
212
-        // Touch force logout
213
-        $user->setForceLogout(false);
214
-        $user->save();
215
-
216
-        $oauth = new OAuthUserHelper($user, $this->getDatabase(), $this->getOAuthProtocolHelper(),
217
-            $this->getSiteConfiguration());
218
-
219
-        if ($oauth->isFullyLinked()) {
220
-            try {
221
-                // Reload the user's identity ticket.
222
-                $oauth->refreshIdentity();
223
-
224
-                // Check for blocks
225
-                if ($oauth->getIdentity()->getBlocked()) {
226
-                    // blocked!
227
-                    SessionAlert::error("You are currently blocked on-wiki. You will not be able to log in until you are unblocked.");
228
-                    $this->redirect('login');
229
-
230
-                    return;
231
-                }
232
-            }
233
-            catch (OAuthException $ex) {
234
-                // Oops. Refreshing ticket failed. Force a re-auth.
235
-                $authoriseUrl = $oauth->getRequestToken();
236
-                WebRequest::setOAuthPartialLogin($user);
237
-                $this->redirectUrl($authoriseUrl);
238
-
239
-                return;
240
-            }
241
-        }
242
-
243
-        if (($this->getSiteConfiguration()->getEnforceOAuth() && !$oauth->isFullyLinked())
244
-            || $oauth->isPartiallyLinked()
245
-        ) {
246
-            $authoriseUrl = $oauth->getRequestToken();
247
-            WebRequest::setOAuthPartialLogin($user);
248
-            $this->redirectUrl($authoriseUrl);
249
-
250
-            return;
251
-        }
252
-
253
-        WebRequest::setLoggedInUser($user);
254
-
255
-        $this->goBackWhenceYouCame($user);
256
-    }
257
-
258
-    protected abstract function getProviderCredentials();
259
-
260
-    /**
261
-     * @param User        $user
262
-     * @param int         $partialStage
263
-     * @param PdoDatabase $database
264
-     *
265
-     * @throws ApplicationLogicException
266
-     */
267
-    private function processJumpNextStage(User $user, $partialStage, PdoDatabase $database)
268
-    {
269
-        WebRequest::setAuthPartialLogin($user->getId(), $partialStage + 1);
270
-
271
-        $sql = 'SELECT type FROM credential WHERE user = :user AND factor = :stage AND disabled = 0 ORDER BY priority';
272
-        $statement = $database->prepare($sql);
273
-        $statement->execute(array(':user' => $user->getId(), ':stage' => $partialStage + 1));
274
-        $nextStage = $statement->fetchColumn();
275
-        $statement->closeCursor();
276
-
277
-        if (!isset($this->nextPageMap[$nextStage])) {
278
-            throw new ApplicationLogicException('Unknown page handler for next authentication stage.');
279
-        }
280
-
281
-        $this->redirect("login/" . $this->nextPageMap[$nextStage]);
282
-    }
283
-
284
-    private function setupAlternates(User $user, $partialStage, PdoDatabase $database)
285
-    {
286
-        // get the providers available
287
-        $sql = 'SELECT type FROM credential WHERE user = :user AND factor = :stage AND disabled = 0';
288
-        $statement = $database->prepare($sql);
289
-        $statement->execute(array(':user' => $user->getId(), ':stage' => $partialStage));
290
-        $alternates = $statement->fetchAll(PDO::FETCH_COLUMN);
291
-
292
-        $types = array();
293
-        foreach ($alternates as $item) {
294
-            $type = $this->nextPageMap[$item];
295
-            if (!isset($types[$type])) {
296
-                $types[$type] = array();
297
-            }
298
-
299
-            $types[$type][] = $item;
300
-        }
301
-
302
-        $userOptions = array();
303
-        if (get_called_class() === PageOtpLogin::class) {
304
-            $userOptions = $this->setupUserOptionsForType($types, 'u2f', $userOptions);
305
-        }
306
-
307
-        if (get_called_class() === PageU2FLogin::class) {
308
-            $userOptions = $this->setupUserOptionsForType($types, 'otp', $userOptions);
309
-        }
310
-
311
-        $this->assign('alternatives', $userOptions);
312
-    }
313
-
314
-    /**
315
-     * @param $types
316
-     * @param $type
317
-     * @param $userOptions
318
-     *
319
-     * @return mixed
320
-     */
321
-    private function setupUserOptionsForType($types, $type, $userOptions)
322
-    {
323
-        if (isset($types[$type])) {
324
-            $options = $types[$type];
325
-
326
-            array_walk($options, function(&$val) {
327
-                $val = $this->names[$val];
328
-            });
329
-
330
-            $userOptions[$type] = $options;
331
-        }
332
-
333
-        return $userOptions;
334
-    }
24
+	/** @var User */
25
+	protected $partialUser = null;
26
+	protected $nextPageMap = array(
27
+		'yubikeyotp' => 'otp',
28
+		'totp'       => 'otp',
29
+		'scratch'    => 'otp',
30
+		'u2f'        => 'u2f',
31
+	);
32
+	protected $names = array(
33
+		'yubikeyotp' => 'Yubikey OTP',
34
+		'totp'       => 'TOTP (phone code generator)',
35
+		'scratch'    => 'scratch token',
36
+		'u2f'        => 'U2F security token',
37
+	);
38
+
39
+	/**
40
+	 * Main function for this page, when no specific actions are called.
41
+	 * @return void
42
+	 */
43
+	protected function main()
44
+	{
45
+		if (!$this->enforceHttps()) {
46
+			return;
47
+		}
48
+
49
+		if (WebRequest::wasPosted()) {
50
+			$this->validateCSRFToken();
51
+
52
+			$database = $this->getDatabase();
53
+			try {
54
+				list($partialId, $partialStage) = WebRequest::getAuthPartialLogin();
55
+
56
+				if ($partialStage === null) {
57
+					$partialStage = 1;
58
+				}
59
+
60
+				if ($partialId === null) {
61
+					$username = WebRequest::postString('username');
62
+
63
+					if ($username === null || trim($username) === '') {
64
+						throw new ApplicationLogicException('No username specified.');
65
+					}
66
+
67
+					$user = User::getByUsername($username, $database);
68
+				}
69
+				else {
70
+					$user = User::getById($partialId, $database);
71
+				}
72
+
73
+				if ($user === false) {
74
+					throw new ApplicationLogicException("Authentication failed");
75
+				}
76
+
77
+				$authMan = new AuthenticationManager($database, $this->getSiteConfiguration(),
78
+					$this->getHttpHelper());
79
+
80
+				$credential = $this->getProviderCredentials();
81
+
82
+				$authResult = $authMan->authenticate($user, $credential, $partialStage);
83
+
84
+				if ($authResult === AuthenticationManager::AUTH_FAIL) {
85
+					throw new ApplicationLogicException("Authentication failed");
86
+				}
87
+
88
+				if ($authResult === AuthenticationManager::AUTH_REQUIRE_NEXT_STAGE) {
89
+					$this->processJumpNextStage($user, $partialStage, $database);
90
+
91
+					return;
92
+				}
93
+
94
+				if ($authResult === AuthenticationManager::AUTH_OK) {
95
+					$this->processLoginSuccess($user);
96
+
97
+					return;
98
+				}
99
+			}
100
+			catch (ApplicationLogicException $ex) {
101
+				WebRequest::clearAuthPartialLogin();
102
+
103
+				SessionAlert::error($ex->getMessage());
104
+				$this->redirect('login');
105
+
106
+				return;
107
+			}
108
+		}
109
+		else {
110
+			$this->assign('showSignIn', true);
111
+
112
+			$this->setupPartial();
113
+			$this->assignCSRFToken();
114
+			$this->providerSpecificSetup();
115
+		}
116
+	}
117
+
118
+	protected function isProtectedPage()
119
+	{
120
+		return false;
121
+	}
122
+
123
+	/**
124
+	 * Enforces HTTPS on the login form
125
+	 *
126
+	 * @return bool
127
+	 */
128
+	private function enforceHttps()
129
+	{
130
+		if ($this->getSiteConfiguration()->getUseStrictTransportSecurity() !== false) {
131
+			if (WebRequest::isHttps()) {
132
+				// Client can clearly use HTTPS, so let's enforce it for all connections.
133
+				$this->headerQueue[] = "Strict-Transport-Security: max-age=15768000";
134
+			}
135
+			else {
136
+				// This is the login form, not the request form. We need protection here.
137
+				$this->redirectUrl('https://' . WebRequest::serverName() . WebRequest::requestUri());
138
+
139
+				return false;
140
+			}
141
+		}
142
+
143
+		return true;
144
+	}
145
+
146
+	protected abstract function providerSpecificSetup();
147
+
148
+	protected function setupPartial()
149
+	{
150
+		$database = $this->getDatabase();
151
+
152
+		// default stuff
153
+		$this->assign('alternatives', array()); // 'u2f' => array('U2F token'), 'otp' => array('TOTP', 'scratch', 'yubiotp')));
154
+
155
+		// is this stage one?
156
+		list($partialId, $partialStage) = WebRequest::getAuthPartialLogin();
157
+		if ($partialStage === null || $partialId === null) {
158
+			WebRequest::clearAuthPartialLogin();
159
+		}
160
+
161
+		// Check to see if we have a partial login in progress
162
+		$username = null;
163
+		if ($partialId !== null) {
164
+			// Yes, enforce this username
165
+			$this->partialUser = User::getById($partialId, $database);
166
+			$username = $this->partialUser->getUsername();
167
+
168
+			$this->setupAlternates($this->partialUser, $partialStage, $database);
169
+		}
170
+		else {
171
+			// No, see if we've preloaded a username
172
+			$preloadUsername = WebRequest::getString('tplUsername');
173
+			if ($preloadUsername !== null) {
174
+				$username = $preloadUsername;
175
+			}
176
+		}
177
+
178
+		if ($partialStage === null) {
179
+			$partialStage = 1;
180
+		}
181
+
182
+		$this->assign('partialStage', $partialStage);
183
+		$this->assign('username', $username);
184
+	}
185
+
186
+	/**
187
+	 * Redirect the user back to wherever they came from after a successful login
188
+	 *
189
+	 * @param User $user
190
+	 */
191
+	protected function goBackWhenceYouCame(User $user)
192
+	{
193
+		// Redirect to wherever the user came from
194
+		$redirectDestination = WebRequest::clearPostLoginRedirect();
195
+		if ($redirectDestination !== null) {
196
+			$this->redirectUrl($redirectDestination);
197
+		}
198
+		else {
199
+			if ($user->isNewUser()) {
200
+				// home page isn't allowed, go to preferences instead
201
+				$this->redirect('preferences');
202
+			}
203
+			else {
204
+				// go to the home page
205
+				$this->redirect('');
206
+			}
207
+		}
208
+	}
209
+
210
+	private function processLoginSuccess(User $user)
211
+	{
212
+		// Touch force logout
213
+		$user->setForceLogout(false);
214
+		$user->save();
215
+
216
+		$oauth = new OAuthUserHelper($user, $this->getDatabase(), $this->getOAuthProtocolHelper(),
217
+			$this->getSiteConfiguration());
218
+
219
+		if ($oauth->isFullyLinked()) {
220
+			try {
221
+				// Reload the user's identity ticket.
222
+				$oauth->refreshIdentity();
223
+
224
+				// Check for blocks
225
+				if ($oauth->getIdentity()->getBlocked()) {
226
+					// blocked!
227
+					SessionAlert::error("You are currently blocked on-wiki. You will not be able to log in until you are unblocked.");
228
+					$this->redirect('login');
229
+
230
+					return;
231
+				}
232
+			}
233
+			catch (OAuthException $ex) {
234
+				// Oops. Refreshing ticket failed. Force a re-auth.
235
+				$authoriseUrl = $oauth->getRequestToken();
236
+				WebRequest::setOAuthPartialLogin($user);
237
+				$this->redirectUrl($authoriseUrl);
238
+
239
+				return;
240
+			}
241
+		}
242
+
243
+		if (($this->getSiteConfiguration()->getEnforceOAuth() && !$oauth->isFullyLinked())
244
+			|| $oauth->isPartiallyLinked()
245
+		) {
246
+			$authoriseUrl = $oauth->getRequestToken();
247
+			WebRequest::setOAuthPartialLogin($user);
248
+			$this->redirectUrl($authoriseUrl);
249
+
250
+			return;
251
+		}
252
+
253
+		WebRequest::setLoggedInUser($user);
254
+
255
+		$this->goBackWhenceYouCame($user);
256
+	}
257
+
258
+	protected abstract function getProviderCredentials();
259
+
260
+	/**
261
+	 * @param User        $user
262
+	 * @param int         $partialStage
263
+	 * @param PdoDatabase $database
264
+	 *
265
+	 * @throws ApplicationLogicException
266
+	 */
267
+	private function processJumpNextStage(User $user, $partialStage, PdoDatabase $database)
268
+	{
269
+		WebRequest::setAuthPartialLogin($user->getId(), $partialStage + 1);
270
+
271
+		$sql = 'SELECT type FROM credential WHERE user = :user AND factor = :stage AND disabled = 0 ORDER BY priority';
272
+		$statement = $database->prepare($sql);
273
+		$statement->execute(array(':user' => $user->getId(), ':stage' => $partialStage + 1));
274
+		$nextStage = $statement->fetchColumn();
275
+		$statement->closeCursor();
276
+
277
+		if (!isset($this->nextPageMap[$nextStage])) {
278
+			throw new ApplicationLogicException('Unknown page handler for next authentication stage.');
279
+		}
280
+
281
+		$this->redirect("login/" . $this->nextPageMap[$nextStage]);
282
+	}
283
+
284
+	private function setupAlternates(User $user, $partialStage, PdoDatabase $database)
285
+	{
286
+		// get the providers available
287
+		$sql = 'SELECT type FROM credential WHERE user = :user AND factor = :stage AND disabled = 0';
288
+		$statement = $database->prepare($sql);
289
+		$statement->execute(array(':user' => $user->getId(), ':stage' => $partialStage));
290
+		$alternates = $statement->fetchAll(PDO::FETCH_COLUMN);
291
+
292
+		$types = array();
293
+		foreach ($alternates as $item) {
294
+			$type = $this->nextPageMap[$item];
295
+			if (!isset($types[$type])) {
296
+				$types[$type] = array();
297
+			}
298
+
299
+			$types[$type][] = $item;
300
+		}
301
+
302
+		$userOptions = array();
303
+		if (get_called_class() === PageOtpLogin::class) {
304
+			$userOptions = $this->setupUserOptionsForType($types, 'u2f', $userOptions);
305
+		}
306
+
307
+		if (get_called_class() === PageU2FLogin::class) {
308
+			$userOptions = $this->setupUserOptionsForType($types, 'otp', $userOptions);
309
+		}
310
+
311
+		$this->assign('alternatives', $userOptions);
312
+	}
313
+
314
+	/**
315
+	 * @param $types
316
+	 * @param $type
317
+	 * @param $userOptions
318
+	 *
319
+	 * @return mixed
320
+	 */
321
+	private function setupUserOptionsForType($types, $type, $userOptions)
322
+	{
323
+		if (isset($types[$type])) {
324
+			$options = $types[$type];
325
+
326
+			array_walk($options, function(&$val) {
327
+				$val = $this->names[$val];
328
+			});
329
+
330
+			$userOptions[$type] = $options;
331
+		}
332
+
333
+		return $userOptions;
334
+	}
335 335
 }
Please login to merge, or discard this patch.
includes/Pages/UserAuth/Login/PageOtpLogin.php 1 patch
Indentation   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -13,18 +13,18 @@
 block discarded – undo
13 13
 
14 14
 class PageOtpLogin extends LoginCredentialPageBase
15 15
 {
16
-    protected function providerSpecificSetup()
17
-    {
18
-        $this->setTemplate('login/otp.tpl');
19
-    }
16
+	protected function providerSpecificSetup()
17
+	{
18
+		$this->setTemplate('login/otp.tpl');
19
+	}
20 20
 
21
-    protected function getProviderCredentials()
22
-    {
23
-        $otp = WebRequest::postString("otp");
24
-        if ($otp === null || $otp === "") {
25
-            throw new ApplicationLogicException("No one-time code specified");
26
-        }
21
+	protected function getProviderCredentials()
22
+	{
23
+		$otp = WebRequest::postString("otp");
24
+		if ($otp === null || $otp === "") {
25
+			throw new ApplicationLogicException("No one-time code specified");
26
+		}
27 27
 
28
-        return $otp;
29
-    }
28
+		return $otp;
29
+	}
30 30
 }
31 31
\ No newline at end of file
Please login to merge, or discard this patch.
includes/Pages/UserAuth/Login/PageU2FLogin.php 1 patch
Indentation   +22 added lines, -22 removed lines patch added patch discarded remove patch
@@ -14,20 +14,20 @@  discard block
 block discarded – undo
14 14
 
15 15
 class PageU2FLogin extends LoginCredentialPageBase
16 16
 {
17
-    protected function providerSpecificSetup()
18
-    {
19
-        $this->assign('showSignIn', false);
20
-        $this->setTemplate('login/u2f.tpl');
17
+	protected function providerSpecificSetup()
18
+	{
19
+		$this->assign('showSignIn', false);
20
+		$this->setTemplate('login/u2f.tpl');
21 21
 
22
-        if ($this->partialUser === null) {
23
-            throw new ApplicationLogicException("U2F cannot be first-stage authentication");
24
-        }
22
+		if ($this->partialUser === null) {
23
+			throw new ApplicationLogicException("U2F cannot be first-stage authentication");
24
+		}
25 25
 
26
-        $u2f = new U2FCredentialProvider($this->getDatabase(), $this->getSiteConfiguration());
27
-        $authData = json_encode($u2f->getAuthenticationData($this->partialUser));
26
+		$u2f = new U2FCredentialProvider($this->getDatabase(), $this->getSiteConfiguration());
27
+		$authData = json_encode($u2f->getAuthenticationData($this->partialUser));
28 28
 
29
-        $this->addJs('/vendor/yubico/u2flib-server/examples/assets/u2f-api.js');
30
-        $this->setTailScript($this->getCspManager()->getNonce(), <<<JS
29
+		$this->addJs('/vendor/yubico/u2flib-server/examples/assets/u2f-api.js');
30
+		$this->setTailScript($this->getCspManager()->getNonce(), <<<JS
31 31
 var request = {$authData};
32 32
 u2f.sign(request, function(data) {
33 33
     document.getElementById('authenticate').value=JSON.stringify(data);
@@ -35,19 +35,19 @@  discard block
 block discarded – undo
35 35
     document.getElementById('loginForm').submit();
36 36
 });
37 37
 JS
38
-        );
38
+		);
39 39
 
40
-    }
40
+	}
41 41
 
42
-    protected function getProviderCredentials()
43
-    {
44
-        $authenticate = WebRequest::postString("authenticate");
45
-        $request = WebRequest::postString("request");
42
+	protected function getProviderCredentials()
43
+	{
44
+		$authenticate = WebRequest::postString("authenticate");
45
+		$request = WebRequest::postString("request");
46 46
 
47
-        if ($authenticate === null || $authenticate === "" || $request === null || $request === "") {
48
-              throw new ApplicationLogicException("No authentication specified");
49
-        }
47
+		if ($authenticate === null || $authenticate === "" || $request === null || $request === "") {
48
+			  throw new ApplicationLogicException("No authentication specified");
49
+		}
50 50
 
51
-        return array(json_decode($authenticate), json_decode($request), 'u2f');
52
-    }
51
+		return array(json_decode($authenticate), json_decode($request), 'u2f');
52
+	}
53 53
 }
Please login to merge, or discard this patch.
includes/Pages/UserAuth/PageOAuthCallback.php 1 patch
Indentation   +77 added lines, -77 removed lines patch added patch discarded remove patch
@@ -18,92 +18,92 @@
 block discarded – undo
18 18
 
19 19
 class PageOAuthCallback extends InternalPageBase
20 20
 {
21
-    /**
22
-     * @return bool
23
-     */
24
-    protected function isProtectedPage()
25
-    {
26
-        // This page is critical to ensuring OAuth functionality is operational.
27
-        return false;
28
-    }
21
+	/**
22
+	 * @return bool
23
+	 */
24
+	protected function isProtectedPage()
25
+	{
26
+		// This page is critical to ensuring OAuth functionality is operational.
27
+		return false;
28
+	}
29 29
 
30
-    /**
31
-     * Main function for this page, when no specific actions are called.
32
-     * @return void
33
-     */
34
-    protected function main()
35
-    {
36
-        // This should never get hit except by URL manipulation.
37
-        $this->redirect('');
38
-    }
30
+	/**
31
+	 * Main function for this page, when no specific actions are called.
32
+	 * @return void
33
+	 */
34
+	protected function main()
35
+	{
36
+		// This should never get hit except by URL manipulation.
37
+		$this->redirect('');
38
+	}
39 39
 
40
-    /**
41
-     * Registered endpoint for the account creation callback.
42
-     *
43
-     * If this ever gets hit, something is wrong somewhere.
44
-     */
45
-    protected function create()
46
-    {
47
-        throw new Exception('OAuth account creation endpoint triggered.');
48
-    }
40
+	/**
41
+	 * Registered endpoint for the account creation callback.
42
+	 *
43
+	 * If this ever gets hit, something is wrong somewhere.
44
+	 */
45
+	protected function create()
46
+	{
47
+		throw new Exception('OAuth account creation endpoint triggered.');
48
+	}
49 49
 
50
-    /**
51
-     * Callback entry point
52
-     * @throws ApplicationLogicException
53
-     * @throws OptimisticLockFailedException
54
-     */
55
-    protected function authorise()
56
-    {
57
-        $oauthToken = WebRequest::getString('oauth_token');
58
-        $oauthVerifier = WebRequest::getString('oauth_verifier');
50
+	/**
51
+	 * Callback entry point
52
+	 * @throws ApplicationLogicException
53
+	 * @throws OptimisticLockFailedException
54
+	 */
55
+	protected function authorise()
56
+	{
57
+		$oauthToken = WebRequest::getString('oauth_token');
58
+		$oauthVerifier = WebRequest::getString('oauth_verifier');
59 59
 
60
-        $this->doCallbackValidation($oauthToken, $oauthVerifier);
60
+		$this->doCallbackValidation($oauthToken, $oauthVerifier);
61 61
 
62
-        $database = $this->getDatabase();
62
+		$database = $this->getDatabase();
63 63
 
64
-        $user = OAuthUserHelper::findUserByRequestToken($oauthToken, $database);
65
-        $oauth = new OAuthUserHelper($user, $database, $this->getOAuthProtocolHelper(), $this->getSiteConfiguration());
64
+		$user = OAuthUserHelper::findUserByRequestToken($oauthToken, $database);
65
+		$oauth = new OAuthUserHelper($user, $database, $this->getOAuthProtocolHelper(), $this->getSiteConfiguration());
66 66
 
67
-        try {
68
-            $oauth->completeHandshake($oauthVerifier);
69
-        }
70
-        catch (CurlException $ex) {
71
-            throw new ApplicationLogicException($ex->getMessage(), 0, $ex);
72
-        }
67
+		try {
68
+			$oauth->completeHandshake($oauthVerifier);
69
+		}
70
+		catch (CurlException $ex) {
71
+			throw new ApplicationLogicException($ex->getMessage(), 0, $ex);
72
+		}
73 73
 
74
-        // OK, we're the same session that just did a partial login that was redirected to OAuth. Let's upgrade the
75
-        // login to a full login
76
-        if (WebRequest::getOAuthPartialLogin() === $user->getId()) {
77
-            WebRequest::setLoggedInUser($user);
78
-        }
74
+		// OK, we're the same session that just did a partial login that was redirected to OAuth. Let's upgrade the
75
+		// login to a full login
76
+		if (WebRequest::getOAuthPartialLogin() === $user->getId()) {
77
+			WebRequest::setLoggedInUser($user);
78
+		}
79 79
 
80
-        // My thinking is there are three cases here:
81
-        //   a) new user => redirect to prefs - it's the only thing they can access other than stats
82
-        //   b) existing user hit the connect button in prefs => redirect to prefs since it's where they were
83
-        //   c) existing user logging in => redirect to wherever they came from
84
-        $redirectDestination = WebRequest::clearPostLoginRedirect();
85
-        if ($redirectDestination !== null && !$user->isNewUser()) {
86
-            $this->redirectUrl($redirectDestination);
87
-        }
88
-        else {
89
-            $this->redirect('preferences', null, null, 'internal.php');
90
-        }
91
-    }
80
+		// My thinking is there are three cases here:
81
+		//   a) new user => redirect to prefs - it's the only thing they can access other than stats
82
+		//   b) existing user hit the connect button in prefs => redirect to prefs since it's where they were
83
+		//   c) existing user logging in => redirect to wherever they came from
84
+		$redirectDestination = WebRequest::clearPostLoginRedirect();
85
+		if ($redirectDestination !== null && !$user->isNewUser()) {
86
+			$this->redirectUrl($redirectDestination);
87
+		}
88
+		else {
89
+			$this->redirect('preferences', null, null, 'internal.php');
90
+		}
91
+	}
92 92
 
93
-    /**
94
-     * @param string $oauthToken
95
-     * @param string $oauthVerifier
96
-     *
97
-     * @throws ApplicationLogicException
98
-     */
99
-    private function doCallbackValidation($oauthToken, $oauthVerifier)
100
-    {
101
-        if ($oauthToken === null) {
102
-            throw new ApplicationLogicException('No token provided');
103
-        }
93
+	/**
94
+	 * @param string $oauthToken
95
+	 * @param string $oauthVerifier
96
+	 *
97
+	 * @throws ApplicationLogicException
98
+	 */
99
+	private function doCallbackValidation($oauthToken, $oauthVerifier)
100
+	{
101
+		if ($oauthToken === null) {
102
+			throw new ApplicationLogicException('No token provided');
103
+		}
104 104
 
105
-        if ($oauthVerifier === null) {
106
-            throw new ApplicationLogicException('No oauth verifier provided.');
107
-        }
108
-    }
105
+		if ($oauthVerifier === null) {
106
+			throw new ApplicationLogicException('No oauth verifier provided.');
107
+		}
108
+	}
109 109
 }
110 110
\ No newline at end of file
Please login to merge, or discard this patch.
includes/Pages/UserAuth/PageChangePassword.php 1 patch
Indentation   +57 added lines, -57 removed lines patch added patch discarded remove patch
@@ -17,71 +17,71 @@
 block discarded – undo
17 17
 
18 18
 class PageChangePassword extends InternalPageBase
19 19
 {
20
-    /**
21
-     * Main function for this page, when no specific actions are called.
22
-     * @return void
23
-     */
24
-    protected function main()
25
-    {
26
-        $this->setHtmlTitle('Change Password');
20
+	/**
21
+	 * Main function for this page, when no specific actions are called.
22
+	 * @return void
23
+	 */
24
+	protected function main()
25
+	{
26
+		$this->setHtmlTitle('Change Password');
27 27
 
28
-        if (WebRequest::wasPosted()) {
29
-            $this->validateCSRFToken();
30
-            try {
31
-                $oldPassword = WebRequest::postString('oldpassword');
32
-                $newPassword = WebRequest::postString('newpassword');
33
-                $newPasswordConfirmation = WebRequest::postString('newpasswordconfirm');
28
+		if (WebRequest::wasPosted()) {
29
+			$this->validateCSRFToken();
30
+			try {
31
+				$oldPassword = WebRequest::postString('oldpassword');
32
+				$newPassword = WebRequest::postString('newpassword');
33
+				$newPasswordConfirmation = WebRequest::postString('newpasswordconfirm');
34 34
 
35
-                $user = User::getCurrent($this->getDatabase());
36
-                if (!$user instanceof User) {
37
-                    throw new ApplicationLogicException('User not found');
38
-                }
35
+				$user = User::getCurrent($this->getDatabase());
36
+				if (!$user instanceof User) {
37
+					throw new ApplicationLogicException('User not found');
38
+				}
39 39
 
40
-                $this->validateNewPassword($oldPassword, $newPassword, $newPasswordConfirmation, $user);
40
+				$this->validateNewPassword($oldPassword, $newPassword, $newPasswordConfirmation, $user);
41 41
 
42
-                $passwordProvider = new PasswordCredentialProvider($this->getDatabase(), $this->getSiteConfiguration());
43
-                $passwordProvider->setCredential($user, 1, $newPassword);
44
-            }
45
-            catch (ApplicationLogicException $ex) {
46
-                SessionAlert::error($ex->getMessage());
47
-                $this->redirect('changePassword');
42
+				$passwordProvider = new PasswordCredentialProvider($this->getDatabase(), $this->getSiteConfiguration());
43
+				$passwordProvider->setCredential($user, 1, $newPassword);
44
+			}
45
+			catch (ApplicationLogicException $ex) {
46
+				SessionAlert::error($ex->getMessage());
47
+				$this->redirect('changePassword');
48 48
 
49
-                return;
50
-            }
49
+				return;
50
+			}
51 51
 
52
-            SessionAlert::success('Password changed successfully!');
52
+			SessionAlert::success('Password changed successfully!');
53 53
 
54
-            $this->redirect('preferences');
55
-        }
56
-        else {
57
-            $this->assignCSRFToken();
58
-            $this->setTemplate('preferences/changePassword.tpl');
59
-            $this->addJs("/vendor/dropbox/zxcvbn/dist/zxcvbn.js");
60
-        }
61
-    }
54
+			$this->redirect('preferences');
55
+		}
56
+		else {
57
+			$this->assignCSRFToken();
58
+			$this->setTemplate('preferences/changePassword.tpl');
59
+			$this->addJs("/vendor/dropbox/zxcvbn/dist/zxcvbn.js");
60
+		}
61
+	}
62 62
 
63
-    /**
64
-     * @param string $oldPassword
65
-     * @param string $newPassword
66
-     * @param string $newPasswordConfirmation
67
-     * @param User   $user
68
-     *
69
-     * @throws ApplicationLogicException
70
-     */
71
-    protected function validateNewPassword($oldPassword, $newPassword, $newPasswordConfirmation, User $user)
72
-    {
73
-        if ($oldPassword === null || $newPassword === null || $newPasswordConfirmation === null) {
74
-            throw new ApplicationLogicException('All three fields must be completed to change your password');
75
-        }
63
+	/**
64
+	 * @param string $oldPassword
65
+	 * @param string $newPassword
66
+	 * @param string $newPasswordConfirmation
67
+	 * @param User   $user
68
+	 *
69
+	 * @throws ApplicationLogicException
70
+	 */
71
+	protected function validateNewPassword($oldPassword, $newPassword, $newPasswordConfirmation, User $user)
72
+	{
73
+		if ($oldPassword === null || $newPassword === null || $newPasswordConfirmation === null) {
74
+			throw new ApplicationLogicException('All three fields must be completed to change your password');
75
+		}
76 76
 
77
-        if ($newPassword !== $newPasswordConfirmation) {
78
-            throw new ApplicationLogicException('Your new passwords did not match!');
79
-        }
77
+		if ($newPassword !== $newPasswordConfirmation) {
78
+			throw new ApplicationLogicException('Your new passwords did not match!');
79
+		}
80 80
 
81
-        // TODO: adapt for MFA support
82
-        $passwordProvider = new PasswordCredentialProvider($this->getDatabase(), $this->getSiteConfiguration());
83
-        if (!$passwordProvider->authenticate($user, $oldPassword)) {
84
-            throw new ApplicationLogicException('The password you entered was incorrect.');
85
-        }
86
-    }
81
+		// TODO: adapt for MFA support
82
+		$passwordProvider = new PasswordCredentialProvider($this->getDatabase(), $this->getSiteConfiguration());
83
+		if (!$passwordProvider->authenticate($user, $oldPassword)) {
84
+			throw new ApplicationLogicException('The password you entered was incorrect.');
85
+		}
86
+	}
87 87
 }
Please login to merge, or discard this patch.
includes/Pages/UserAuth/PageForgotPassword.php 1 patch
Indentation   +205 added lines, -205 removed lines patch added patch discarded remove patch
@@ -22,209 +22,209 @@
 block discarded – undo
22 22
 
23 23
 class PageForgotPassword extends InternalPageBase
24 24
 {
25
-    /**
26
-     * Main function for this page, when no specific actions are called.
27
-     *
28
-     * This is the forgotten password reset form
29
-     * @category Security-Critical
30
-     */
31
-    protected function main()
32
-    {
33
-        if (WebRequest::wasPosted()) {
34
-            $this->validateCSRFToken();
35
-            $username = WebRequest::postString('username');
36
-            $email = WebRequest::postEmail('email');
37
-            $database = $this->getDatabase();
38
-
39
-            if ($username === null || trim($username) === "" || $email === null || trim($email) === "") {
40
-                throw new ApplicationLogicException("Both username and email address must be specified!");
41
-            }
42
-
43
-            $user = User::getByUsername($username, $database);
44
-            $this->sendResetMail($user, $email);
45
-
46
-            SessionAlert::success('<strong>Your password reset request has been completed.</strong> If the details you have provided match our records, you should receive an email shortly.');
47
-
48
-            $this->redirect('login');
49
-        }
50
-        else {
51
-            $this->assignCSRFToken();
52
-            $this->setTemplate('forgot-password/forgotpw.tpl');
53
-        }
54
-    }
55
-
56
-    /**
57
-     * Sends a reset email if the user is authenticated
58
-     *
59
-     * @param User|boolean $user  The user located from the database, or false. Doesn't really matter, since we do the
60
-     *                            check anyway within this method and silently skip if we don't have a user.
61
-     * @param string       $email The provided email address
62
-     */
63
-    private function sendResetMail($user, $email)
64
-    {
65
-        // If the user isn't found, or the email address is wrong, skip sending the details silently.
66
-        if (!$user instanceof User) {
67
-            return;
68
-        }
69
-
70
-        if (strtolower($user->getEmail()) === strtolower($email)) {
71
-            $clientIp = $this->getXffTrustProvider()
72
-                ->getTrustedClientIp(WebRequest::remoteAddress(), WebRequest::forwardedAddress());
73
-
74
-            $this->cleanExistingTokens($user);
75
-
76
-            $hash = Base32::encodeUpper(openssl_random_pseudo_bytes(30));
77
-
78
-            $encryptionHelper = new EncryptionHelper($this->getSiteConfiguration());
79
-
80
-            $cred = new Credential();
81
-            $cred->setDatabase($this->getDatabase());
82
-            $cred->setFactor(-1);
83
-            $cred->setUserId($user->getId());
84
-            $cred->setType('reset');
85
-            $cred->setData($encryptionHelper->encryptData($hash));
86
-            $cred->setVersion(0);
87
-            $cred->setDisabled(0);
88
-            $cred->setTimeout(new DateTimeImmutable('+ 1 hour'));
89
-            $cred->setPriority(9);
90
-            $cred->save();
91
-
92
-            $this->assign("user", $user);
93
-            $this->assign("hash", $hash);
94
-            $this->assign("remoteAddress", $clientIp);
95
-
96
-            $emailContent = $this->fetchTemplate('forgot-password/reset-mail.tpl');
97
-
98
-            $this->getEmailHelper()->sendMail($user->getEmail(), "WP:ACC password reset", $emailContent);
99
-        }
100
-    }
101
-
102
-    /**
103
-     * Entry point for the reset action
104
-     *
105
-     * This is the reset password part of the form.
106
-     * @category Security-Critical
107
-     */
108
-    protected function reset()
109
-    {
110
-        $si = WebRequest::getString('si');
111
-        $id = WebRequest::getString('id');
112
-
113
-        if ($si === null || trim($si) === "" || $id === null || trim($id) === "") {
114
-            throw new ApplicationLogicException("Link not valid, please ensure it has copied correctly");
115
-        }
116
-
117
-        $database = $this->getDatabase();
118
-        $user = $this->getResettingUser($id, $database, $si);
119
-
120
-        // Dual mode
121
-        if (WebRequest::wasPosted()) {
122
-            $this->validateCSRFToken();
123
-            try {
124
-                $this->doReset($user);
125
-                $this->cleanExistingTokens($user);
126
-            }
127
-            catch (ApplicationLogicException $ex) {
128
-                SessionAlert::error($ex->getMessage());
129
-                $this->redirect('forgotPassword', 'reset', array('si' => $si, 'id' => $id));
130
-
131
-                return;
132
-            }
133
-        }
134
-        else {
135
-            $this->assignCSRFToken();
136
-            $this->assign('user', $user);
137
-            $this->setTemplate('forgot-password/forgotpwreset.tpl');
138
-            $this->addJs("/vendor/dropbox/zxcvbn/dist/zxcvbn.js");
139
-        }
140
-    }
141
-
142
-    /**
143
-     * Gets the user resetting their password from the database, or throwing an exception if that is not possible.
144
-     *
145
-     * @param integer     $id       The ID of the user to retrieve
146
-     * @param PdoDatabase $database The database object to use
147
-     * @param string      $si       The reset hash provided
148
-     *
149
-     * @return User
150
-     * @throws ApplicationLogicException
151
-     */
152
-    private function getResettingUser($id, $database, $si)
153
-    {
154
-        $user = User::getById($id, $database);
155
-
156
-        if ($user === false ||  $user->isCommunityUser()) {
157
-            throw new ApplicationLogicException("Password reset failed. Please try again.");
158
-        }
159
-
160
-        $statement = $database->prepare("SELECT * FROM credential WHERE type = 'reset' AND user = :user;");
161
-        $statement->execute([':user' => $user->getId()]);
162
-
163
-        /** @var Credential $credential */
164
-        $credential = $statement->fetchObject(Credential::class);
165
-
166
-        $statement->closeCursor();
167
-
168
-        if ($credential === false) {
169
-            throw new ApplicationLogicException("Password reset failed. Please try again.");
170
-        }
171
-
172
-        $credential->setDatabase($database);
173
-
174
-        $encryptionHelper = new EncryptionHelper($this->getSiteConfiguration());
175
-        if ($encryptionHelper->decryptData($credential->getData()) != $si) {
176
-            throw new ApplicationLogicException("Password reset failed. Please try again.");
177
-        }
178
-
179
-        if ($credential->getTimeout() < new DateTimeImmutable()) {
180
-            $credential->delete();
181
-            throw new ApplicationLogicException("Password reset token expired. Please try again.");
182
-        }
183
-
184
-        return $user;
185
-    }
186
-
187
-    /**
188
-     * Performs the setting of the new password
189
-     *
190
-     * @param User $user The user to set the password for
191
-     *
192
-     * @throws ApplicationLogicException
193
-     */
194
-    private function doReset(User $user)
195
-    {
196
-        $pw = WebRequest::postString('pw');
197
-        $pw2 = WebRequest::postString('pw2');
198
-
199
-        if ($pw !== $pw2) {
200
-            throw new ApplicationLogicException('Passwords do not match!');
201
-        }
202
-
203
-        $passwordCredentialProvider = new PasswordCredentialProvider($user->getDatabase(), $this->getSiteConfiguration());
204
-        $passwordCredentialProvider->setCredential($user, 1, $pw);
205
-
206
-        SessionAlert::success('You may now log in!');
207
-        $this->redirect('login');
208
-    }
209
-
210
-    protected function isProtectedPage()
211
-    {
212
-        return false;
213
-    }
214
-
215
-    /**
216
-     * @param $user
217
-     */
218
-    private function cleanExistingTokens($user): void
219
-    {
220
-        // clean out existing reset tokens
221
-        $statement = $this->getDatabase()->prepare("SELECT * FROM credential WHERE type = 'reset' AND user = :user;");
222
-        $statement->execute([':user' => $user->getId()]);
223
-        $existing = $statement->fetchAll(PdoDatabase::FETCH_CLASS, Credential::class);
224
-
225
-        foreach ($existing as $c) {
226
-            $c->setDatabase($this->getDatabase());
227
-            $c->delete();
228
-        }
229
-    }
25
+	/**
26
+	 * Main function for this page, when no specific actions are called.
27
+	 *
28
+	 * This is the forgotten password reset form
29
+	 * @category Security-Critical
30
+	 */
31
+	protected function main()
32
+	{
33
+		if (WebRequest::wasPosted()) {
34
+			$this->validateCSRFToken();
35
+			$username = WebRequest::postString('username');
36
+			$email = WebRequest::postEmail('email');
37
+			$database = $this->getDatabase();
38
+
39
+			if ($username === null || trim($username) === "" || $email === null || trim($email) === "") {
40
+				throw new ApplicationLogicException("Both username and email address must be specified!");
41
+			}
42
+
43
+			$user = User::getByUsername($username, $database);
44
+			$this->sendResetMail($user, $email);
45
+
46
+			SessionAlert::success('<strong>Your password reset request has been completed.</strong> If the details you have provided match our records, you should receive an email shortly.');
47
+
48
+			$this->redirect('login');
49
+		}
50
+		else {
51
+			$this->assignCSRFToken();
52
+			$this->setTemplate('forgot-password/forgotpw.tpl');
53
+		}
54
+	}
55
+
56
+	/**
57
+	 * Sends a reset email if the user is authenticated
58
+	 *
59
+	 * @param User|boolean $user  The user located from the database, or false. Doesn't really matter, since we do the
60
+	 *                            check anyway within this method and silently skip if we don't have a user.
61
+	 * @param string       $email The provided email address
62
+	 */
63
+	private function sendResetMail($user, $email)
64
+	{
65
+		// If the user isn't found, or the email address is wrong, skip sending the details silently.
66
+		if (!$user instanceof User) {
67
+			return;
68
+		}
69
+
70
+		if (strtolower($user->getEmail()) === strtolower($email)) {
71
+			$clientIp = $this->getXffTrustProvider()
72
+				->getTrustedClientIp(WebRequest::remoteAddress(), WebRequest::forwardedAddress());
73
+
74
+			$this->cleanExistingTokens($user);
75
+
76
+			$hash = Base32::encodeUpper(openssl_random_pseudo_bytes(30));
77
+
78
+			$encryptionHelper = new EncryptionHelper($this->getSiteConfiguration());
79
+
80
+			$cred = new Credential();
81
+			$cred->setDatabase($this->getDatabase());
82
+			$cred->setFactor(-1);
83
+			$cred->setUserId($user->getId());
84
+			$cred->setType('reset');
85
+			$cred->setData($encryptionHelper->encryptData($hash));
86
+			$cred->setVersion(0);
87
+			$cred->setDisabled(0);
88
+			$cred->setTimeout(new DateTimeImmutable('+ 1 hour'));
89
+			$cred->setPriority(9);
90
+			$cred->save();
91
+
92
+			$this->assign("user", $user);
93
+			$this->assign("hash", $hash);
94
+			$this->assign("remoteAddress", $clientIp);
95
+
96
+			$emailContent = $this->fetchTemplate('forgot-password/reset-mail.tpl');
97
+
98
+			$this->getEmailHelper()->sendMail($user->getEmail(), "WP:ACC password reset", $emailContent);
99
+		}
100
+	}
101
+
102
+	/**
103
+	 * Entry point for the reset action
104
+	 *
105
+	 * This is the reset password part of the form.
106
+	 * @category Security-Critical
107
+	 */
108
+	protected function reset()
109
+	{
110
+		$si = WebRequest::getString('si');
111
+		$id = WebRequest::getString('id');
112
+
113
+		if ($si === null || trim($si) === "" || $id === null || trim($id) === "") {
114
+			throw new ApplicationLogicException("Link not valid, please ensure it has copied correctly");
115
+		}
116
+
117
+		$database = $this->getDatabase();
118
+		$user = $this->getResettingUser($id, $database, $si);
119
+
120
+		// Dual mode
121
+		if (WebRequest::wasPosted()) {
122
+			$this->validateCSRFToken();
123
+			try {
124
+				$this->doReset($user);
125
+				$this->cleanExistingTokens($user);
126
+			}
127
+			catch (ApplicationLogicException $ex) {
128
+				SessionAlert::error($ex->getMessage());
129
+				$this->redirect('forgotPassword', 'reset', array('si' => $si, 'id' => $id));
130
+
131
+				return;
132
+			}
133
+		}
134
+		else {
135
+			$this->assignCSRFToken();
136
+			$this->assign('user', $user);
137
+			$this->setTemplate('forgot-password/forgotpwreset.tpl');
138
+			$this->addJs("/vendor/dropbox/zxcvbn/dist/zxcvbn.js");
139
+		}
140
+	}
141
+
142
+	/**
143
+	 * Gets the user resetting their password from the database, or throwing an exception if that is not possible.
144
+	 *
145
+	 * @param integer     $id       The ID of the user to retrieve
146
+	 * @param PdoDatabase $database The database object to use
147
+	 * @param string      $si       The reset hash provided
148
+	 *
149
+	 * @return User
150
+	 * @throws ApplicationLogicException
151
+	 */
152
+	private function getResettingUser($id, $database, $si)
153
+	{
154
+		$user = User::getById($id, $database);
155
+
156
+		if ($user === false ||  $user->isCommunityUser()) {
157
+			throw new ApplicationLogicException("Password reset failed. Please try again.");
158
+		}
159
+
160
+		$statement = $database->prepare("SELECT * FROM credential WHERE type = 'reset' AND user = :user;");
161
+		$statement->execute([':user' => $user->getId()]);
162
+
163
+		/** @var Credential $credential */
164
+		$credential = $statement->fetchObject(Credential::class);
165
+
166
+		$statement->closeCursor();
167
+
168
+		if ($credential === false) {
169
+			throw new ApplicationLogicException("Password reset failed. Please try again.");
170
+		}
171
+
172
+		$credential->setDatabase($database);
173
+
174
+		$encryptionHelper = new EncryptionHelper($this->getSiteConfiguration());
175
+		if ($encryptionHelper->decryptData($credential->getData()) != $si) {
176
+			throw new ApplicationLogicException("Password reset failed. Please try again.");
177
+		}
178
+
179
+		if ($credential->getTimeout() < new DateTimeImmutable()) {
180
+			$credential->delete();
181
+			throw new ApplicationLogicException("Password reset token expired. Please try again.");
182
+		}
183
+
184
+		return $user;
185
+	}
186
+
187
+	/**
188
+	 * Performs the setting of the new password
189
+	 *
190
+	 * @param User $user The user to set the password for
191
+	 *
192
+	 * @throws ApplicationLogicException
193
+	 */
194
+	private function doReset(User $user)
195
+	{
196
+		$pw = WebRequest::postString('pw');
197
+		$pw2 = WebRequest::postString('pw2');
198
+
199
+		if ($pw !== $pw2) {
200
+			throw new ApplicationLogicException('Passwords do not match!');
201
+		}
202
+
203
+		$passwordCredentialProvider = new PasswordCredentialProvider($user->getDatabase(), $this->getSiteConfiguration());
204
+		$passwordCredentialProvider->setCredential($user, 1, $pw);
205
+
206
+		SessionAlert::success('You may now log in!');
207
+		$this->redirect('login');
208
+	}
209
+
210
+	protected function isProtectedPage()
211
+	{
212
+		return false;
213
+	}
214
+
215
+	/**
216
+	 * @param $user
217
+	 */
218
+	private function cleanExistingTokens($user): void
219
+	{
220
+		// clean out existing reset tokens
221
+		$statement = $this->getDatabase()->prepare("SELECT * FROM credential WHERE type = 'reset' AND user = :user;");
222
+		$statement->execute([':user' => $user->getId()]);
223
+		$existing = $statement->fetchAll(PdoDatabase::FETCH_CLASS, Credential::class);
224
+
225
+		foreach ($existing as $c) {
226
+			$c->setDatabase($this->getDatabase());
227
+			$c->delete();
228
+		}
229
+	}
230 230
 }
Please login to merge, or discard this patch.
includes/Pages/UserAuth/PageOAuth.php 1 patch
Indentation   +77 added lines, -77 removed lines patch added patch discarded remove patch
@@ -22,81 +22,81 @@
 block discarded – undo
22 22
 
23 23
 class PageOAuth extends InternalPageBase
24 24
 {
25
-    /**
26
-     * Attach entry point
27
-     *
28
-     * must be posted, or will redirect to preferences
29
-     */
30
-    protected function attach()
31
-    {
32
-        if (!WebRequest::wasPosted()) {
33
-            $this->redirect('preferences');
34
-
35
-            return;
36
-        }
37
-
38
-        $database = $this->getDatabase();
39
-
40
-        $this->validateCSRFToken();
41
-
42
-        $oauthProtocolHelper = $this->getOAuthProtocolHelper();
43
-        $user = User::getCurrent($database);
44
-        $oauth = new OAuthUserHelper($user, $database, $oauthProtocolHelper, $this->getSiteConfiguration());
45
-
46
-        try {
47
-            $authoriseUrl = $oauth->getRequestToken();
48
-            $this->redirectUrl($authoriseUrl);
49
-        }
50
-        catch (CurlException $ex) {
51
-            throw new ApplicationLogicException($ex->getMessage(), 0, $ex);
52
-        }
53
-    }
54
-
55
-    /**
56
-     * Detach account entry point
57
-     * @throws Exception
58
-     */
59
-    protected function detach()
60
-    {
61
-        if ($this->getSiteConfiguration()->getEnforceOAuth()) {
62
-            throw new AccessDeniedException($this->getSecurityManager());
63
-        }
64
-
65
-        $database = $this->getDatabase();
66
-        $user = User::getCurrent($database);
67
-        $oauth = new OAuthUserHelper($user, $database, $this->getOAuthProtocolHelper(), $this->getSiteConfiguration());
68
-
69
-        try {
70
-            $oauth->refreshIdentity();
71
-        }
72
-        catch (CurlException $ex) {
73
-            // do nothing. The user's already revoked this access anyway.
74
-        }
75
-        catch (OAuthException $ex) {
76
-            // do nothing. The user's already revoked this access anyway.
77
-        }
78
-        catch (OptimisticLockFailedException $e) {
79
-            // do nothing. The user's already revoked this access anyway.
80
-        }
81
-
82
-        $oauth->detach();
83
-
84
-        // TODO: figure out why we need to force logout after a detach.
85
-        $user->setForcelogout(true);
86
-        $user->save();
87
-
88
-        // force the user to log out
89
-        Session::destroy();
90
-
91
-        $this->redirect('login');
92
-    }
93
-
94
-    /**
95
-     * Main function for this page, when no specific actions are called.
96
-     * @return void
97
-     */
98
-    protected function main()
99
-    {
100
-        $this->redirect('preferences');
101
-    }
25
+	/**
26
+	 * Attach entry point
27
+	 *
28
+	 * must be posted, or will redirect to preferences
29
+	 */
30
+	protected function attach()
31
+	{
32
+		if (!WebRequest::wasPosted()) {
33
+			$this->redirect('preferences');
34
+
35
+			return;
36
+		}
37
+
38
+		$database = $this->getDatabase();
39
+
40
+		$this->validateCSRFToken();
41
+
42
+		$oauthProtocolHelper = $this->getOAuthProtocolHelper();
43
+		$user = User::getCurrent($database);
44
+		$oauth = new OAuthUserHelper($user, $database, $oauthProtocolHelper, $this->getSiteConfiguration());
45
+
46
+		try {
47
+			$authoriseUrl = $oauth->getRequestToken();
48
+			$this->redirectUrl($authoriseUrl);
49
+		}
50
+		catch (CurlException $ex) {
51
+			throw new ApplicationLogicException($ex->getMessage(), 0, $ex);
52
+		}
53
+	}
54
+
55
+	/**
56
+	 * Detach account entry point
57
+	 * @throws Exception
58
+	 */
59
+	protected function detach()
60
+	{
61
+		if ($this->getSiteConfiguration()->getEnforceOAuth()) {
62
+			throw new AccessDeniedException($this->getSecurityManager());
63
+		}
64
+
65
+		$database = $this->getDatabase();
66
+		$user = User::getCurrent($database);
67
+		$oauth = new OAuthUserHelper($user, $database, $this->getOAuthProtocolHelper(), $this->getSiteConfiguration());
68
+
69
+		try {
70
+			$oauth->refreshIdentity();
71
+		}
72
+		catch (CurlException $ex) {
73
+			// do nothing. The user's already revoked this access anyway.
74
+		}
75
+		catch (OAuthException $ex) {
76
+			// do nothing. The user's already revoked this access anyway.
77
+		}
78
+		catch (OptimisticLockFailedException $e) {
79
+			// do nothing. The user's already revoked this access anyway.
80
+		}
81
+
82
+		$oauth->detach();
83
+
84
+		// TODO: figure out why we need to force logout after a detach.
85
+		$user->setForcelogout(true);
86
+		$user->save();
87
+
88
+		// force the user to log out
89
+		Session::destroy();
90
+
91
+		$this->redirect('login');
92
+	}
93
+
94
+	/**
95
+	 * Main function for this page, when no specific actions are called.
96
+	 * @return void
97
+	 */
98
+	protected function main()
99
+	{
100
+		$this->redirect('preferences');
101
+	}
102 102
 }
Please login to merge, or discard this patch.