Completed
Pull Request — master (#31)
by Blizzz
13:09 queued 04:36
created

TwoFactorChallengeController::getLogoutAttribute()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
104
		}
105
106
		if ($this->session->exists('two_factor_auth_error')) {
107
			$this->session->remove('two_factor_auth_error');
108
			$error = true;
109
		} else {
110
			$error = false;
111
		}
112
		$tmpl = $provider->getTemplate($user);
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->userSession->getUser() on line 100 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...
113
		$tmpl->assign('redirect_url', $redirect_url);
114
		$data = [
115
			'error' => $error,
116
			'provider' => $provider,
117
			'logout_attribute' => $this->getLogoutAttribute(),
118
			'template' => $tmpl->fetchPage(),
119
		];
120
		return new TemplateResponse($this->appName, 'twofactorshowchallenge', $data, 'guest');
121
	}
122
123
	/**
124
	 * @NoAdminRequired
125
	 * @NoCSRFRequired
126
	 * @UseSession
127
	 *
128
	 * @param string $challengeProviderId
129
	 * @param string $challenge
130
	 * @param string $redirect_url
131
	 * @return RedirectResponse
132
	 */
133
	public function solveChallenge($challengeProviderId, $challenge, $redirect_url = null) {
134
		$user = $this->userSession->getUser();
135
		$provider = $this->twoFactorManager->getProvider($user, $challengeProviderId);
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->userSession->getUser() on line 134 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...
136
		if (is_null($provider)) {
137
			return new RedirectResponse($this->urlGenerator->linkToRoute('core.TwoFactorChallenge.selectChallenge'));
138
		}
139
140
		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 134 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...
141
			if (!is_null($redirect_url)) {
142
				return new RedirectResponse($this->urlGenerator->getAbsoluteURL(urldecode($redirect_url)));
143
			}
144
			return new RedirectResponse($this->urlGenerator->linkToRoute('files.view.index'));
145
		}
146
147
		$this->session->set('two_factor_auth_error', true);
148
		return new RedirectResponse($this->urlGenerator->linkToRoute('core.TwoFactorChallenge.showChallenge', [
149
			'challengeProviderId' => $provider->getId(),
150
			'redirect_url' => $redirect_url,
151
		]));
152
	}
153
154
}
155