FOSSology  4.4.0
Open Source License Compliance by Open Source Software
core-auth.php
1 <?php
2 /*
3  SPDX-FileCopyrightText: © 2008-2013 Hewlett-Packard Development Company, L.P.
4  SPDX-FileCopyrightText: © 2015-2016, 2021 Siemens AG
5  SPDX-FileCopyrightText: © 2020 Robert Bosch GmbH
6  SPDX-FileCopyrightText: © Dineshkumar Devarajan <Devarajan.Dineshkumar@in.bosch.com>
7  SPDX-FileCopyrightText: © 2021-2022 Orange
8  Contributors: Piotr Pszczola, Bartlomiej Drozdz
9 
10  SPDX-License-Identifier: GPL-2.0-only
11 */
12 
17 use Symfony\Component\HttpFoundation\Session\Session;
18 use Symfony\Component\HttpFoundation\RedirectResponse;
19 use League\OAuth2\Client\Provider\GenericProvider;
20 
21 define("TITLE_CORE_AUTH", _("Login"));
22 
23 class core_auth extends FO_Plugin
24 {
25  public static $origReferer;
27  private $dbManager;
29  private $userDao;
31  private $session;
33  private $authExternal;
34 
35  function __construct()
36  {
37  $this->Name = "auth";
38  $this->Title = TITLE_CORE_AUTH;
39  $this->PluginLevel = 1000; /* make this run first! */
40  $this->LoginFlag = 0;
41  parent::__construct();
42 
43  global $container;
44  $this->dbManager = $container->get("db.manager");
45  $this->userDao = $container->get('dao.user');
46  $this->session = $container->get('session');
47  $this->authExternal = auth_external_check();
48  }
49 
53  public function staticValue()
54  {
55  return self::$origReferer;
56  }
57 
65  function Install()
66  {
67  return $this->userDao->updateUserTable();
68  }
69 
74  function PostInitialize()
75  {
76  global $SysConf;
77 
78  /* if Site Minder enabled core-auth will be disabled*/
79  if (siteminder_check() != -1) {
80  return (0);
81  }
82 
83  if (!$this->session->isStarted()) {
84  $this->session->setName('Login');
85  $this->session->start();
86  }
87 
88  //--------- Authentification external connection for auto-login-----------
89  if ($this->authExternal !== false && $this->authExternal['useAuthExternal']) {
90  $this->checkUsernameAndPassword($this->authExternal['loginAuthExternal'], $this->authExternal['passwordAuthExternal']);
91  }
92 
93  if (array_key_exists('selectMemberGroup', $_POST)) {
94  $selectedGroupId = intval($_POST['selectMemberGroup']);
95  $this->userDao->setDefaultGroupMembership(intval($_SESSION[Auth::USER_ID]), $selectedGroupId);
96  $_SESSION[Auth::GROUP_ID] = $selectedGroupId;
97  $this->session->set(Auth::GROUP_ID, $selectedGroupId);
98  $SysConf['auth'][Auth::GROUP_ID] = $selectedGroupId;
99  }
100 
101  if (array_key_exists(Auth::USER_ID, $_SESSION)) {
102  $SysConf['auth'][Auth::USER_ID] = $_SESSION[Auth::USER_ID];
103  }
104  if (array_key_exists(Auth::GROUP_ID, $_SESSION)) {
105  $SysConf['auth'][Auth::GROUP_ID] = $_SESSION[Auth::GROUP_ID];
106  }
107 
108  $Now = time();
109  /* Logins older than 60 secs/min * 480 min = 8 hr are auto-logout */
110  if (!empty($_SESSION['time']) && @$_SESSION['time'] + (60 * 480) < $Now) {
111  $this->updateSession("");
112  }
113 
114  $_SESSION['time'] = $Now;
115  if (empty($_SESSION['ip'])) {
116  $_SESSION['ip'] = $this->getIP();
117  } else if ((@$_SESSION['checkip'] == 1) && (@$_SESSION['ip'] != $this->getIP())) {
118  /* Sessions are not transferable. */
119  $this->updateSession("", true);
120  $_SESSION['ip'] = $this->getIP();
121  }
122 
123  if (@$_SESSION[Auth::USER_NAME]) {
124  /* Recheck the user in case he is suddenly blocked or changed. */
125  if (empty($_SESSION['time_check'])) {
126  $_SESSION['time_check'] = time() + (480 * 60);
127  }
128  if (time() >= @$_SESSION['time_check']) {
129  $userName = @$_SESSION[Auth::USER_NAME];
130  $row = $this->userDao->getUserAndDefaultGroupByUserName($userName, @$_SESSION['oauthCheck']);
131  /* Check for instant logouts */
132  if (empty($row['user_pass'])) {
133  $row = "";
134  }
135  $this->updateSession($row);
136  }
137  } else {
138  $this->updateSession("", true);
139  }
140 
141  /* Disable all plugins with >= level access */
142  plugin_disable($_SESSION[Auth::USER_LEVEL]);
143  $this->State = PLUGIN_STATE_READY;
144  } // GetIP()
145 
152  function updateSession($userRow, $oauth=false)
153  {
154  global $SysConf;
155 
156  if (empty($userRow)) {
157  $username = 'Default User';
158  $userRow = $this->userDao->getUserAndDefaultGroupByUserName($username);
159  }
160 
161  $_SESSION[Auth::USER_ID] = $userRow['user_pk'];
162  $SysConf['auth'][Auth::USER_ID] = $userRow['user_pk'];
163  $this->session->set(Auth::USER_ID, $userRow['user_pk']);
164  $_SESSION[Auth::USER_NAME] = $userRow['user_name'];
165  $this->session->set(Auth::USER_NAME, $userRow['user_name']);
166  $_SESSION['Folder'] = $userRow['root_folder_fk'];
167  $_SESSION[Auth::USER_LEVEL] = $userRow['user_perm'];
168  $this->session->set(Auth::USER_LEVEL, $userRow['user_perm']);
169  $_SESSION['UserEmail'] = $userRow['user_email'];
170  $_SESSION['UserEnote'] = $userRow['email_notify'];
171  $_SESSION[Auth::GROUP_ID] = $userRow['group_fk'];
172  $SysConf['auth'][Auth::GROUP_ID] = $userRow['group_fk'];
173  $this->session->set(Auth::GROUP_ID, $userRow['group_fk']);
174  $_SESSION['GroupName'] = $userRow['group_name'];
175  if (!$oauth) {
176  $_SESSION['oauthCheck'] = $userRow['oauth'];
177  }
178  if (array_key_exists(Menu::BANNER_COOKIE, $_COOKIE)) {
179  $_COOKIE[Menu::BANNER_COOKIE] = 0;
180  }
181  setcookie(Menu::BANNER_COOKIE, "", time() - 3600);
182  }
183 
190  function getIP()
191  {
192  /* NOTE: This can be easily defeated wtih fake HTTP headers. */
193  $Vars = array('HTTP_CLIENT_IP', 'HTTP_X_COMING_FROM', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED');
194  foreach ($Vars as $V) {
195  if (!empty($_SERVER[$V])) {
196  return ($_SERVER[$V]);
197  }
198  }
199  return (@$_SERVER['REMOTE_ADDR']);
200  }
201 
205  public function Output()
206  {
207  global $SysConf;
208 
209  $this->vars['loginProvider'] = "password";
210  if (array_key_exists('AUTHENTICATION', $SysConf) &&
211  array_key_exists('provider', $SysConf['AUTHENTICATION'])) {
212  $this->vars['loginProvider'] = $SysConf['AUTHENTICATION']['provider'];
213  }
214 
215  $userName = GetParm("username", PARM_TEXT);
216  $password = GetParm("password", PARM_TEXT);
217  $timezone = GetParm("timezone", PARM_TEXT);
218  if (empty($timezone) || strpos($timezone,"Unknown") == true) {
219  $timezone = date_default_timezone_get();
220  }
221  $_SESSION['timezone'] = $timezone;
222  $referrer = GetParm("HTTP_REFERER", PARM_TEXT);
223  $getEmail = "";
224  $providerCheck = GetParm("providerCheck", PARM_TEXT);
225  $proxy = "";
226  if (array_key_exists('http_proxy', $SysConf['FOSSOLOGY']) &&
227  ! empty($SysConf['FOSSOLOGY']['http_proxy'])) {
228  $proxy = $SysConf['FOSSOLOGY']['http_proxy'];
229  }
230  if (array_key_exists('https_proxy', $SysConf['FOSSOLOGY']) &&
231  ! empty($SysConf['FOSSOLOGY']['https_proxy'])) {
232  $proxy = $SysConf['FOSSOLOGY']['https_proxy'];
233  }
234 
235  if (! empty($providerCheck)) {
236  $provider = new GenericProvider([
237  "clientId" => $SysConf['SYSCONFIG']['OidcAppId'],
238  "clientSecret" => $SysConf['SYSCONFIG']['OidcSecret'],
239  "redirectUri" => $SysConf['SYSCONFIG']['OidcRedirectURL'],
240  "urlAuthorize" => $SysConf['SYSCONFIG']['OidcAuthorizeURL'],
241  "urlAccessToken" => $SysConf['SYSCONFIG']['OidcAccessTokenURL'],
242  "urlResourceOwnerDetails" => $SysConf['SYSCONFIG']['OidcResourceURL'],
243  "proxy" => $proxy
244  ]);
245  $authorizationUrl = $provider->getAuthorizationUrl([
246  "scope" => ['email openid']
247  ]);
248  $_SESSION['oauth2state'] = $provider->getState();
249  $_SESSION['HTTP_REFERER'] = $referrer;
250  header('Location: ' . $authorizationUrl);
251  exit;
252  }
253 
254  if (empty($referrer) && array_key_exists('HTTP_REFERER', $_SESSION)) {
255  $referrer = $_SESSION['HTTP_REFERER'];
256  } else if (empty($referrer)) {
257  $referrer = GetArrayVal('HTTP_REFERER', $_SERVER);
258  }
259 
260  if (array_key_exists("oauthemail", $_SESSION)) {
261  $getEmail = $_SESSION['oauthemail'];
262  unset($_SESSION['oauthemail']);
263  }
264  $referrerQuery = parse_url($referrer,PHP_URL_QUERY);
265  if ($referrerQuery) {
266  $params = array();
267  parse_str($referrerQuery,$params);
268  if (array_key_exists('mod', $params) && $params['mod'] == $this->Name) {
269  $referrer = Traceback_uri();
270  }
271  }
272  if (!empty($getEmail) && empty($userName)) {
273  $validLogin = $this->checkUsernameAndPassword($getEmail, "", true);
274  } else {
275  $validLogin = $this->checkUsernameAndPassword($userName, $password);
276  }
277  if ($validLogin) {
278  if (empty($referrer)) {
279  if (plugin_find_id('browse') < 0) {
280  $newReferrer = Traceback_uri() . '?mod=' . 'browse' . '&oauth=true';
281  }
282  return new RedirectResponse($newReferrer);
283  } else {
284  return new RedirectResponse($referrer);
285  }
286  }
287 
288  $initPluginId = plugin_find_id("init");
289  if ($initPluginId >= 0) {
290  global $Plugins;
291  $this->vars['info'] = $Plugins[$initPluginId]->infoFirstTimeUsage();
292  }
293 
294  if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != "off") {
295  $this->vars['protocol'] = "HTTPS";
296  } else {
297  $this->vars['protocol'] = preg_replace("@/.*@", "", @$_SERVER['SERVER_PROTOCOL']);
298  }
299 
300  $this->vars['referrer'] = $referrer;
301  $this->vars['loginFailure'] = !empty($userName) || !empty($password);
302  if (!empty($userName) && $userName!='Default User') {
303  $this->vars['userName'] = $userName;
304  }
305  if (!empty($SysConf['SYSCONFIG']['OidcAppName'])) {
306  $this->vars['providerExist'] = $SysConf['SYSCONFIG']['OidcAppName'];
307  } else {
308  $this->vars['providerExist'] = 0;
309  }
310  return $this->render('login.html.twig',$this->vars);
311  }
312 
316  function OutputOpen()
317  {
318  if (array_key_exists('User', $_SESSION) && $_SESSION['User'] != "Default User") {
319  global $SysConf;
320  if (!empty($SysConf['SYSCONFIG']['OidcLogoutURL'])) {
321  $uri = $SysConf['SYSCONFIG']['OidcLogoutURL'];
322  } else {
323  $uri = Traceback_uri();
324  }
325  $this->updateSession("");
326  $_SESSION['oauth2state'] = "";
327  header("Location: $uri");
328  exit;
329  }
330  parent::OutputOpen();
331  }
332 
341  function checkUsernameAndPassword($userName, $password, $oauth=false,
342  $isRest=false)
343  {
344  global $SysConf;
345 
346  $user_exists = true;
347  $options = array('cost' => 10);
348 
349  /* Check the user for external authentication */
350  if ($this->authExternal !== false && $this->authExternal['useAuthExternal']) {
351  $username = $this->authExternal['loginAuthExternal'];
352  /* checking if user exists */
353  try {
354  $this->userDao->getUserAndDefaultGroupByUserName($username);
355  } catch (Exception $e) {
356  $user_exists=false;
357  }
358  if (! $user_exists && $GLOBALS['SysConf']['EXT_AUTH']['CONF_EXT_AUTH_NEW_USER_AUTO_CREATE']) {
359  /* If user does not exist then we create it */
360  $User = trim(str_replace("'", "''", $this->authExternal['loginAuthExternal']));
361  $Pass = $this->authExternal['passwordAuthExternal'] ;
362  $Hash = password_hash($Pass, PASSWORD_DEFAULT, $options);
363  $Desc = $this->authExternal['descriptionAuthExternal'];
364  $Perm = 3;
365  $Folder = 1;
366  $Email_notify = "y";
367  $Email = $this->authExternal['emailAuthExternal'];
368  /* Set default list of agents when a new user is created */
369  $agentList = $GLOBALS['SysConf']['EXT_AUTH']['CONF_EXT_AUTH_NEW_USER_AGENT_LIST'];
370  add_user($User, $Desc, $Hash, $Perm, $Email, $Email_notify,
371  $GLOBALS['SysConf']['SYSCONFIG']['UploadVisibility'], $agentList, $Folder);
372  }
373  }
374 
375  $authProvider = "password";
376  if (array_key_exists('AUTHENTICATION', $SysConf) &&
377  array_key_exists('provider', $SysConf['AUTHENTICATION'])) {
378  $authProvider = $SysConf['AUTHENTICATION']['provider'];
379  }
380 
381  if (empty($userName) || $userName == 'Default User') {
382  return false;
383  }
384  try {
385  $row = $this->userDao->getUserAndDefaultGroupByUserName($userName, $oauth);
386  } catch (Exception $e) {
387  return false;
388  }
389 
390  if (empty($row['user_name'])) {
391  return false;
392  }
393 
394  if (! $oauth) {
395  if (!$isRest && $authProvider != "password") {
396  // Password authentication is not allowed and request if not from REST
397  // API
398  return false;
399  }
400  /* Check the password -- only if a password exists */
401  if (! empty($row['user_pass'])) {
402  $options = array('cost' => 10);
403  /* Check if the password matches by password_verify */
404  if (password_verify($password, $row['user_pass'])) {
405  if (password_needs_rehash($row['user_pass'], PASSWORD_DEFAULT, $options)) {
406  $newHash = password_hash($password, PASSWORD_DEFAULT, $options);
407  /* Update old hash with new hash */
408  update_password_hash($userName, $newHash);
409  }
410  } else if (! empty($row['user_seed'])) {
411  $passwordHash = sha1($row['user_seed'] . $password);
412  /* If verify with new hash fails check with the old hash */
413  if (strcmp($passwordHash, $row['user_pass']) == 0) {
414  $newHash = password_hash($password, PASSWORD_DEFAULT, $options);
415  /* Update old hash with new hash */
416  update_password_hash($userName, $newHash);
417  } else {
418  return false;
419  }
420  }
421  } else if (!empty($password)) {
422  /* empty password required */
423  return false;
424  }
425  }
426 
427  if (!$this->userDao->isUserActive($userName)) {
428  /* user not active */
429  $this->vars['userInactive'] = true;
430  return false;
431  }
432 
433  /* If you make it here, then username and password were good! */
434  $this->updateSession($row);
435 
436  $_SESSION['time_check'] = time() + (480 * 60);
437  /* No specified permission means ALL permission */
438  if ("X" . $row['user_perm'] == "X") {
439  $_SESSION[Auth::USER_LEVEL] = PLUGIN_DB_ADMIN;
440  } else {
441  $_SESSION[Auth::USER_LEVEL] = $row['user_perm'];
442  }
443  $_SESSION['checkip'] = GetParm("checkip", PARM_STRING);
444  /* Check for the no-popup flag */
445  if (GetParm("nopopup", PARM_INTEGER) == 1) {
446  $_SESSION['NoPopup'] = 1;
447  } else {
448  $_SESSION['NoPopup'] = 0;
449  }
450 
451  $this->userDao->updateUserLastConnection($row['user_pk']);
452 
453  return true;
454  }
455 }
456 
457 $NewPlugin = new core_auth();
This is the Plugin class. All plugins should:
Definition: FO_Plugin.php:57
render($templateName, $vars=null)
Definition: FO_Plugin.php:434
Contains the constants and helpers for authentication of user.
Definition: Auth.php:24
Definition: state.hpp:16
Install()
Only used during installation. This may be called multiple times. Used to ensure the DB has the right...
Definition: core-auth.php:65
getIP()
Retrieve the user's IP address. Some proxy systems pass forwarded IP address info....
Definition: core-auth.php:190
Output()
This is only called when the user logs out.
Definition: core-auth.php:205
staticValue()
getter to retreive value of static var
Definition: core-auth.php:53
checkUsernameAndPassword($userName, $password, $oauth=false, $isRest=false)
Definition: core-auth.php:341
OutputOpen()
perform logout
Definition: core-auth.php:316
PostInitialize()
This is where the magic for Authentication happens.
Definition: core-auth.php:74
updateSession($userRow, $oauth=false)
Set $_SESSION and $SysConf user variables.
Definition: core-auth.php:152
__construct()
base constructor. Most plugins will just use this
Definition: core-auth.php:35
siteminder_check()
Check if SiteMinder is enabled.
Definition: common-auth.php:22
auth_external_check()
Check if the external HTTP authentication is enabled. The mapping variables should be configured in f...
Definition: common-auth.php:38
Traceback_uri()
Get the URI without query to this location.
Definition: common-parm.php:97
const PARM_TEXT
Definition: common-parm.php:20
const PARM_INTEGER
Definition: common-parm.php:14
const PARM_STRING
Definition: common-parm.php:18
GetParm($parameterName, $parameterType)
This function will retrieve the variables and check data types.
Definition: common-parm.php:46
GetArrayVal($Key, $Arr)
Get the value from a array(map)
Definition: common-ui.php:157
update_password_hash($User, $Hash)
Update user password hash.
add_user($User, $Desc, $Hash, $Perm, $Email, $Email_notify, $Upload_visibility, $agentList, $Folder, $default_bucketpool_fk='')
Add a user.
char * trim(char *ptext)
Trimming whitespace.
Definition: fossconfig.c:690
#define PLUGIN_DB_ADMIN
Plugin requires admin level permission on DB.
Definition: libfossology.h:39
fo_dbManager * dbManager
fo_dbManager object
Definition: process.c:16