Completed
Pull Request — develop (#51)
by Patrick
02:37
created

UsersAPI::validateCanCreateUser()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 10
nc 3
nop 3
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
1
<?php
2
class UsersAPI extends ProfilesAdminAPI
3
{
4
    public function setup($app)
5
    {
6
        $app->get('[/]', array($this, 'listUsers'));
7
        $app->post('[/]', array($this, 'createUser'));
8
        $app->get('/{uid}[/]', array($this, 'showUser'));
9
        $app->patch('/{uid}[/]', array($this, 'editUser'));
10
        $app->delete('/{uid}[/]', array($this, 'deleteUser'));
11
        $app->get('/{uid}/groups[/]', array($this, 'listGroupsForUser'));
12
        $app->post('/{uid}/Actions/link[/]', array($this, 'linkUser'));
13
        $app->post('/{uid}/Actions/reset_pass[/]', array($this, 'resetUserPassword'));
14
        $app->post('/Actions/check_email_available[/]', array($this, 'checkEmailAvailable'));
15
        $app->post('/Actions/check_uid_available[/]', array($this, 'checkUidAvailable'));
16
        $app->post('/Actions/remind_uid[/]', array($this, 'remindUid'));
17
    }
18
19
    public function listUsers($request, $response)
20
    {
21
        $odata = $request->getAttribute('odata', new \ODataParams(array()));
22
        if($this->validateIsAdmin($request, true) === false)
23
        {
24
            $users = array($this->user);
25
            $users = $odata->filterArrayPerSelect($users);
26
        }
27
        else
28
        {
29
            $auth = AuthProvider::getInstance();
30
            $users = $auth->getUsersByFilter($odata->filter, $odata->select, $odata->top, $odata->skip, 
31
                                             $odata->orderby);
32
        }
33
        return $response->withJson($users);
34
    }
35
36
    protected function validateCanCreateUser($proposedUser, $auth, &$message)
37
    {
38
        $user = $auth->getUsersByFilter(new \Data\Filter('mail eq '.$proposedUser->mail));
39
        if(!empty($user))
40
        {
41
            $message = 'Email already exists!';
42
            return false;
43
        }
44
        $user = $auth->getUsersByFilter(new \Data\Filter('uid eq '.$proposedUser->uid));
45
        if(!empty($user))
46
        {
47
            $message = 'Username already exists!';
48
            return false;
49
        }
50
        return true;
51
    }
52
53
    protected function validEmail($email)
54
    {
55
        if(filter_var($email) === false)
56
        {
57
            return false;
58
        }
59
        $pos = strpos($email, '@');
60
        if($pos === false)
61
        {
62
            return false;
63
        }
64
        $domain = substr($email, $pos + 1);
65
        if(checkdnsrr($domain, 'MX') === false)
66
        {
67
            return false;
68
        }
69
        return true;
70
    }
71
72
    protected function getFailArray($message)
73
    {
74
        return array('res'=>false, 'message'=>$message);
75
    }
76
77
    public function createUser($request, $response)
78
    {
79
        $this->user = $request->getAttribute('user');
80
        //This one is different. If they are logged in fail...
81
        if($this->user !== false)
82
        {
83
            return $response->withStatus(404);
84
        }
85
        $obj = $request->getParsedBody();
86
        if(!isset($obj->captcha))
87
        {
88
            return $response->withStatus(401);
89
        }
90
        $captcha = FlipSession::getVar('captcha');
91
        if($captcha === false)
92
        {
93
            return $response->withStatus(401);
94
        }
95
        if(!$captcha->is_answer_right($obj->captcha))
96
        {
97
            return $response->withJson($this->getFailArray('Incorrect answer to CAPTCHA!'), 412);
98
        }
99
        $auth = AuthProvider::getInstance();
100
        $message = false;
101
        if($this->validateCanCreateUser($obj, $auth, $message) === false)
102
        {
103
            return $response->withJson($this->getFailArray($message), 412);
104
        }
105
        else if($this->validEmail($obj->mail) === false)
106
        {
107
            return $response->withJson($this->getFailArray('Invalid Email Address!'));
108
        }
109
        $ret = $auth->createPendingUser($obj);
110
        if($ret == false)
111
        {
112
            return $response->withJson($this->getFailArray('Failed to save user registration!'), 500);
113
        }
114
        return $response->withJson($ret);
115
    }
116
117
    protected function userIsMe($request, $uid)
118
    {
119
        $this->user = $request->getAttribute('user');
120
        return ($uid === 'me' || ($this->user !== false && $uid === $this->user->uid));
121
    }
122
123
    protected function hasLeadAccess()
124
    {
125
        return ($this->user->isInGroupNamed('Leads') || $this->user->isInGroupNamed('CC') || $this->user->isInGroupNamed('AFs'));
126
    }
127
128 View Code Duplication
    protected function getUserByUIDReadOnly($request, $uid)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
129
    {
130
        if($this->userIsMe($request, $uid))
131
        {
132
            return $this->user;
133
        }
134
        if($this->user->isInGroupNamed('LDAPAdmins') || $this->hasLeadAccess())
135
        {
136
            $auth = \AuthProvider::getInstance();
137
            $filter = new \Data\Filter("uid eq $uid");
138
            $users = $auth->getUsersByFilter($filter);
139
            if(!empty($users))
140
            {
141
                return $users[0];
142
            }
143
        }
144
        return false;
145
    }
146
147 View Code Duplication
    protected function getUserByUID($request, $uid)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
148
    {
149
        if($this->userIsMe($request, $uid))
150
        {
151
            return $this->user;
152
        }
153
        if($this->user->isInGroupNamed('LDAPAdmins'))
154
        {
155
            $auth = \AuthProvider::getInstance();
156
            $filter = new \Data\Filter("uid eq $uid");
157
            $users = $auth->getUsersByFilter($filter);
158
            if(!empty($users))
159
            {
160
                return $users[0];
161
            }
162
        }
163
        return false;
164
    }
165
166
    public function showUser($request, $response, $args)
167
    {
168
        $uid = $args['uid'];
169
        $user = $request->getAttribute('user');
170
        if($user === false)
171
        {
172
            if($_SERVER['SERVER_ADDR'] === $_SERVER['REMOTE_ADDR'])
173
            {
174
                $user = \AuthProvider::getInstance()->getUsersByFilter(new \Data\Filter("uid eq $uid"));
175
                if(empty($user))
176
                {
177
                    return $response->withStatus(404);
178
                }
179
                return $response->withJson($user[0]);
180
            } 
181
            return $response->withStatus(401);
182
        }
183
        $user = $this->getUserByUIDReadOnly($request, $uid);
184
        if($user === false)
185
        {
186
            return $response->withStatus(404);
187
        }
188
        if(!is_object($user) && isset($user[0]))
189
        {
190
            $user = $user[0];
191
        }
192
        if($request->getAttribute('format') === 'vcard')
193
        {
194
            $response = $response->withHeader('Content-Type', 'text/x-vCard');
195
            $response->getBody()->write($user->getVcard());
196
            return $response;
197
        }
198
        return $response->withJson($user);
199
    }
200
201
    protected function sendPasswordResetEmail($user)
202
    {
203
        $forwardedFor = false;
204
        if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
205
        {
206
            $forwardedFor = $_SERVER['HTTP_X_FORWARDED_FOR'];
207
        }
208
        $emailMsg = new PasswordHasBeenResetEmail($user, $_SERVER['REMOTE_ADDR'], $forwardedFor);
209
        $emailProvider = EmailProvider::getInstance();
210
        if($emailProvider->sendEmail($emailMsg) === false)
211
        {
212
            throw new \Exception('Unable to send password reset email!');
213
        }
214
    }
215
216
    protected function exceptionCodeToHttpCode($e)
217
    {
218
        if($e->getCode() === 3)
219
        {
220
            return 401;
221
        }
222
        return 500;
223
    }
224
225
    protected function getUser($request, $uid, $payload)
226
    {
227
        $this->user = $request->getAttribute('user');
228
        if($this->user === false)
229
        {
230
            if(isset($payload->hash))
231
            {
232
                $auth = AuthProvider::getInstance();
233
                $this->user = $auth->getUserByResetHash($payload->hash);
234
                return $this->user;
235
            }
236
            return false;
237
        }
238
        return $this->getUserByUID($request, $uid);
239
    }
240
241
    public function editUser($request, $response, $args)
242
    {
243
        $uid = 'me';
244
        if(isset($args['uid']))
245
        {
246
            $uid = $args['uid'];
247
        }
248
        $obj = $request->getParsedBody();
249
        $user = $this->getUser($request, $uid, $obj);
250
        if($user === false)
251
        {
252
            return $response->withStatus(404);
253
        }
254
        try
255
        {
256
            if(isset($obj->old_uid))
257
            {
258
                unset($obj->old_uid);
259
            }
260
            $user->editUser($obj);
261
        }
262
        catch(\Exception $e)
263
        {
264
            return $response->withJson($e, exceptionCodeToHttpCode($e));
265
        }
266
        if($this->userIsMe($request, $uid))
267
        {
268
            \FlipSession::setUser($user);
269
        }
270
        if(isset($obj->password))
271
        {
272
            $this->sendPasswordResetEmail($user);
273
        }
274
        return $response->withJson(array('success'=>true));
275
    }
276
277
    public function deleteUser($request, $response, $args)
278
    {
279
        $uid = 'me';
280
        if(isset($args['uid']))
281
        {
282
            $uid = $args['uid'];
283
        }
284
        $user = false;
0 ignored issues
show
Unused Code introduced by
$user is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
285
        if($this->validateIsAdmin($request, true) === false && $this->userIsMe($request, $uid))
286
        {
287
            $user = $this->user;
288
        }
289
        else
290
        {
291
            $auth = AuthProvider::getInstance();
292
            $filter = new \Data\Filter("uid eq $uid");
293
            $user = $auth->getUsersByFilter($filter);
294
            if(empty($user))
295
            {
296
                $user = false;
297
            }
298
            else
299
            {
300
                $user = $user[0];
301
            }
302
        }
303
        if($user === false)
304
        {
305
            return $response->withStatus(404);
306
        }
307
        return $response->withJson($user->delete());
308
    }
309
310
    public function listGroupsForUser($request, $response, $args)
311
    {
312
        $uid = 'me';
313
        if(isset($args['uid']))
314
        {
315
            $uid = $args['uid'];
316
        }
317
        $this->validateLoggedIn($request);
318
        $user = $this->getUserByUID($request, $uid);
319
        if($user === false)
320
        {
321
            return $response->withStatus(404);
322
        }
323
        $groups = $user->getGroups();
324
        if($groups === false)
325
        {
326
            $groups = array();
327
        }
328
        return $response->withJson($groups);
329
    }
330
331
    public function linkUser($request, $response, $args)
332
    {
333
        $uid = 'me';
334
        if(isset($args['uid']))
335
        {
336
            $uid = $args['uid'];
337
        }
338
        $this->validateLoggedIn($request);
339
        $obj = $request->getParsedBody();
340
        if($this->userIsMe($request, $uid))
341
        {
342
            $this->user->addLoginProvider($obj->provider);
343
            AuthProvider::getInstance()->impersonateUser($this->user);
344
        }
345
        else if($this->user->isInGroupNamed("LDAPAdmins"))
346
        {
347
            $user = AuthProvider::getInstance()->getUser($uid);
348
            if($user === false)
349
            {
350
                return $response->withStatus(404);
351
            }
352
            $user->addLoginProvider($obj->provider);
353
        }
354
        else
355
        {
356
            return $response->withStatus(404);
357
        }
358
        return $response->withJson(array('success'=>true));
359
    }
360
361
    protected function getAllUsersByFilter($filter, &$pending)
362
    {
363
        $auth = AuthProvider::getInstance();
364
        $user = $auth->getUsersByFilter($filter);
365
        if(!empty($user))
366
        {
367
            $pending = false;
368
            return $user[0];
369
        }
370
        $user = $auth->getPendingUsersByFilter($filter);
371
        if(!empty($user))
372
        {
373
            $pending = true;
374
            return $user[0];
375
        }
376
        return false;
377
    }
378
379
    public function checkEmailAvailable($request, $response)
380
    {
381
        $params = $request->getQueryParams();
382
        $email = false;
383
        if(isset($params['email']))
384
        {
385
            $email = $params['email'];
386
        }
387
        if($email === false)
388
        {
389
            return $response->withStatus(400);
390
        }
391
        if(filter_var($email, FILTER_VALIDATE_EMAIL) === false || strpos($email, '@') === false)
392
        {
393
            return $response->withJson(false);
394
        }
395
        if(strstr($email, '+') !== false)
396
        {
397
            //Remove everything between the + and the @
398
            $begining = strpos($email, '+');
399
            $end = strpos($email, '@');
400
            $to_delete = substr($email, $begining, $end - $begining);
401
            $email = str_replace($to_delete, '', $email);
402
        }
403
        $filter = new \Data\Filter('mail eq '.$email);
404
        $pending = false;
405
        $user = $this->getAllUsersByFilter($filter, $pending);
406
        if($user === false)
407
        {
408
            return $response->withJson(true);
409
        }
410
        return $response->withJson(array('res'=>false, 'email'=>$user->mail, 'pending'=>$pending));
411
    }
412
413
    public function checkUidAvailable($request, $response)
414
    {
415
        $params = $request->getQueryParams();
416
        $uid = false;
417
        if(isset($params['uid']))
418
        {
419
            $uid = $params['uid'];
420
        }
421
        if($uid === false)
422
        {
423
            return $response->withStatus(400);
424
        }
425
        if(strpos($uid, '=') !== false || strpos($uid, ',') !== false)
426
        {
427
            return $response->withJson(false);
428
        }
429
        $filter = new \Data\Filter('uid eq '.$uid);
430
        $pending = false;
431
        $user = $this->getAllUsersByFilter($filter, $pending);
432
        if($user === false)
433
        {
434
            return $response->withJson(true);
435
        }
436
        return $response->withJson(array('res'=>false, 'uidl'=>$user->uid, 'pending'=>$pending));
437
    }
438
439
    public function resetUserPassword($request, $response, $args)
440
    {
441
        $uid = false;
0 ignored issues
show
Unused Code introduced by
$uid is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
442
        if(isset($args['uid']))
443
        {
444
            $uid = $args['uid'];
445
        }
446
        else
447
        {
448
            return $response->withStatus(400);
449
        }
450
        $auth = AuthProvider::getInstance();
451
        $users = $auth->getUsersByFilter(new \Data\Filter('uid eq '.$uid));
452
        if(empty($users))
453
        {
454
            return $response->withStatus(404);
455
        }
456
        $email_msg = new PasswordResetEmail($users[0]);
457
        $email_provider = EmailProvider::getInstance();
458
        if($email_provider->sendEmail($email_msg) === false)
459
        {
460
            throw new \Exception('Unable to send email!');
461
        }
462
        return $response->withJson(true);
463
    }
464
465
    public function remindUid($request, $response)
466
    {
467
        $params = $request->getQueryParams();
468
        $email = false;
469
        if(isset($params['email']))
470
        {
471
            $email = $params['email'];
472
        }
473
        if($email === false)
474
        {
475
            return $response->withStatus(400);
476
        }
477
        if(filter_var($email, FILTER_VALIDATE_EMAIL) === false)
478
        {
479
            return $response->withStatus(400);
480
        }
481
        $auth = AuthProvider::getInstance();
482
        $users = $auth->getUsersByFilter(new \Data\Filter('mail eq '.$email));
483
        if(empty($users))
484
        {
485
            return $response->withStatus(404);
486
        }
487
        $email_msg = new UIDForgotEmail($users[0]);
488
        $email_provider = EmailProvider::getInstance();
489
        if($email_provider->sendEmail($email_msg) === false)
490
        {
491
            throw new \Exception('Unable to send email!');
492
        }
493
    }
494
}
495
/* vim: set tabstop=4 shiftwidth=4 expandtab: */
496