FOSSology  3.2.0rc1
Open Source License Compliance by Open Source Software
user-edit.php
1 <?php
2 /***********************************************************
3  Copyright (C) 2014 Hewlett-Packard Development Company, L.P.
4 
5  This program is free software; you can redistribute it and/or
6  modify it under the terms of the GNU General Public License
7  version 2 as published by the Free Software Foundation.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License along
15  with this program; if not, write to the Free Software Foundation, Inc.,
16  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  ***********************************************************/
18 
30 
32 {
33  const NAME = "user_edit";
34 
36  private $dbManager;
37 
41  private $authHelper;
42 
46  private $userDao;
47 
48  function __construct()
49  {
50  parent::__construct(self::NAME, array(
51  self::TITLE => _("Edit User Account"),
52  self::MENU_LIST => 'Admin::Users::Edit User Account',
53  self::REQUIRES_LOGIN => true,
54  self::PERMISSION => Auth::PERM_READ
55  ));
56 
57  $this->dbManager = $this->getObject('db.manager');
58  $this->authHelper = $this->getObject('helper.authHelper');
59  $this->userDao = $this->getObject('dao.user');
60  }
61 
71  protected function handle(Request $request)
72  {
73  /* Is the session owner an admin? */
74  $user_pk = Auth::getUserId();
75  $SessionUserRec = $this->GetUserRec($user_pk);
76  $SessionIsAdmin = $this->IsSessionAdmin($SessionUserRec);
77  $newToken = "";
78 
79  if (GetParm('new_pat', PARM_STRING)) {
80  try {
81  $newToken = $this->generateNewToken($request);
82  } catch (\Exception $e) {
83  $vars['message'] = $e->getMessage();
84  }
85  }
86 
87  $user_pk_to_modify = intval($request->get('user_pk'));
88  if (! ($SessionIsAdmin || empty($user_pk_to_modify) ||
89  $user_pk == $user_pk_to_modify)) {
90  $vars['content'] = _("Your request is not valid.");
91  return $this->render('include/base.html.twig', $this->mergeWithDefault($vars));
92  }
93 
94  $vars = array('refreshUri' => Traceback_uri() . "?mod=" . self::NAME);
95 
96  /*
97  * If this is a POST (the submit button was clicked), then process the
98  * request.
99  */
100  $BtnText = $request->get('UpdateBtn');
101  if (! empty($BtnText)) {
102  /* Get the form data to in an associated array */
103  $UserRec = $this->CreateUserRec($request, "");
104 
105  $rv = $this->UpdateUser($UserRec, $SessionIsAdmin);
106  if (empty($rv)) {
107  // Successful db update
108  $vars['message'] = "User $UserRec[user_name] updated.";
109 
110  /* Reread the user record as update verification */
111  $UserRec = $this->CreateUserRec($request, $UserRec['user_pk']);
112  } else {
113  $vars['message'] = $rv;
114  }
115  } else {
116  $NewUserpk = intval($request->get('newuser'));
117  $UserRec = empty($NewUserpk) ? $this->CreateUserRec($request, $user_pk) : $this->CreateUserRec($request, $NewUserpk);
118  }
119 
120  /* display the edit form with the requested user data */
121  $vars = array_merge($vars, $this->DisplayForm($UserRec, $SessionIsAdmin));
122  $vars['userId'] = $UserRec['user_pk'];
123  $vars['newToken'] = $newToken;
124  $vars['tokenList'] = $this->getListOfActiveTokens();
125  $vars['expiredTokenList'] = $this->getListOfExpiredTokens();
126  $vars['maxTokenDate'] = $this->authHelper->getMaxTokenValidity();
127  $vars['writeAccess'] = ($_SESSION[Auth::USER_LEVEL] >= 3);
128 
129  return $this->render('user_edit.html.twig', $this->mergeWithDefault($vars));
130  }
131 
139  private function DisplayForm($UserRec, $SessionIsAdmin)
140  {
141  $vars = array('isSessionAdmin' => $SessionIsAdmin,
142  'userId' => $UserRec['user_pk']);
143 
144  /* For Admins, get the list of all users
145  * For non-admins, only show themself
146  */
147  if ($SessionIsAdmin) {
148  $stmt = __METHOD__ . '.asSessionAdmin';
149  $sql = "SELECT * FROM users ORDER BY user_name";
150  $this->dbManager->prepare($stmt, $sql);
151  $res = $this->dbManager->execute($stmt);
152  $allUsers = array();
153  while ($row = $this->dbManager->fetchArray($res)) {
154  $allUsers[$row['user_pk']] = htmlentities($row['user_name']);
155  }
156  $this->dbManager->freeResult($res);
157  $vars['allUsers'] = $allUsers;
158  }
159 
160  $vars['userName'] = $UserRec['user_name'];
161  $vars['userDescription'] = $UserRec['user_desc'];
162  $vars['userEMail'] = $UserRec["user_email"];
163  $vars['eMailNotification'] = ($UserRec['email_notify'] == 'y');
164 
165  if ($SessionIsAdmin) {
166  $vars['allAccessLevels'] = array(
167  PLUGIN_DB_NONE => _("None (very basic, no database access)"),
168  PLUGIN_DB_READ => _("Read-only (read, but no writes or downloads)"),
169  PLUGIN_DB_WRITE => _("Read-Write (read, download, or edit information)"),
170  PLUGIN_DB_CADMIN => _("Clearing Administrator (read, download, edit information and edit decisions)"),
171  PLUGIN_DB_ADMIN => _("Full Administrator (all access including adding and deleting users)")
172  );
173  $vars['accessLevel'] = $UserRec['user_perm'];
174 
175  $SelectedFolderPk = $UserRec['root_folder_fk'];
176  $vars['folderListOption'] = FolderListOption($ParentFolder = -1, $Depth = 0, $IncludeTop = 1, $SelectedFolderPk);
177  }
178 
179  $vars['isBlankPassword'] = ($UserRec['_blank_pass'] == 'on');
180  $vars['agentSelector'] = AgentCheckBoxMake(-1, array("agent_unpack",
181  "agent_adj2nest", "wget_agent"), $UserRec['user_name']);
182  $vars['bucketPool'] = SelectBucketPool($UserRec["default_bucketpool_fk"]);
183  $vars['defaultGroupOption'] = $this->getUserGroupSelect($UserRec);
184 
185  return $vars;
186  }
187 
194  function UpdateUser($UserRec, $SessionIsAdmin)
195  {
196  global $PG_CONN;
197 
198  $Errors = "";
199 
200  /**** Validations ****/
201  /* Make sure we have a user_pk */
202  if (empty($UserRec['user_pk'])) {
203  $Errors .= "<li>" . _("Consistency error (User_pk missing). Please start over.") . "</li>";
204  }
205 
206  /* Make sure username looks valid */
207  if (empty($UserRec['user_name'])) {
208  $Errors .= "<li>" . _("Username must be specified.") . "</li>";
209  }
210 
211  /* Verify the user_name is not a duplicate */
212  $CheckUserRec = GetSingleRec("users", "WHERE user_name='$UserRec[user_name]'");
213  if ((!empty($CheckUserRec)) and ( $CheckUserRec['user_pk'] != $UserRec['user_pk'])) {
214  $Errors .= "<li>" . _("Username is not unique.") . "</li>";
215  }
216 
217  /* Make sure password matches */
218  if ($UserRec['_pass1'] != $UserRec['_pass2']) {
219  $Errors .= "<li>" . _("Passwords do not match.") . "</li>";
220  }
221 
222  /* Make sure email looks valid */
223  $Check = preg_replace("/[^a-zA-Z0-9@_.+-]/", "", $UserRec['user_email']);
224  if ($Check != $UserRec['user_email']) {
225  $Errors .= "<li>" . _("Invalid email address.") . "</li>";
226  }
227 
228  /* Did they specify a password and also request a blank password? */
229  if (!empty($UserRec['_blank_pass']) and ( !empty($UserRec['_pass1']) or ! empty($UserRec['_pass2']))) {
230  $Errors .= "<li>" . _("You cannot specify both a password and a blank password.") . "</li>";
231  }
232 
233  /* Check if the user is member of the group */
234  if (!empty($UserRec['group_fk'])) {
235  $group_map = $this->userDao->getUserGroupMap($UserRec['user_pk']);
236  if (array_search($UserRec['group_fk'], array_keys($group_map)) === false) {
237  $Errors .= "<li>" . _("User is not member of provided group.") .
238  "</li>";
239  }
240  }
241 
242  /* If we have any errors, return them */
243  if (!empty($Errors)) {
244  return _("Errors") . ":<ol>$Errors </ol>";
245  }
246 
247  /**** Update the users database record ****/
248  /* First remove user_pass and user_seed if the password wasn't changed. */
249  if (!empty($UserRec['_blank_pass']) ) {
250  $UserRec['user_seed'] = rand() . rand();
251  $UserRec['user_pass'] = sha1($UserRec['user_seed'] . "");
252  } else if (empty($UserRec['_pass1'])) { // password wasn't changed
253  unset( $UserRec['user_pass']);
254  unset( $UserRec['user_seed']);
255  }
256 
257  /* Build the sql update */
258  $sql = "UPDATE users SET ";
259  $first = true;
260  foreach ($UserRec as $key=>$val) {
261  if ($key[0] == '_' || $key == "user_pk") {
262  continue;
263  }
264  if (!$SessionIsAdmin && ($key == "user_perm" || $key == "root_folder_fk")) {
265  continue;
266  }
267 
268  if (!$first) {
269  $sql .= ",";
270  }
271  $sql .= "$key='" . pg_escape_string($val) . "'";
272  $first = false;
273  }
274  $sql .= " WHERE user_pk=$UserRec[user_pk]";
275  $result = pg_query($PG_CONN, $sql);
276  DBCheckResult($result, $sql, __FILE__, __LINE__);
277  pg_free_result($result);
278 
279  return (null);
280  } // UpdateUser()
281 
288  function GetUserRec($user_pk)
289  {
290  if (empty($user_pk)) {
291  throw new Exception("Invalid access. Your session has expired.",1);
292  }
293 
294  $UserRec = GetSingleRec("users", "WHERE user_pk=$user_pk");
295  if (empty($UserRec)) {
296  throw new Exception("Invalid user. ",1);
297  }
298  return $UserRec;
299  }
300 
306  private function IsSessionAdmin($UserRec)
307  {
308  return ($UserRec['user_perm'] == PLUGIN_DB_ADMIN);
309  }
310 
320  function CreateUserRec(Request $request, $user_pk="")
321  {
322  /* If a $user_pk was given, use it to read the user db record.
323  * Otherwise, use the form data.
324  */
325  if (!empty($user_pk)) {
326  $UserRec = $this->GetUserRec($user_pk);
327  $UserRec['_pass1'] = "";
328  $UserRec['_pass2'] = "";
329  $UserRec['_blank_pass'] = ($UserRec['user_pass'] == sha1($UserRec['user_seed'] . "")) ? "on" : "";
330  } else {
331  $UserRec = array();
332  $UserRec['user_pk'] = intval($request->get('user_pk'));
333  $UserRec['user_name'] = stripslashes($request->get('user_name'));
334  $UserRec['root_folder_fk'] = intval($request->get('root_folder_fk'));
335  $UserRec['user_desc'] = stripslashes($request->get('user_desc'));
336  $UserRec['group_fk'] = intval($request->get('default_group_fk'));
337 
338  $UserRec['_pass1'] = stripslashes($request->get('_pass1'));
339  $UserRec['_pass2'] = stripslashes($request->get('_pass2'));
340  if (!empty($UserRec['_pass1'])) {
341  $UserRec['user_seed'] = rand() . rand();
342  $UserRec['user_pass'] = sha1($UserRec['user_seed'] . $UserRec['_pass1']);
343  $UserRec['_blank_pass'] = "";
344  } else {
345  $UserRec['user_pass'] = "";
346  $UserRec['_blank_pass'] = stripslashes($request->get("_blank_pass"));
347  if (empty($UserRec['_blank_pass'])) { // check for blank password
348  // get the stored seed
349  $StoredUserRec = $this->GetUserRec($UserRec['user_pk']);
350  $UserRec['_blank_pass'] = ($UserRec['user_pass'] == sha1($StoredUserRec['user_seed'] . "")) ? "on" : "";
351  }
352  }
353 
354  $UserRec['user_perm'] = intval($request->get('user_perm'));
355  $UserRec['user_email'] = stripslashes($request->get('user_email'));
356  $UserRec['email_notify'] = stripslashes($request->get('email_notify'));
357  if (!empty($UserRec['email_notify'])) {
358  $UserRec['email_notify'] = 'y';
359  }
360  $UserRec['user_agent_list'] = userAgents();
361  $UserRec['default_bucketpool_fk'] = intval($request->get("default_bucketpool_fk"));
362  }
363  return $UserRec;
364  }
365 
376  private function generateNewToken(Request $request)
377  {
378  global $container;
379 
380  $user_pk = Auth::getUserId();
381  $tokenName = GetParm('pat_name', PARM_STRING);
382  $tokenExpiry = GetParm('pat_expiry', PARM_STRING);
383  if ($_SESSION[Auth::USER_LEVEL] < 3) {
384  $tokenScope = 'r';
385  } else {
386  $tokenScope = GetParm('pat_scope', PARM_STRING);
387  }
388  $tokenScope = array_search($tokenScope, RestHelper::SCOPE_DB_MAP);
389  $restHelper = $container->get('helper.restHelper');
390  $isTokenRequestValid = $restHelper->validateTokenRequest($tokenExpiry,
391  $tokenName, $tokenScope);
392 
393  if ($isTokenRequestValid !== true) {
394  throw new \UnexpectedValueException($isTokenRequestValid->getMessage());
395  } else {
396  $restDbHelper = $container->get('helper.dbHelper');
397  $key = bin2hex(
398  openssl_random_pseudo_bytes(RestHelper::TOKEN_KEY_LENGTH / 2));
399  try {
400  $jti = $restDbHelper->insertNewTokenKey($user_pk, $tokenExpiry,
401  RestHelper::SCOPE_DB_MAP[$tokenScope], $tokenName, $key);
402  } catch (DuplicateTokenKeyException $e) {
403  // Key already exists, try again.
404  $key = bin2hex(
405  openssl_random_pseudo_bytes(RestHelper::TOKEN_KEY_LENGTH / 2));
406  try {
407  $jti = $restDbHelper->insertNewTokenKey($user_pk, $tokenExpiry,
408  RestHelper::SCOPE_DB_MAP[$tokenScope], $tokenName, $key);
409  } catch (DuplicateTokenKeyException $e) {
410  // New key also failed, give up!
411  throw new DuplicateTokenKeyException("Please try again later.");
412  }
413  } catch (DuplicateTokenNameException $e) {
414  throw new \UnexpectedValueException($e->getMessage());
415  }
416  return $this->authHelper->generateJwtToken($tokenExpiry,
417  $jti['created_on'], $jti['jti'], $tokenScope, $key);
418  }
419  }
420 
428  private function getListOfActiveTokens()
429  {
430  global $container;
431 
432  $user_pk = Auth::getUserId();
433  $sql = "SELECT pat_pk, user_fk, expire_on, token_scope, token_name, created_on, active " .
434  "FROM personal_access_tokens " .
435  "WHERE user_fk = $1 AND active = true;";
436  $rows = $this->dbManager->getRows($sql, [$user_pk],
437  __METHOD__ . ".getActiveTokens");
438  $response = [];
439  foreach ($rows as $row) {
440  if ($this->authHelper->isTokenActive($row, $row["pat_pk"]) === true) {
441  $entry = [
442  "id" => $row["pat_pk"] . "." . $user_pk,
443  "name" => $row["token_name"],
444  "created" => $row["created_on"],
445  "expire" => $row["expire_on"],
446  "scope" => $row["token_scope"]
447  ];
448  $response[] = $entry;
449  }
450  }
451  array_multisort(array_column($response, "created"), SORT_ASC, $response);
452  return $response;
453  }
454 
459  private function getListOfExpiredTokens()
460  {
461  global $container;
462 
463  $user_pk = Auth::getUserId();
464  $sql = "SELECT pat_pk, user_fk, expire_on, token_scope, token_name, created_on " .
465  "FROM personal_access_tokens " .
466  "WHERE user_fk = $1 AND active = false;";
467  $rows = $this->dbManager->getRows($sql, [$user_pk],
468  __METHOD__ . ".getActiveTokens");
469  $response = [];
470  foreach ($rows as $row) {
471  $entry = [
472  "id" => $row["pat_pk"] . "." . $user_pk,
473  "name" => $row["token_name"],
474  "created" => $row["created_on"],
475  "expire" => $row["expire_on"],
476  "scope" => $row["token_scope"]
477  ];
478  $response[] = $entry;
479  }
480  array_multisort(array_column($response, "created"), SORT_ASC, $response);
481  return $response;
482  }
483 
489  private function getUserGroupSelect($userRec)
490  {
491  $groups = $this->userDao->getUserGroupMap($userRec['user_pk']);
492  $userDefaults = $this->userDao->getUserAndDefaultGroupByUserName($userRec['user_name']);
493  $options = "";
494  foreach ($groups as $groupId => $groupName) {
495  $options .= "<option value='$groupId' ";
496  if ($groupId == $userDefaults['group_fk']) {
497  $options .= "selected='selected'";
498  }
499  $options .= ">$groupName</option>";
500  }
501  return $options;
502  }
503 }
504 
505 register_plugin(new UserEditPage());
Exception when a token has duplicate name for same user.
SelectBucketPool($selected, $active='Y')
Return a select list containing all the active bucketpool&#39;s.
Traceback_uri()
Get the URI without query to this location.
userAgents()
Read the UI form and format the user selected agents into a comma separated list. ...
generateNewToken(Request $request)
Definition: user-edit.php:376
#define PLUGIN_DB_ADMIN
Plugin requires admin level permission on DB.
Definition: libfossology.h:51
IsSessionAdmin($UserRec)
Determine if the session user is an admin.
Definition: user-edit.php:306
FolderListOption($ParentFolder, $Depth, $IncludeTop=1, $SelectId=-1, $linkParent=false, $OldParent=0)
Create the folder tree, using OPTION tags.
UpdateUser($UserRec, $SessionIsAdmin)
Validate and update the user data.
Definition: user-edit.php:194
render($templateName, $vars=null, $headers=null)
AgentCheckBoxMake($upload_pk, $SkipAgents=array(), $specified_username="")
Generate a checkbox list of available agents.
GetSingleRec($Table, $Where="")
Retrieve a single database record.
Definition: common-db.php:102
getListOfActiveTokens()
Get a list of active tokens for current user.
Definition: user-edit.php:428
GetUserRec($user_pk)
Get a user record.
Definition: user-edit.php:288
#define PLUGIN_DB_READ
Plugin requires read permission on DB.
Definition: libfossology.h:49
Exception when a token has duplicate key for same user.
getUserGroupSelect($userRec)
Definition: user-edit.php:489
GetParm($parameterName, $parameterType)
This function will retrieve the variables and check data types.
Definition: common-parm.php:57
handle(Request $request)
Allow user to change their account settings (users db table).
Definition: user-edit.php:71
const PARM_STRING
Definition: common-parm.php:29
CreateUserRec(Request $request, $user_pk="")
Create a user record.
Definition: user-edit.php:320
#define PLUGIN_DB_NONE
Plugin requires no DB permission.
Definition: libfossology.h:48
DisplayForm($UserRec, $SessionIsAdmin)
Display the user record edit form.
Definition: user-edit.php:139
#define PLUGIN_DB_WRITE
Plugin requires write permission on DB.
Definition: libfossology.h:50
fo_dbManager * dbManager
fo_dbManager object
Definition: process.c:28
#define PERM_READ
Read-only permission.
Definition: libfossology.h:44
foreach($Options as $Option=> $OptVal) if(0==$reference_flag &&0==$nomos_flag) $PG_CONN
DBCheckResult($result, $sql, $filenm, $lineno)
Check the postgres result for unexpected errors. If found, treat them as fatal.
Definition: common-db.php:198
getListOfExpiredTokens()
Definition: user-edit.php:459