1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* User class |
4
|
|
|
* |
5
|
|
|
* This file describes the User classes |
6
|
|
|
* |
7
|
|
|
* PHP version 5 and 7 |
8
|
|
|
* |
9
|
|
|
* @author Patrick Boyd / [email protected] |
10
|
|
|
* @copyright Copyright (c) 2015, Austin Artistic Reconstruction |
11
|
|
|
* @license http://www.apache.org/licenses/ Apache 2.0 License |
12
|
|
|
*/ |
13
|
|
|
|
14
|
|
|
namespace Flipside\Auth; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* A class to abstract access to Users regardless of the Authentication type used. |
18
|
|
|
* |
19
|
|
|
* This class is the primary method to access user information. |
20
|
|
|
* |
21
|
|
|
* @property string $uid The user's ID or name |
22
|
|
|
* @property string $mail The user's email address |
23
|
|
|
* @property string $sn The user's surname (last name) |
24
|
|
|
* @property string $givenName The user's given name (first name) |
25
|
|
|
* @property string $cn The user's nick name |
26
|
|
|
* @property string $displayName The user's display name |
27
|
|
|
* @property string $postalAddress The user's mailing address |
28
|
|
|
* @property string $postalCode The user's postal or zip code |
29
|
|
|
* @property string $l The user's city |
30
|
|
|
* @property string $st The user's state or province |
31
|
|
|
* @property string $c The user's country |
32
|
|
|
* @property string $mobile The user's phone number |
33
|
|
|
* @property string $jpegPhoto The user's profile photo |
34
|
|
|
* @property array $host The service's the user can use to login |
35
|
|
|
* @property array $title The user's titles in the organization |
36
|
|
|
* @property string $o The user's organization |
37
|
|
|
* @property array $ou The user's units or areas within the organization |
38
|
|
|
*/ |
39
|
|
|
class User extends \Flipside\SerializableObject |
40
|
|
|
{ |
41
|
|
|
/** |
42
|
|
|
* An array to cache the title to string mappings so that they don't need to be pulled from the database |
43
|
|
|
* everytime |
44
|
|
|
*/ |
45
|
|
|
public static $titlenames = null; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* An array of properties that cannot be set on a user |
49
|
|
|
*/ |
50
|
|
|
protected $unsettableElements = array( |
51
|
|
|
'uid', |
52
|
|
|
'email' |
53
|
|
|
); |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* Is this user in the Group or a child of that group? |
57
|
|
|
* |
58
|
|
|
* @param string $name The name of the group to check if the user is in |
59
|
|
|
* |
60
|
|
|
* @return boolean True if the user is in the group, false otherwise |
61
|
|
|
*/ |
62
|
|
|
public function isInGroupNamed($name) |
63
|
|
|
{ |
64
|
|
|
return false; |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
public function __get($propName) |
68
|
|
|
{ |
69
|
|
|
return false; |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
public function __set($propName, $value) |
73
|
|
|
{ |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
public function __isset($propName) |
77
|
|
|
{ |
78
|
|
|
return false; |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* The list of titles for the user |
83
|
|
|
* |
84
|
|
|
* @return boolean|array The user's title(s) in user friendly strings |
85
|
|
|
* |
86
|
|
|
* @SuppressWarnings("StaticAccess") |
87
|
|
|
*/ |
88
|
|
|
public function getTitleNames() |
89
|
|
|
{ |
90
|
|
|
$titles = $this->title; |
91
|
|
|
if($titles === false) |
92
|
|
|
{ |
93
|
|
|
return false; |
94
|
|
|
} |
95
|
|
|
if(self::$titlenames === null) |
96
|
|
|
{ |
97
|
|
|
$dataSet = \DataSetFactory::getDataSetByName('profiles'); |
98
|
|
|
$dataTable = $dataSet['position']; |
99
|
|
|
$titlenames = $dataTable->read(); |
100
|
|
|
self::$titlenames = array(); |
101
|
|
|
$count = count($titlenames); |
102
|
|
|
for($i = 0; $i < $count; $i++) |
103
|
|
|
{ |
104
|
|
|
self::$titlenames[$titlenames[$i]['short_name']] = $titlenames[$i]; |
105
|
|
|
} |
106
|
|
|
} |
107
|
|
|
$count = count($titles); |
108
|
|
|
for($i = 0; $i < $count; $i++) |
109
|
|
|
{ |
110
|
|
|
if(isset(self::$titlenames[$titles[$i]])) |
111
|
|
|
{ |
112
|
|
|
$title = self::$titlenames[$titles[$i]]; |
113
|
|
|
$titles[$i] = $title['name']; |
114
|
|
|
} |
115
|
|
|
} |
116
|
|
|
return $titles; |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
* The groups the user is a part of |
121
|
|
|
* |
122
|
|
|
* @return boolean|array The user's Auth\Group structures |
123
|
|
|
*/ |
124
|
|
|
public function getGroups() |
125
|
|
|
{ |
126
|
|
|
return false; |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* Add a supplemental login type that the user can use to login |
131
|
|
|
* |
132
|
|
|
* @param string $provider The hostname for the provider |
133
|
|
|
*/ |
134
|
|
|
public function addLoginProvider($provider) |
135
|
|
|
{ |
136
|
|
|
if(isset($this->host)) |
137
|
|
|
{ |
138
|
|
|
$tmp = $this->host; |
139
|
|
|
$tmp[] = $provider; |
140
|
|
|
$this->host = $tmp; |
141
|
|
|
} |
142
|
|
|
else |
143
|
|
|
{ |
144
|
|
|
$this->host = array($provider); |
145
|
|
|
} |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
/** |
149
|
|
|
* Can the user login with this provider? |
150
|
|
|
* |
151
|
|
|
* @param string $provider The hostname for the provider |
152
|
|
|
* |
153
|
|
|
* @return boolean true if they can login with the provider, false otherwise |
154
|
|
|
*/ |
155
|
|
|
public function canLoginWith($provider) |
156
|
|
|
{ |
157
|
|
|
$hosts = $this->host; |
158
|
|
|
if($hosts === false) |
159
|
|
|
{ |
160
|
|
|
return false; |
161
|
|
|
} |
162
|
|
|
$count = count($hosts); |
163
|
|
|
for($i = 0; $i < $count; $i++) |
164
|
|
|
{ |
165
|
|
|
if(strcasecmp($hosts[$i], $provider) === 0) |
166
|
|
|
{ |
167
|
|
|
return true; |
168
|
|
|
} |
169
|
|
|
} |
170
|
|
|
return false; |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
/** |
174
|
|
|
* Set the user's password without verifying the current password |
175
|
|
|
* |
176
|
|
|
* @param string $password The new user password |
177
|
|
|
* |
178
|
|
|
* @return boolean true if the user's password was changed, false otherwise |
179
|
|
|
*/ |
180
|
|
|
protected function setPass($password) |
181
|
|
|
{ |
182
|
|
|
return false; |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
/** |
186
|
|
|
* Has the user completely filled out their user profile? |
187
|
|
|
* |
188
|
|
|
* @return boolean true if the user's profile is complete, false otherwise |
189
|
|
|
*/ |
190
|
|
|
public function isProfileComplete() |
191
|
|
|
{ |
192
|
|
|
if($this->c === false || $this->postalAddress === false || |
193
|
|
|
$this->postalCode === false || $this->l === false || |
194
|
|
|
$this->st === false || $this->mobile === false) |
195
|
|
|
{ |
196
|
|
|
return false; |
197
|
|
|
} |
198
|
|
|
return true; |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
/** |
202
|
|
|
* Validate that the user's password is the specified password |
203
|
|
|
* |
204
|
|
|
* @param string $password The user's current password |
205
|
|
|
* |
206
|
|
|
* @return boolean true if the user's password is correct, false otherwise |
207
|
|
|
* |
208
|
|
|
* @SuppressWarnings("UnusedFormalParameter") |
209
|
|
|
*/ |
210
|
|
|
public function validate_password($password) |
211
|
|
|
{ |
212
|
|
|
return false; |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
/** |
216
|
|
|
* Validate that the user's reset hash is the sepcified hash |
217
|
|
|
* |
218
|
|
|
* @param string $hash The user's reset hash |
219
|
|
|
* |
220
|
|
|
* @return boolean true if the user's hash is correct, false otherwise |
221
|
|
|
* |
222
|
|
|
* @SuppressWarnings("UnusedFormalParameter") |
223
|
|
|
*/ |
224
|
|
|
public function validate_reset_hash($hash) |
225
|
|
|
{ |
226
|
|
|
return false; |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
/** |
230
|
|
|
* Change the user's password, validating the old password or reset hash |
231
|
|
|
* |
232
|
|
|
* @param string $oldpass The user's original password or reset hash if $isHash is true |
233
|
|
|
* @param string $newpass The user's new password |
234
|
|
|
* @param boolean $isHash Is $old_pass a password or a hash |
235
|
|
|
* |
236
|
|
|
* @return boolean true if the user's password was changed, false otherwise |
237
|
|
|
*/ |
238
|
|
|
public function change_pass($oldpass, $newpass, $isHash = false) |
239
|
|
|
{ |
240
|
|
|
if($isHash === false && $this->validate_password($oldpass) === false) |
241
|
|
|
{ |
242
|
|
|
throw new \Exception('Invalid Password!', 3); |
243
|
|
|
} |
244
|
|
|
if($isHash === true && $this->validate_reset_hash($oldpass) === false) |
245
|
|
|
{ |
246
|
|
|
throw new \Exception('Invalid Reset Hash!', 3); |
247
|
|
|
} |
248
|
|
|
if($this->setPass($newpass) === false) |
249
|
|
|
{ |
250
|
|
|
throw new \Exception('Unable to set password!', 6); |
251
|
|
|
} |
252
|
|
|
return true; |
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
/** |
256
|
|
|
* Allow write for the user |
257
|
|
|
*/ |
258
|
|
|
protected function enableReadWrite() |
259
|
|
|
{ |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
/** |
263
|
|
|
* Update the user password if required |
264
|
|
|
*/ |
265
|
|
|
private function editUserPassword(&$data) |
266
|
|
|
{ |
267
|
|
|
if(isset($data->password)) |
268
|
|
|
{ |
269
|
|
View Code Duplication |
if(isset($data->oldpass)) |
|
|
|
|
270
|
|
|
{ |
271
|
|
|
$this->change_pass($data->oldpass, $data->password); |
272
|
|
|
unset($data->oldpass); |
273
|
|
|
} |
274
|
|
|
else if(isset($data->hash)) |
275
|
|
|
{ |
276
|
|
|
$this->change_pass($data->hash, $data->password, true); |
277
|
|
|
unset($data->hash); |
278
|
|
|
} |
279
|
|
|
unset($data->password); |
280
|
|
|
} |
281
|
|
|
else if(isset($data->userPassword)) |
282
|
|
|
{ |
283
|
|
View Code Duplication |
if(isset($data->oldpass)) |
|
|
|
|
284
|
|
|
{ |
285
|
|
|
$this->change_pass($data->oldpass, $data->userPassword); |
286
|
|
|
unset($data->oldpass); |
287
|
|
|
} |
288
|
|
|
else if(isset($data->hash)) |
289
|
|
|
{ |
290
|
|
|
$this->change_pass($data->hash, $data->userPassword, true); |
291
|
|
|
unset($data->hash); |
292
|
|
|
} |
293
|
|
|
unset($data->userPassword); |
294
|
|
|
} |
295
|
|
|
} |
296
|
|
|
|
297
|
|
|
private function checkForUnsettableElements($data) |
298
|
|
|
{ |
299
|
|
|
$count = count($this->unsettableElements); |
300
|
|
|
for($i = 0; $i < $count; $i++) |
301
|
|
|
{ |
302
|
|
|
$propName = $this->unsettableElements[$i]; |
303
|
|
|
if(isset($data->{$propName})) |
304
|
|
|
{ |
305
|
|
|
if($data->{$propName} !== $this->{$propName}) |
306
|
|
|
{ |
307
|
|
|
throw new \Exception('Unable to change '.$propName.'!'); |
308
|
|
|
} |
309
|
|
|
unset($data->{$propName}); |
310
|
|
|
} |
311
|
|
|
} |
312
|
|
|
} |
313
|
|
|
|
314
|
|
|
/** |
315
|
|
|
* Modify the user given the provided data object |
316
|
|
|
* |
317
|
|
|
* @param stdClass $data The user's new data |
318
|
|
|
* |
319
|
|
|
* @return boolean true if the user's data was changed, false otherwise |
320
|
|
|
*/ |
321
|
|
|
public function editUser($data) |
322
|
|
|
{ |
323
|
|
|
if(is_array($data)) |
324
|
|
|
{ |
325
|
|
|
$data = new \Flipside\SerializableObject($data); |
326
|
|
|
} |
327
|
|
|
|
328
|
|
|
$this->checkForUnsettableElements($data); |
329
|
|
|
|
330
|
|
|
$this->enableReadWrite(); |
331
|
|
|
|
332
|
|
|
/* These elements require special handling */ |
333
|
|
|
$this->editUserPassword($data); |
334
|
|
|
if(isset($data->jpegPhoto)) |
335
|
|
|
{ |
336
|
|
|
$this->jpegPhoto = base64_decode($data->jpegPhoto); |
337
|
|
|
unset($data->jpegPhoto); |
338
|
|
|
} |
339
|
|
|
|
340
|
|
|
/* These are generic elements */ |
341
|
|
|
if(!is_array($data)) |
342
|
|
|
{ |
343
|
|
|
$data = get_object_vars($data); |
344
|
|
|
} |
345
|
|
|
foreach($data as $key=>$value) |
346
|
|
|
{ |
347
|
|
|
$this->{$key} = $value; |
348
|
|
|
} |
349
|
|
|
} |
350
|
|
|
|
351
|
|
|
/** |
352
|
|
|
* Obtain the user's password reset hash |
353
|
|
|
* |
354
|
|
|
* @return string|false A hash if available, false otherwise |
355
|
|
|
*/ |
356
|
|
|
public function getPasswordResetHash() |
357
|
|
|
{ |
358
|
|
|
return false; |
359
|
|
|
} |
360
|
|
|
|
361
|
|
|
/** |
362
|
|
|
* Remove the email address from the user account |
363
|
|
|
* |
364
|
|
|
* @param string $email The email to remove |
365
|
|
|
* |
366
|
|
|
* @return boolean If the operation succeeded or not |
367
|
|
|
*/ |
368
|
|
|
public function removeEmail($email) |
369
|
|
|
{ |
370
|
|
|
return false; |
371
|
|
|
} |
372
|
|
|
|
373
|
|
|
/** |
374
|
|
|
* Serialize the user data into a format usable by the json_encode method |
375
|
|
|
* |
376
|
|
|
* @return array A simple keyed array representing the user |
377
|
|
|
*/ |
378
|
|
|
public function jsonSerialize() |
379
|
|
|
{ |
380
|
|
|
$user = array(); |
381
|
|
|
$user['displayName'] = $this->displayName; |
382
|
|
|
$user['givenName'] = $this->givenName; |
383
|
|
|
$user['jpegPhoto'] = base64_encode($this->jpegPhoto); |
384
|
|
|
$user['mail'] = $this->mail; |
385
|
|
|
$user['mobile'] = $this->mobile; |
386
|
|
|
$user['uid'] = $this->uid; |
387
|
|
|
$user['o'] = $this->o; |
388
|
|
|
$user['title'] = $this->title; |
389
|
|
|
$user['titlenames'] = $this->getTitleNames(); |
390
|
|
|
$user['st'] = $this->st; |
391
|
|
|
$user['l'] = $this->l; |
392
|
|
|
$user['sn'] = $this->sn; |
393
|
|
|
$user['cn'] = $this->cn; |
394
|
|
|
$user['postalAddress'] = $this->postalAddress; |
395
|
|
|
$user['postalCode'] = $this->postalCode; |
396
|
|
|
$user['c'] = $this->c; |
397
|
|
|
$user['ou'] = $this->ou; |
398
|
|
|
$user['host'] = $this->host; |
399
|
|
|
$user['class'] = get_class($this); |
400
|
|
|
if(isset($this->allMail)) |
401
|
|
|
{ |
402
|
|
|
$user['allMail'] = $this->allMail; |
|
|
|
|
403
|
|
|
} |
404
|
|
|
return $user; |
405
|
|
|
} |
406
|
|
|
|
407
|
|
|
/** |
408
|
|
|
* Serialize the user data into a VCARD 2.1 format |
409
|
|
|
* |
410
|
|
|
* @return string The VCARD for the user |
411
|
|
|
*/ |
412
|
|
|
public function getVcard() |
413
|
|
|
{ |
414
|
|
|
$ret = "BEGIN:VCARD\nVERSION:2.1\n"; |
415
|
|
|
$ret .= 'N:'.$this->sn.';'.$this->givenName."\n"; |
416
|
|
|
$ret .= 'FN:'.$this->givenName."\n"; |
417
|
|
|
$titles = $this->title; |
418
|
|
|
if($titles !== false) |
419
|
|
|
{ |
420
|
|
|
$ret .= 'TITLE:'.implode(',', $titles)."\n"; |
421
|
|
|
} |
422
|
|
|
$ret .= "ORG: Austin Artistic Reconstruction\n"; |
423
|
|
|
$ret .= 'TEL;TYPE=MOBILE,VOICE:'.$this->mobile."\n"; |
424
|
|
|
$ret .= 'EMAIL;TYPE=PREF,INTERNET:'.$this->mail."\n"; |
425
|
|
|
$ret .= "END:VCARD\n"; |
426
|
|
|
return $ret; |
427
|
|
|
} |
428
|
|
|
} |
429
|
|
|
/* vim: set tabstop=4 shiftwidth=4 expandtab: */ |
430
|
|
|
|
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.