Completed
Pull Request — master (#32)
by Blizzz
09:50
created

TwoFactorChallengeController   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 113
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 113
rs 10
wmc 9
lcom 1
cbo 9

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 1
A solveChallenge() 0 20 4
A selectChallenge() 0 10 1
A showChallenge() 0 22 3
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
	 * @NoAdminRequired
66
	 * @NoCSRFRequired
67
	 *
68
	 * @param string $redirect_url
69
	 * @return TemplateResponse
70
	 */
71
	public function selectChallenge($redirect_url) {
72
		$user = $this->userSession->getUser();
73
		$providers = $this->twoFactorManager->getProviders($user);
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->userSession->getUser() on line 72 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...
74
75
		$data = [
76
			'providers' => $providers,
77
			'redirect_url' => $redirect_url,
78
		];
79
		return new TemplateResponse($this->appName, 'twofactorselectchallenge', $data, 'guest');
80
	}
81
82
	/**
83
	 * @NoAdminRequired
84
	 * @NoCSRFRequired
85
	 * @UseSession
86
	 *
87
	 * @param string $challengeProviderId
88
	 * @param string $redirect_url
89
	 * @return TemplateResponse
90
	 */
91
	public function showChallenge($challengeProviderId, $redirect_url) {
92
		$user = $this->userSession->getUser();
93
		$provider = $this->twoFactorManager->getProvider($user, $challengeProviderId);
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->userSession->getUser() on line 92 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...
94
		if (is_null($provider)) {
95
			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...
96
		}
97
98
		if ($this->session->exists('two_factor_auth_error')) {
99
			$this->session->remove('two_factor_auth_error');
100
			$error = true;
101
		} else {
102
			$error = false;
103
		}
104
		$tmpl = $provider->getTemplate($user);
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->userSession->getUser() on line 92 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...
105
		$tmpl->assign('redirect_url', $redirect_url);
106
		$data = [
107
			'error' => $error,
108
			'provider' => $provider,
109
			'template' => $tmpl->fetchPage(),
110
		];
111
		return new TemplateResponse($this->appName, 'twofactorshowchallenge', $data, 'guest');
112
	}
113
114
	/**
115
	 * @NoAdminRequired
116
	 * @NoCSRFRequired
117
	 * @UseSession
118
	 *
119
	 * @param string $challengeProviderId
120
	 * @param string $challenge
121
	 * @param string $redirect_url
122
	 * @return RedirectResponse
123
	 */
124
	public function solveChallenge($challengeProviderId, $challenge, $redirect_url = null) {
125
		$user = $this->userSession->getUser();
126
		$provider = $this->twoFactorManager->getProvider($user, $challengeProviderId);
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->userSession->getUser() on line 125 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...
127
		if (is_null($provider)) {
128
			return new RedirectResponse($this->urlGenerator->linkToRoute('core.TwoFactorChallenge.selectChallenge'));
129
		}
130
131
		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 125 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...
132
			if (!is_null($redirect_url)) {
133
				return new RedirectResponse($this->urlGenerator->getAbsoluteURL(urldecode($redirect_url)));
134
			}
135
			return new RedirectResponse($this->urlGenerator->linkToRoute('files.view.index'));
136
		}
137
138
		$this->session->set('two_factor_auth_error', true);
139
		return new RedirectResponse($this->urlGenerator->linkToRoute('core.TwoFactorChallenge.showChallenge', [
140
			'challengeProviderId' => $provider->getId(),
141
			'redirect_url' => $redirect_url,
142
		]));
143
	}
144
145
}
146