Completed
Push — master ( 4f23d4...a4c187 )
by Patrick
02:03
created

UsersAPI::createUser()   C

Complexity

Conditions 8
Paths 8

Size

Total Lines 39
Code Lines 22

Duplication

Lines 8
Ratio 20.51 %

Importance

Changes 0
Metric Value
cc 8
eloc 22
nc 8
nop 3
dl 8
loc 39
rs 5.3846
c 0
b 0
f 0
1
<?php
2
require_once('class.UIDForgotEmail.php');
3
4
class UsersAPI extends Http\Rest\RestAPI
5
{
6
    public function setup($app)
7
    {
8
        $app->get('[/]', array($this, 'listUsers'));
9
        $app->post('[/]', array($this, 'createUser'));
10
        $app->get('/{uid}[/]', array($this, 'showUser'));
11
        $app->patch('/{uid}[/]', array($this, 'editUser'));
12
        $app->delete('/{uid}[/]', array($this, 'deleteUser'));
13
        $app->get('/{uid}/groups[/]', array($this, 'listGroupsForUser'));
14
        $app->post('/{uid}/Actions/link[/]', array($this, 'linkUser'));
15
        $app->post('/{uid}/Actions/reset_pass[/]', array($this, 'resetUserPassword'));
16
        $app->post('/Actions/check_email_available[/]', array($this, 'checkEmailAvailable'));
17
        $app->post('/Actions/check_uid_available[/]', array($this, 'checkUidAvailable'));
18
        $app->post('/Actions/remind_uid[/]', array($this, 'remindUid'));
19
    }
20
21 View Code Duplication
    public function validateIsAdmin($request, $nonFatal = false)
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...
22
    {
23
        $this->user = $request->getAttribute('user');
0 ignored issues
show
Bug introduced by
The property user does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
24
        if($this->user === false)
25
        {
26
            throw new Exception('Must be logged in', \Http\Rest\ACCESS_DENIED);
27
        }
28
        if(!$this->user->isInGroupNamed('LDAPAdmins'))
29
        {
30
            if($nonFatal)
31
            {
32
                return false;
33
            }
34
            throw new Exception('Must be Admin', \Http\Rest\ACCESS_DENIED);
35
        }
36
        return true;
37
    }
38
39
    public function listUsers($request, $response, $args)
0 ignored issues
show
Unused Code introduced by
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
40
    {
41
        $users = false;
0 ignored issues
show
Unused Code introduced by
$users 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...
42
        $odata = $request->getAttribute('odata', new \ODataParams(array()));
43
        if($this->validateIsAdmin($request, true) === false)
44
        {
45
            $users = array($this->user);
46
            $users = $odata->filterArrayPerSelect($users);
47
        }
48
        else
49
        {
50
            $auth = AuthProvider::getInstance();
51
            $users = $auth->getUsersByFilter($odata->filter, $odata->select, $odata->top, $odata->skip, 
52
                                             $odata->orderby);
53
        }
54
        return $response->withJson($users);
55
    }
56
57
    protected function validateCanCreateUser($proposedUser, $auth, &$message)
58
    {
59
        $user = $auth->getUsersByFilter(new \Data\Filter('mail eq '.$proposedUser->mail));
60 View Code Duplication
        if($user !== false && isset($user[0]))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
61
        {
62
            $message = 'Email already exists!';
63
            return false;
64
        }
65
        $user = $auth->getUsersByFilter(new \Data\Filter('uid eq '.$proposedUser->uid));
66 View Code Duplication
        if($user !== false && isset($user[0]))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
67
        {
68
            $message = 'Username already exists!';
69
            return false;
70
        }
71
        return true;
72
    }
73
74 View Code Duplication
    protected function validEmail($email)
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...
75
    {
76
        if(filter_var($email) === false)
77
        {
78
            return false;
79
        }
80
        $pos = strpos($email, '@');
81
        if($pos === false)
82
        {
83
            return false;
84
        }
85
        $domain = substr($email, $pos+1);
86
        if(checkdnsrr($domain, 'MX') === false)
87
        {
88
            return false;
89
        }
90
        return true;
91
    }
92
93
    public function createUser($request, $response, $args)
0 ignored issues
show
Unused Code introduced by
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
94
    {
95
        $this->user = $request->getAttribute('user');
96
        //This one is different. If they are logged in fail...
97
        if($this->user !== false)
98
        {
99
            return $response->withStatus(404);
100
        }
101
        $obj = $request->getParsedBody();
102
        if(!isset($obj->captcha))
103
        {
104
            return $response->withStatus(401);
105
        }
106
        $captcha = FlipSession::getVar('captcha');
107
        if($captcha === false)
108
        {
109
            return $response->withStatus(401);
110
        }
111
        if(!$captcha->is_answer_right($obj->captcha))
112
        {
113
            return $response->withJson(array('res'=>false, 'message'=>'Incorrect answer to CAPTCHA!'), 412);
114
        }
115
        $auth = AuthProvider::getInstance();
116
        $message = false;
117
        if($this->validateCanCreateUser($obj, $auth, $message) === false)
118
        {
119
            return $response->withJson(array('res'=>false, 'message'=>$message), 412);
120
        }
121 View Code Duplication
        else if($this->validEmail($obj->mail) === false)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
122
        {
123
            return $response->withJson(array('res'=>false, 'message'=>'Invalid Email Address!'));
124
        }
125
        $ret = $auth->createPendingUser($obj);
126 View Code Duplication
        if($ret == false)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
127
        {
128
            return $response->withJson(array('res'=>false, 'message'=>'Failed to save user registration!'), 500);
129
        }
130
        return $response->withJson($ret);
131
    }
132
133
    protected function userIsMe($request, $uid)
134
    {
135
        $this->user = $request->getAttribute('user');
136
        return ($uid === 'me' || ($this->user !== false && $uid === $this->user->uid));
137
    }
138
139 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...
140
    {
141
        if($this->userIsMe($request, $uid))
142
        {
143
            return $this->user;
144
        }
145
        if($this->user->isInGroupNamed('LDAPAdmins') || $this->hasLeadAccess($request))
0 ignored issues
show
Bug introduced by
The method hasLeadAccess() does not seem to exist on object<UsersAPI>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
146
        {
147
            $auth = \AuthProvider::getInstance();
148
            $filter = new \Data\Filter("uid eq $uid");
149
            $users = $auth->getUsersByFilter($filter);
150
            if($users !== false && isset($users[0]))
151
            {
152
                return $users[0];
153
            }
154
        }
155
        return false;
156
    }
157
158 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...
159
    {
160
        if($this->userIsMe($request, $uid))
161
        {
162
            return $this->user;
163
        }
164
        if($this->user->isInGroupNamed('LDAPAdmins'))
165
        {
166
            $auth = \AuthProvider::getInstance();
167
            $filter = new \Data\Filter("uid eq $uid");
168
            $users = $auth->getUsersByFilter($filter);
169
            if($users !== false && isset($users[0]))
170
            {
171
                return $users[0];
172
            }
173
        }
174
        return false;
175
    }
176
177
    public function showUser($request, $response, $args)
178
    {
179
        $uid = $args['uid'];
180
        $user = $request->getAttribute('user');
181
        if($user === false)
182
        {
183
            if($_SERVER['SERVER_ADDR'] === $_SERVER['REMOTE_ADDR'])
184
            {
185
                $user = \AuthProvider::getInstance()->getUsersByFilter(new \Data\Filter("uid eq $uid"));
186
                if($user === false || !isset($user[0]))
187
                {
188
                    return $response->withStatus(404);
189
                }
190
                return $response->withJson($user[0]);
191
            } 
192
            return $response->withStatus(401);
193
        }
194
        $user = $this->getUserByUIDReadOnly($request, $uid);
195
        if($user === false)
196
        {
197
            return $response->withStatus(404);
198
        }
199
        if(!is_object($user) && isset($user[0]))
200
        {
201
            $user = $user[0];
202
        }
203
        if($request->getAttribute('format') === 'vcard')
204
        {
205
            $response = $response->withHeader('Content-Type', 'text/x-vCard');
206
            $response->getBody()->write($user->getVcard());
207
            return $response;
208
        }
209
        return $response->withJson($user);
210
    }
211
212
    protected function sendPasswordResetEmail($user)
213
    {
214
        $forwardedFor = false;
215
        if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
216
        {
217
            $forwardedFor = $_SERVER['HTTP_X_FORWARDED_FOR'];
218
        }
219
        $emailMsg = new PasswordHasBeenResetEmail($user, $_SERVER['REMOTE_ADDR'], $forwardedFor);
220
        $emailProvider = EmailProvider::getInstance();
221
        if($emailProvider->sendEmail($emailMsg) === false)
222
        {
223
            throw new \Exception('Unable to send password reset email!');
224
        }
225
    }
226
227
    protected function exceptionCodeToHttpCode($e)
228
    {
229
        if($e->getCode() === 3)
230
        {
231
            return 401;
232
        }
233
        return 500;
234
    }
235
236
    protected function getUser($request, $uid, $payload)
237
    {
238
        $this->user = $request->getAttribute('user');
239
        if($this->user === false)
240
        {
241
            if(isset($payload->hash))
242
            {
243
                $auth = AuthProvider::getInstance();
244
                $this->user = $auth->getUserByResetHash($payload->hash);
245
                return $this->user;
246
            }
247
            return false;
248
        }
249
        return $this->getUserByUID($request, $uid);
250
    }
251
252
    public function editUser($request, $response, $args)
253
    {
254
        $uid = 'me';
255
        if(isset($args['uid']))
256
        {
257
            $uid = $args['uid'];
258
        }
259
        $obj = $request->getParsedBody();
260
        $user = $this->getUser($request, $uid, $obj);
261
        if($user === false)
262
        {
263
            return $response->withStatus(404);
264
        }
265
        try
266
        {
267
            if(isset($obj['old_uid']))
268
            {
269
                unset($obj['old_uid']);
270
            }
271
            unset($obj['uid']);
272
            $user->editUser($obj);
273
        }
274
        catch(\Exception $e)
275
        {
276
            return $response->withJson(array('error'=>array('msg'=>$e->getMessage(), 'stack'=>$e->getTraceAsString())), $this->exceptionCodeToHttpCode($e));
277
        }
278
        if($this->userIsMe($request, $uid))
279
        {
280
            \FlipSession::setUser($user);
281
        }
282
        if(isset($obj->password))
283
        {
284
            $this->sendPasswordResetEmail($user);
285
        }
286
        return $response->withJson(array('success'=>true));
287
    }
288
289
    public function deleteUser($request, $response, $args)
290
    {
291
        $uid = 'me';
292
        if(isset($args['uid']))
293
        {
294
            $uid = $args['uid'];
295
        }
296
        $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...
297
        if($this->validateIsAdmin($request, true) === false && $this->userIsMe($request, $uid))
298
        {
299
            $user = $this->user;
300
        }
301
        else
302
        {
303
            $auth = AuthProvider::getInstance();
304
            $filter = new \Data\Filter("uid eq $uid");
305
            $user = $auth->getUsersByFilter($filter);
306
            if(empty($user))
307
            {
308
                $user = false;
309
            }
310
            else
311
            {
312
                $user = $user[0];
313
            }
314
        }
315
        if($user === false)
316
        {
317
            return $response->withStatus(404);
318
        }
319
        return $response->withJson($user->delete());
320
    }
321
322
    public function listGroupsForUser($request, $response, $args)
323
    {
324
        $uid = 'me';
325
        if(isset($args['uid']))
326
        {
327
            $uid = $args['uid'];
328
        }
329
        $this->validateLoggedIn($request);
330
        $user = $this->getUserByUID($request, $uid);
331
        if($user === false)
332
        {
333
            return $response->withStatus(404);
334
        }
335
        $groups = $user->getGroups();
336
        if($groups === false)
337
        {
338
            $groups = array();
339
        }
340
        return $response->withJson($groups);
341
    }
342
343
    public function linkUser($request, $response, $args)
344
    {
345
        $uid = 'me';
346
        if(isset($args['uid']))
347
        {
348
            $uid = $args['uid'];
349
        }
350
        $this->validateLoggedIn($request);
351
        $obj = $request->getParsedBody();
352
        if($this->userIsMe($request, $uid))
353
        {
354
            $this->user->addLoginProvider($obj->provider);
355
            AuthProvider::getInstance()->impersonateUser($app->user);
0 ignored issues
show
Bug introduced by
The variable $app does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
356
        }
357
        else if($this->user->isInGroupNamed("LDAPAdmins"))
358
        {
359
            $user = AuthProvider::getInstance()->getUser($uid);
360
            if($user === false)
361
            {
362
                return $response->withStatus(404);
363
            }
364
            $user->addLoginProvider($obj->provider);
365
        }
366
        else
367
        {
368
            return $response->withStatus(404);
369
        }
370
        return $response->withJson(array('success'=>true));
371
    }
372
373
    protected function getAllUsersByFilter($filter, &$pending)
374
    {
375
        $auth = AuthProvider::getInstance();
376
        $user = $auth->getUsersByFilter($filter);
377 View Code Duplication
        if($user !== false && isset($user[0]))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
378
        {
379
            $pending = false;
380
            return $user[0];
381
        }
382
        $user = $auth->getPendingUsersByFilter($filter);
383 View Code Duplication
        if($user !== false && isset($user[0]))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
384
        {
385
            $pending = true;
386
            return $user[0];
387
        }
388
        return false;
389
    }
390
391
    public function checkEmailAvailable($request, $response, $args)
0 ignored issues
show
Unused Code introduced by
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
392
    {
393
        $params = $request->getQueryParams();
394
        $email = false;
395
        if(isset($params['email']))
396
        {
397
            $email = $params['email'];
398
        }
399 View Code Duplication
        if($email === false)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
400
        {
401
            $params = $request->getParsedBody();
402
            if(isset($params['email']))
403
            {
404
                $email = $params['email'];
405
            }
406
            if($email === false)
407
            {
408
                return $response->withStatus(400);
409
            }
410
        }
411
        if(filter_var($email, FILTER_VALIDATE_EMAIL) === false || strpos($email, '@') === false)
412
        {
413
            return $response->withJson(false);
414
        }
415
        if(strstr($email, '+') !== false)
416
        {
417
            //Remove everything between the + and the @
418
            $begining = strpos($email, '+');
419
            $end = strpos($email, '@');
420
            $to_delete = substr($email, $begining, $end - $begining);
421
            $email = str_replace($to_delete, '', $email);
422
        }
423
        $filter = new \Data\Filter('mail eq '.$email);
424
        $pending = false;
425
        $user = $this->getAllUsersByFilter($filter, $pending);
426
        if($user === false)
427
        {
428
            return $response->withJson(true);
429
        }
430
        return $response->withJson(array('res'=>false, 'email'=>$user->mail, 'pending'=>$pending));
431
    }
432
433
    public function checkUidAvailable($request, $response, $args)
0 ignored issues
show
Unused Code introduced by
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
434
    {
435
        $params = $request->getQueryParams();
436
        $uid = false;
437
        if(isset($params['uid']))
438
        {
439
            $uid = $params['uid'];
440
        }
441
        if($uid === false)
442
        {
443
            return $response->withStatus(400);
444
        }
445
        if(strpos($uid, '=') !== false || strpos($uid, ',') !== false)
446
        {
447
            return $response->withJson(false);
448
        }
449
        $filter = new \Data\Filter('uid eq '.$uid);
450
        $pending = false;
451
        $user = $this->getAllUsersByFilter($filter, $pending);
452
        if($user === false)
453
        {
454
            return $response->withJson(true);
455
        }
456
        return $response->withJson(array('res'=>false, 'uidl'=>$user->uid, 'pending'=>$pending));
457
    }
458
459
    public function resetUserPassword($request, $response, $args)
460
    {
461
        $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...
462
        if(isset($args['uid']))
463
        {
464
            $uid = $args['uid'];
465
        }
466
        else
467
        {
468
            return $response->withStatus(400);
469
        }
470
        $auth = AuthProvider::getInstance();
471
        $users = $auth->getUsersByFilter(new \Data\Filter('uid eq '.$uid));
472
        if($users === false || !isset($users[0]))
473
        {
474
            return $response->withStatus(404);
475
        }
476
        $email_msg = new PasswordResetEmail($users[0]);
477
        $email_provider = EmailProvider::getInstance();
478
        if($email_provider->sendEmail($email_msg) === false)
479
        {
480
            throw new \Exception('Unable to send email!');
481
        }
482
        return $response->withJson(true);
483
    }
484
485
    public function remindUid($request, $response, $args)
0 ignored issues
show
Unused Code introduced by
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
486
    {
487
        $params = $request->getQueryParams();
488
        $email = false;
489
        if(isset($params['email']))
490
        {
491
            $email = $params['email'];
492
        }
493 View Code Duplication
        if($email === false)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
494
        {
495
            $params = $request->getParsedBody();
496
            if(isset($params['email']))
497
            {
498
                $email = $params['email'];
499
            }
500
            if($email === false)
501
            {
502
                return $response->withStatus(400);
503
            }
504
        }
505
        if(filter_var($email, FILTER_VALIDATE_EMAIL) === false)
506
        {
507
            return $response->withStatus(400);
508
        }
509
        $auth = AuthProvider::getInstance();
510
        $users = $auth->getUsersByFilter(new \Data\Filter('mail eq '.$email));
511
        if($users === false || !isset($users[0]))
512
        {
513
            return $response->withStatus(404);
514
        }
515
        $email_msg = new UIDForgotEmail($users[0]);
516
        $email_provider = EmailProvider::getInstance();
517
        if($email_provider->sendEmail($email_msg) === false)
518
        {
519
            throw new \Exception('Unable to send email!');
520
        }
521
    }
522
}
523
/* vim: set tabstop=4 shiftwidth=4 expandtab: */
524