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

api/v1/class.UsersAPI.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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)
22
    {
23
        $this->user = $request->getAttribute('user');
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)
40
    {
41
        $users = false;
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]))
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]))
67
        {
68
            $message = 'Username already exists!';
69
            return false;
70
        }
71
        return true;
72
    }
73
74 View Code Duplication
    protected function validEmail($email)
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)
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)
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)
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)
140
    {
141
        if($this->userIsMe($request, $uid))
142
        {
143
            return $this->user;
144
        }
145
        if($this->user->isInGroupNamed('LDAPAdmins') || $this->hasLeadAccess($request))
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)
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;
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);
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]))
378
        {
379
            $pending = false;
380
            return $user[0];
381
        }
382
        $user = $auth->getPendingUsersByFilter($filter);
383 View Code Duplication
        if($user !== false && isset($user[0]))
384
        {
385
            $pending = true;
386
            return $user[0];
387
        }
388
        return false;
389
    }
390
391
    public function checkEmailAvailable($request, $response, $args)
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
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)
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;
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
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
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