Completed
Pull Request — master (#32767)
by Sujith
74:52 queued 26:28
created

CreateUser::isAdmin()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 0
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Sujith Haridasan <[email protected]>
4
 *
5
 * @copyright Copyright (c) 2018, ownCloud GmbH
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\User\Service;
23
24
use OCP\IGroupManager;
25
use OCP\ILogger;
26
use OCP\IUserManager;
27
use OCP\IUserSession;
28
use OCP\Mail\IMailer;
29
use OCP\Security\ISecureRandom;
30
use OCP\User\Exceptions\CannotCreateUserException;
31
use OCP\User\Exceptions\InvalidEmailException;
32
use OCP\User\Exceptions\UserAlreadyExistsException;
33
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
34
use Symfony\Component\EventDispatcher\GenericEvent;
35
36
class CreateUser {
37
	/** @var IUserSession  */
38
	private $userSession;
39
	/** @var IGroupManager  */
40
	private $groupManager;
41
	/** @var IUserManager  */
42
	private $userManager;
43
	/** @var IMailer  */
44
	private $mailer;
45
	/** @var ISecureRandom  */
46
	private $secureRandom;
47
	/** @var EventDispatcherInterface  */
48
	private $eventDispatcher;
49
	/** @var ILogger  */
50
	private $logger;
51
	/** @var UserSendMail  */
52
	private $userSendMail;
53
54
	/**
55
	 * CreateUser constructor.
56
	 *
57
	 * @param IUserSession $userSession
58
	 * @param IGroupManager $groupManager
59
	 * @param IUserManager $userManager
60
	 * @param IMailer $mailer
61
	 * @param ISecureRandom $secureRandom
62
	 * @param EventDispatcherInterface $eventDispatcher
63
	 * @param ILogger $logger
64
	 * @param UserSendMail $userSendMail
65
	 */
66
	public function __construct(IUserSession $userSession,
67
								IGroupManager $groupManager,
68
								IUserManager $userManager,
69
								IMailer $mailer,
70
								ISecureRandom $secureRandom,
71
								EventDispatcherInterface $eventDispatcher,
72
								ILogger $logger, UserSendMail $userSendMail) {
73
		$this->userSession = $userSession;
74
		$this->groupManager = $groupManager;
75
		$this->userManager = $userManager;
76
		$this->mailer = $mailer;
77
		$this->secureRandom = $secureRandom;
78
		$this->eventDispatcher = $eventDispatcher;
79
		$this->logger = $logger;
80
		$this->userSendMail = $userSendMail;
81
	}
82
83
	/**
84
	 * @param $username
85
	 * @param $password
86
	 * @param array $groups
87
	 * @param string $email
88
	 * @return bool|\OCP\IUser
89
	 * @throws CannotCreateUserException
90
	 * @throws InvalidEmailException
91
	 * @throws UserAlreadyExistsException
92
	 */
93
	public function createUser($username, $password, array $groups= [], $email='') {
94
		if ($email !== '' && !$this->mailer->validateMailAddress($email)) {
95
			throw new InvalidEmailException("Invalid mail address");
96
		}
97
98
		$currentUser = $this->userSession->getUser();
99
100
		if (!$this->isAdmin()) {
101
			if (!empty($groups)) {
102
				foreach ($groups as $key => $group) {
103
					$groupObject = $this->groupManager->get($group);
104
					if ($groupObject === null) {
105
						unset($groups[$key]);
106
						continue;
107
					}
108
109
					if (!$this->groupManager->getSubAdmin()->isSubAdminofGroup($currentUser, $groupObject)) {
0 ignored issues
show
Bug introduced by
It seems like $currentUser defined by $this->userSession->getUser() on line 98 can be null; however, OCP\ISubAdminManager::isSubAdminofGroup() 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...
110
						unset($groups[$key]);
111
					}
112
				}
113
			}
114
115
			if (empty($groups)) {
116
				$groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($currentUser);
0 ignored issues
show
Bug introduced by
It seems like $currentUser defined by $this->userSession->getUser() on line 98 can be null; however, OCP\ISubAdminManager::getSubAdminsGroups() 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...
117
				// New class returns IGroup[] so convert back
118
				$gids = [];
119
				foreach ($groups as $group) {
120
					$gids[] = $group->getGID();
121
				}
122
				$groups = $gids;
123
			}
124
		}
125
126
		if ($this->userManager->userExists($username)) {
127
			throw new UserAlreadyExistsException('A user with that name already exists.');
128
		}
129
130
		try {
131
			if (($password === '') && ($email !== '')) {
132
				/**
133
				 * Generate a random password as we are going to have this
134
				 * use one time. The new user has to reset it using the link
135
				 * from email.
136
				 */
137
				$event = new GenericEvent();
138
				$this->eventDispatcher->dispatch('OCP\User::createPassword', $event);
139
				if ($event->hasArgument('password')) {
140
					$password = $event->getArgument('password');
141
				} else {
142
					$password = $this->secureRandom->generate(20);
143
				}
144
			}
145
			$user = $this->userManager->createUser($username, $password);
146
		} catch (\Exception $exception) {
147
			$message = $exception->getMessage();
148
			if (!$message) {
149
				$message = 'Unable to create user.';
150
			}
151
			throw new CannotCreateUserException($message);
152
		}
153
154
		if ($user === null) {
155
			throw new CannotCreateUserException('Unable to create user.');
156
		}
157
158
		if ($groups !== null) {
159
			foreach ($groups as $groupName) {
160
				if ($groupName !== null) {
161
					$group = $this->groupManager->get($groupName);
162
163
					if (empty($group)) {
164
						$group = $this->groupManager->createGroup($groupName);
165
					}
166
					$group->addUser($user);
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->userManager->crea...r($username, $password) on line 145 can also be of type boolean; however, OCP\IGroup::addUser() does only seem to accept object<OCP\IUser>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
167
					$this->logger->info('Added userid ' . $user->getUID() . ' to group ' . $group->getGID());
168
				}
169
			}
170
		}
171
		/**
172
		 * Send new user mail only if a mail is set
173
		 */
174
		if ($email !== '') {
175
			$user->setEMailAddress($email);
176
			try {
177
				$this->userSendMail->generateTokenAndSendMail($username, $email);
178
			} catch (\Exception $e) {
179
				$this->logger->error("Can't send new user mail to $email: " . $e->getMessage(), ['app' => 'settings']);
180
			}
181
		}
182
183
		return $user;
184
	}
185
186
	private function isAdmin() {
187
		// Check if current user (active and not in incognito mode)
188
		// is an admin
189
		$activeUser = $this->userSession->getUser();
190
		if ($activeUser !== null) {
191
			return $this->groupManager->isAdmin($activeUser->getUID());
192
		}
193
		// Check if it is triggered from command line
194
		$cli = $this->triggeredFromCommandLine();
195
		if ($cli === true) {
196
			return true;
197
		}
198
		return false;
199
	}
200
201
	/**
202
	 * Check if action is triggered from command line
203
	 * @return bool
204
	 */
205
	private function triggeredFromCommandLine() {
206
		return \in_array(\php_sapi_name(), ['cli']);
207
	}
208
}
209