Completed
Push — master ( e3be9e...9444a3 )
by Morris
73:40 queued 52:27
created

TwoFactorChallengeController::getLogoutUrl()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Christoph Wurst <[email protected]>
6
 * @author Cornelius Kölbel <[email protected]>
7
 * @author Joas Schilling <[email protected]>
8
 * @author Lukas Reschke <[email protected]>
9
 * @author Roeland Jago Douma <[email protected]>
10
 *
11
 * @license AGPL-3.0
12
 *
13
 * This code is free software: you can redistribute it and/or modify
14
 * it under the terms of the GNU Affero General Public License, version 3,
15
 * as published by the Free Software Foundation.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
 * GNU Affero General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License, version 3,
23
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
24
 *
25
 */
26
27
namespace OC\Core\Controller;
28
29
use OC\Authentication\TwoFactorAuth\Manager;
30
use OC_User;
31
use OC_Util;
32
use OCP\AppFramework\Controller;
33
use OCP\AppFramework\Http\RedirectResponse;
34
use OCP\AppFramework\Http\TemplateResponse;
35
use OCP\Authentication\TwoFactorAuth\IProvider;
36
use OCP\Authentication\TwoFactorAuth\IProvidesCustomCSP;
37
use OCP\Authentication\TwoFactorAuth\TwoFactorException;
38
use OCP\IRequest;
39
use OCP\ISession;
40
use OCP\IURLGenerator;
41
use OCP\IUserSession;
42
43
class TwoFactorChallengeController extends Controller {
44
45
	/** @var Manager */
46
	private $twoFactorManager;
47
48
	/** @var IUserSession */
49
	private $userSession;
50
51
	/** @var ISession */
52
	private $session;
53
54
	/** @var IURLGenerator */
55
	private $urlGenerator;
56
57
	/**
58
	 * @param string $appName
59
	 * @param IRequest $request
60
	 * @param Manager $twoFactorManager
61
	 * @param IUserSession $userSession
62
	 * @param ISession $session
63
	 * @param IURLGenerator $urlGenerator
64
	 */
65
	public function __construct($appName, IRequest $request, Manager $twoFactorManager, IUserSession $userSession,
66
		ISession $session, IURLGenerator $urlGenerator) {
67
		parent::__construct($appName, $request);
68
		$this->twoFactorManager = $twoFactorManager;
69
		$this->userSession = $userSession;
70
		$this->session = $session;
71
		$this->urlGenerator = $urlGenerator;
72
	}
73
74
	/**
75
	 * @return string
76
	 */
77
	protected function getLogoutUrl() {
78
		return OC_User::getLogoutUrl($this->urlGenerator);
79
	}
80
	
81
	/**
82
	 * @param IProvider[] $providers
83
	 */
84
	private function splitProvidersAndBackupCodes(array $providers): array {
85
		$regular = [];
86
		$backup = null;
87
		foreach ($providers as $provider) {
88
			if ($provider->getId() === 'backup_codes') {
89
				$backup = $provider;
90
			} else {
91
				$regular[] = $provider;
92
			}
93
		}
94
95
		return [$regular, $backup];
96
	}
97
98
	/**
99
	 * @NoAdminRequired
100
	 * @NoCSRFRequired
101
	 *
102
	 * @param string $redirect_url
103
	 * @return TemplateResponse
104
	 */
105
	public function selectChallenge($redirect_url) {
106
		$user = $this->userSession->getUser();
107
		$providerSet = $this->twoFactorManager->getProviderSet($user);
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->userSession->getUser() on line 106 can be null; however, OC\Authentication\TwoFac...nager::getProviderSet() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
108
		$allProviders = $providerSet->getProviders();
109
		list($providers, $backupProvider) = $this->splitProvidersAndBackupCodes($allProviders);
110
111
		$data = [
112
			'providers' => $providers,
113
			'backupProvider' => $backupProvider,
114
			'providerMissing' => $providerSet->isProviderMissing(),
115
			'redirect_url' => $redirect_url,
116
			'logout_url' => $this->getLogoutUrl(),
117
		];
118
		return new TemplateResponse($this->appName, 'twofactorselectchallenge', $data, 'guest');
119
	}
120
121
	/**
122
	 * @NoAdminRequired
123
	 * @NoCSRFRequired
124
	 * @UseSession
125
	 *
126
	 * @param string $challengeProviderId
127
	 * @param string $redirect_url
128
	 * @return TemplateResponse|RedirectResponse
129
	 */
130
	public function showChallenge($challengeProviderId, $redirect_url) {
131
		$user = $this->userSession->getUser();
132
		$providerSet = $this->twoFactorManager->getProviderSet($user);
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->userSession->getUser() on line 131 can be null; however, OC\Authentication\TwoFac...nager::getProviderSet() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
133
		$provider = $providerSet->getProvider($challengeProviderId);
134
		if (is_null($provider)) {
135
			return new RedirectResponse($this->urlGenerator->linkToRoute('core.TwoFactorChallenge.selectChallenge'));
136
		}
137
138
		$backupProvider = $providerSet->getProvider('backup_codes');
139
		if (!is_null($backupProvider) && $backupProvider->getId() === $provider->getId()) {
140
			// Don't show the backup provider link if we're already showing that provider's challenge
141
			$backupProvider = null;
142
		}
143
144
		$errorMessage = '';
145
		$error = false;
146
		if ($this->session->exists('two_factor_auth_error')) {
147
			$this->session->remove('two_factor_auth_error');
148
			$error = true;
149
			$errorMessage = $this->session->get("two_factor_auth_error_message");
150
			$this->session->remove('two_factor_auth_error_message');
151
		}
152
		$tmpl = $provider->getTemplate($user);
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->userSession->getUser() on line 131 can be null; however, OCP\Authentication\TwoFa...Provider::getTemplate() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
153
		$tmpl->assign('redirect_url', $redirect_url);
154
		$data = [
155
			'error' => $error,
156
			'error_message' => $errorMessage,
157
			'provider' => $provider,
158
			'backupProvider' => $backupProvider,
159
			'logout_url' => $this->getLogoutUrl(),
160
			'redirect_url' => $redirect_url,
161
			'template' => $tmpl->fetchPage(),
162
		];
163
		$response = new TemplateResponse($this->appName, 'twofactorshowchallenge', $data, 'guest');
164
		if ($provider instanceof IProvidesCustomCSP) {
165
			$response->setContentSecurityPolicy($provider->getCSP());
166
		}
167
		return $response;
168
	}
169
170
	/**
171
	 * @NoAdminRequired
172
	 * @NoCSRFRequired
173
	 * @UseSession
174
	 *
175
	 * @UserRateThrottle(limit=5, period=100)
176
	 *
177
	 * @param string $challengeProviderId
178
	 * @param string $challenge
179
	 * @param string $redirect_url
180
	 * @return RedirectResponse
181
	 */
182
	public function solveChallenge($challengeProviderId, $challenge, $redirect_url = null) {
183
		$user = $this->userSession->getUser();
184
		$provider = $this->twoFactorManager->getProvider($user, $challengeProviderId);
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->userSession->getUser() on line 183 can be null; however, OC\Authentication\TwoFac...\Manager::getProvider() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
185
		if (is_null($provider)) {
186
			return new RedirectResponse($this->urlGenerator->linkToRoute('core.TwoFactorChallenge.selectChallenge'));
187
		}
188
189
		try {
190
			if ($this->twoFactorManager->verifyChallenge($challengeProviderId, $user, $challenge)) {
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->userSession->getUser() on line 183 can be null; however, OC\Authentication\TwoFac...ager::verifyChallenge() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
191
				if (!is_null($redirect_url)) {
192
					return new RedirectResponse($this->urlGenerator->getAbsoluteURL(urldecode($redirect_url)));
193
				}
194
				return new RedirectResponse(OC_Util::getDefaultPageUrl());
195
			}
196
		} catch (TwoFactorException $e) {
197
			/*
198
			 * The 2FA App threw an TwoFactorException. Now we display more
199
			 * information to the user. The exception text is stored in the
200
			 * session to be used in showChallenge()
201
			 */
202
			$this->session->set('two_factor_auth_error_message', $e->getMessage());
203
		}
204
205
		$this->session->set('two_factor_auth_error', true);
206
		return new RedirectResponse($this->urlGenerator->linkToRoute('core.TwoFactorChallenge.showChallenge', [
207
			'challengeProviderId' => $provider->getId(),
208
			'redirect_url' => $redirect_url,
209
		]));
210
	}
211
212
}
213