1<?php 2 3/** 4* 5* User class to work with current user, authentication etc 6* 7*/ 8class User extends Common_functions { 9 10 11 /** 12 * Current username 13 * 14 * @var string 15 */ 16 public $username; 17 18 /** 19 * flag if user is authenticated 20 * 21 * (default value: false) 22 * 23 * @var bool 24 */ 25 protected $authenticated = false; 26 27 /** 28 * timeout flag - is timeout reached 29 * 30 * (default value: false) 31 * 32 * @var bool 33 */ 34 protected $timeout = false; 35 36 /** 37 * user details 38 * 39 * (default value: null) 40 * 41 * @var object 42 */ 43 public $user = null; 44 45 /** 46 * flag if user is admin 47 * 48 * (default value: false) 49 * 50 * @var bool 51 */ 52 protected $isadmin = false; 53 54 /** 55 * limit for IP block - after how many attampts user is blocked 56 * 57 * (default value: 5) 58 * 59 * @var int 60 */ 61 public $blocklimit = 5; 62 63 /** 64 * authentication method id for user 65 * 66 * (default value: 1) 67 * 68 * @var int 69 */ 70 private $authmethodid = 1; 71 72 /** 73 * authentication method type 74 * 75 * (default value: "local") 76 * 77 * @var string 78 */ 79 private $authmethodtype = "local"; 80 81 /** 82 * ldap is used flag 83 * 84 * (default value: false) 85 * 86 * @var bool 87 */ 88 private $ldap = false; 89 90 /** 91 * Users IP address 92 * 93 * @var mixed 94 */ 95 private $ip; 96 97 /** 98 * Set allowed themes 99 * 100 * @var array 101 */ 102 public $themes = array("white", "dark"); 103 104 /** 105 * (json) parameters for authentication 106 * 107 * @var mixed 108 */ 109 protected $authmethodparams; 110 111 /** 112 * Cryptographic functions 113 * @var Crypto 114 */ 115 public $Crypto; 116 117 118 /** 119 * __construct function. 120 * 121 * @access public 122 * @param Database_PDO $database 123 * @param bool $api (default: false) 124 */ 125 public function __construct (Database_PDO $database, $api = false) { 126 parent::__construct(); 127 128 # Save database object 129 $this->Database = $database; 130 # set api 131 $this->api = $api; 132 # initialize Result 133 $this->Result = new Result (); 134 135 # get settings 136 $this->get_settings (); 137 138 # Log object 139 $this->Log = new Logging ($this->Database, $this->settings); 140 141 # initialize Crypto 142 $this->Crypto = new Crypto (); 143 144 # register new session 145 $this->register_session (); 146 # check timeut 147 $this->check_timeout (); 148 # set authenticated flag 149 $this->is_authenticated (); 150 # get users IP address 151 $this->block_get_ip (); 152 # set theme 153 $this->set_user_theme (); 154 } 155 156 157 158 159 160 161 162 163 164 165 /** 166 * @session management functions 167 * ------------------------------ 168 */ 169 170 /** 171 * registers new session 172 * 173 * @access private 174 * @return void 175 */ 176 private function register_session () { 177 // not for api 178 if ($this->api !== true) { 179 if (@$_SESSION===NULL && !isset($_SESSION)) { 180 //set session name 181 $this->set_session_name(); 182 //set default params 183 $this->set_session_ini_params (); 184 //register session 185 $this->start_session (); 186 } 187 } 188 } 189 190 /** 191 * Start session - files or use database handler 192 * @method start_session 193 * @return [type] 194 */ 195 private function start_session () { 196 // check if database should be set for sessions 197 if (Config::get('session_storage') == "database") { 198 new Session_db ($this->Database); 199 } 200 // local 201 else { 202 session_start (); 203 } 204 205 // Re-set HTTP session cookie with mandatory samesite=Strict attribute. 206 // php native support for samesite is >=php7.3 207 208 $session_name = session_name(); 209 $session_id = session_id(); 210 $session_lifetime = ini_get('session.cookie_lifetime'); 211 $session_use_cookies = ini_get('session.use_cookies'); 212 213 if ($session_use_cookies && is_string($session_id) && strlen($session_id) > 0) 214 setcookie_samesite($session_name, $session_id, $session_lifetime, true); 215 } 216 217 /** 218 * destroys session 219 * 220 * @access public 221 * @return void 222 */ 223 public function destroy_session () { 224 session_destroy(); 225 } 226 227 /** 228 * sets session name if specified in config file 229 * 230 * @access private 231 * @return void 232 */ 233 private function set_session_name () { 234 $sessname = Config::get('phpsessname', 'phpipam'); 235 // check old name 236 $old_name = session_name(); 237 if ($sessname != $old_name) { 238 // save 239 session_name($sessname); 240 } 241 } 242 243 /** 244 * Default session parameters for phpipam - MAX 245 * 246 * gc_maxlifetime : time for server to keep data parameters for (at least 24 hours) 247 * cookie_lifetime : time for client browser to keep cookies 248 * 249 * @access private 250 * @return void 251 */ 252 private function set_session_ini_params () { 253 if(!isset($_SESSION)) { 254 ini_set('session.gc_maxlifetime', 86400); 255 ini_set('session.cookie_lifetime', 86400); 256 } 257 } 258 259 /** 260 * saves parameters to session after authentication succeeds 261 * 262 * @access private 263 * @return void 264 */ 265 private function write_session_parameters () { 266 // not for api 267 if ($this->api !== true) { 268 // Avoid session ID fixation attacks 269 session_regenerate_id(true); 270 271 $_SESSION['ipamusername'] = $this->user->username; 272 $_SESSION['ipamlanguage'] = $this->fetch_lang_details (); 273 $_SESSION['lastactive'] = time(); 274 // 2fa required ? 275 if (isset($this->twofa) && $this->twofa) { 276 $_SESSION['2fa_required'] = true; 277 } 278 } 279 } 280 281 /** 282 * Update users language 283 * 284 * @access public 285 * @return void 286 */ 287 public function update_session_language () { 288 // not for api 289 if ($this->api !== true) { 290 # update user object 291 $this->fetch_user_details ($this->username, true); 292 $_SESSION['ipamlanguage'] = $this->fetch_lang_details (); 293 } 294 } 295 296 /** 297 * Checks if user is authenticated - session is set 298 * 299 * @access public 300 * @return bool 301 */ 302 public function is_authenticated () { 303 # if checked for subpages first check if $user is array 304 if(!is_array($this->user)) { 305 if( strlen(@$_SESSION['ipamusername'])>0 ) { 306 # save username 307 $this->username = $_SESSION['ipamusername']; 308 # check for timeout 309 if($this->timeout === true) { 310 $this->authenticated = false; 311 } 312 else { 313 # fetch user profile and save it 314 $this->fetch_user_details ($this->username); 315 316 $this->authenticated = true; 317 $this->reset_inactivity_time(); 318 $this->update_activity_time (); 319 # bind language 320 $this->set_ui_language(); 321 } 322 } 323 } 324 325 # return 326 return $this->authenticated; 327 } 328 329 /** 330 * Check if 2fa is required for user 331 * @method twofa_required 332 * @return bool 333 */ 334 public function twofa_required () { 335 return isset($_SESSION['2fa_required']) ? true : false; 336 } 337 338 /** 339 * Checks if current user is admin or not 340 * 341 * @access public 342 * @param bool $die (default: true) 343 * @return string|bool 344 */ 345 public function is_admin ($die = true) { 346 if($this->isadmin) { return true; } 347 else { 348 if($die) { $this->Result->show("danger", _('Administrator level privileges required'), true); } 349 else { return false; } 350 } 351 } 352 353 /** 354 * checks if user is authenticated, if not redirects to login page 355 * 356 * @access public 357 * @param bool $redirect (default: true) 358 * @return string|false 359 */ 360 public function check_user_session ($redirect = true, $ignore_2fa = false) { 361 # set url 362 $url = $this->createURL(); 363 364 # not authenticated 365 if($this->authenticated===false) { 366 # error print for AJAX 367 if(@$_SERVER['HTTP_X_REQUESTED_WITH'] == "XMLHttpRequest") { 368 # for AJAX always check origin 369 $this->check_referrer (); 370 # kill session 371 $this->destroy_session (); 372 # error 373 $this->Result->show("danger", _('Please login first')."!<hr><a class='btn btn-sm btn-default' href='".$url.create_link ("login")."'>"._('Login')."</a>", true, true); 374 die(); 375 } 376 # timeout 377 elseif ($this->timeout) { 378 # set redirect cookie 379 $this->set_redirect_cookie (); 380 # redirect 381 if ($redirect) 382 header("Location:".$url.create_link ("login","timeout")); 383 die(); 384 } 385 else { 386 # set redirect cookie 387 $this->set_redirect_cookie (); 388 # redirect 389 if ($redirect) 390 header("Location:".$url.create_link ("login")); 391 die(); 392 } 393 } 394 # authenticated, do we need to do 2fa ? 395 elseif (isset($_SESSION['2fa_required']) && $ignore_2fa!==true) { 396 header("Location:".$url.create_link ("2fa")); 397 die(); 398 } 399 # disabled 400 elseif ($this->user->disabled=="Yes") { 401 header("Location:".$url.create_link ("login")); 402 die(); 403 } 404 else { 405 return true; 406 } 407 } 408 409 /** 410 * Sets UI theme for user 411 * 412 * @method set_user_theme 413 * @return void 414 */ 415 private function set_user_theme () { 416 // set defaukt theme if field is missing 417 if(!isset($this->settings->theme)) { 418 $this->settings->theme = "dark"; 419 } 420 // set user 421 if(is_object($this->user)) { 422 // use default theme from general settings 423 if(!isset($this->user->theme) || @$this->user->theme=="") { 424 $this->user->ui_theme = $this->settings->theme; 425 } 426 else { 427 $this->user->ui_theme = $this->user->theme; 428 } 429 // validate 430 if(!in_array($this->user->ui_theme, $this->themes)) { 431 $this->user->ui_theme = "white"; 432 } 433 } 434 } 435 436 /** 437 * Check if users timeout expired 438 * if yes set timeout flag 439 * 440 * @access private 441 * @return void 442 */ 443 private function check_timeout () { 444 //session set 445 if(isset($_SESSION['lastactive'])) { 446 if( strlen($this->settings->inactivityTimeout)>0 && (time()-@$_SESSION['lastactive']) > $this->settings->inactivityTimeout) { 447 $this->timeout = true; 448 unset($_SESSION['lastactive']); 449 } 450 } 451 } 452 453 /** 454 * resets inactivity time after each succesfull login 455 * 456 * @access private 457 * @return void 458 */ 459 private function reset_inactivity_time () { 460 if($this->timeout!==true) { 461 $_SESSION['lastactive'] = time(); 462 } 463 } 464 465 /** 466 * Saves redirect cookie if session times out 467 * 468 * @access private 469 * @return void 470 */ 471 private function set_redirect_cookie () { 472 # save current redirect vaule 473 if( $_SERVER['SCRIPT_URL']=="/login/" || 474 $_SERVER['SCRIPT_URL']=="logout" || 475 $_SERVER['SCRIPT_URL']=="?page=login" || 476 $_SERVER['SCRIPT_URL']=="?page=logout" || 477 $_SERVER['SCRIPT_URL']=="index.php?page=login" || 478 $_SERVER['SCRIPT_URL']=="index.php?page=logout" || 479 $_SERVER['SCRIPT_URL']=="/" || 480 $_SERVER['SCRIPT_URL']=="%2f") 481 { 482 return; 483 } 484 485 $uri = is_string($_SERVER['HTTP_X_FORWARDED_URI']) ? $_SERVER['HTTP_X_FORWARDED_URI'] : $_SERVER['REQUEST_URI']; 486 487 setcookie_samesite("phpipamredirect", preg_replace('/^\/+/', '/', $uri), 10, true); 488 } 489 490 /** 491 * Sets translation for logged in user 492 * 493 * @access private 494 * @return void 495 */ 496 private function set_ui_language () { 497 if(strlen($_SESSION['ipamlanguage'])>0) { 498 putenv("LC_ALL=$_SESSION[ipamlanguage]"); 499 bindtextdomain("phpipam", dirname(__FILE__)."/../locale"); // Specify location of translation tables 500 setlocale(LC_ALL, $_SESSION['ipamlanguage']); // set language 501 textdomain("phpipam"); // Choose domain 502 } 503 } 504 505 /** 506 * Checks if system is in maintaneance mode and exits if it is 507 * 508 * @method check_maintaneance_mode 509 * @param bool $is_popup (default: false) 510 * @return void 511 */ 512 public function check_maintaneance_mode ($is_popup = false) { 513 if($this->settings->maintaneanceMode == "1" && $this->user->username!="Admin") { 514 if($is_popup) { 515 $this->Result->show("warning", "<i class='fa fa-info'></i> "._("System is running in maintenance mode")." !", true, true); 516 } 517 else { 518 $this->Result->show("warning text-center nomargin", "<i class='fa fa-info'></i> "._("System is running in maintenance mode")." !", true); 519 } 520 } 521 } 522 523 /** 524 * Sets maintaneance mode 525 * 526 * @method set_maintaneance_mode 527 * @param bool $on (default: false) 528 */ 529 public function set_maintaneance_mode ($on = false) { 530 # set mode status 531 $maintaneance_mode = $on ? "1" : "0"; 532 # execute 533 try { $this->Database->updateObject("settings", array("id"=>1, "maintaneanceMode"=>$maintaneance_mode), "id"); } 534 catch (Exception $e) {} 535 } 536 537 /** 538 * Migrate resolve_subnets from config.php to database 539 * for versions older than 1.31 540 * 541 * @method migrate_resolve_subnets 542 * 543 * @return void 544 */ 545 public function migrate_resolve_subnets () { 546 // read config.php 547 $config = Config::get('config'); 548 549 // check for array and values 550 if(!isset($config['resolve_subnets']) || !is_array($config['resolve_subnets']) || sizeof($config['resolve_subnets'])==0) 551 return; 552 553 foreach ($config['resolve_subnets'] as $subnetId) { 554 $update = ["id" => $subnetId, "resolveDNS" => 1 ]; 555 // update 556 try { 557 $this->Database->updateObject("subnets", $update); 558 } catch (Exception $e) {} 559 } 560 // print that is can be deleted 561 $this->Result->show ("warning", '$config[resolve_subnets] '._('was migrated to database. It can be deleted from config.php'), false); 562 } 563 564 565 566 567 568 569 570 571 /** 572 * @miscalaneous methods 573 * ------------------------------ 574 */ 575 576 /** 577 * Checks AJAX loaded pages for proper origin 578 * 579 * @access private 580 * @return void 581 */ 582 private function check_referrer () { 583 if ( ($_SERVER['HTTP_X_REQUESTED_WITH'] != "XMLHttpRequest") && ($_SERVER['HTTP_ORIGIN'] != $_SERVER['HTTP_HOST'] ) ) { 584 # write log and die 585 $this->Log->write ("referrer_check", _('Page not referred properly'), 0 ); 586 $this->Result->show ("danger", _('Page not referred properly'), true); 587 } 588 } 589 590 /** 591 * fetches default language 592 * 593 * @access public 594 * @return object 595 */ 596 public function get_default_lang () { 597 try { $lang = $this->Database->findObject("lang","l_id",$this->settings->defaultLang); } 598 catch (Exception $e) { $this->debugging ? : $this->Result->show("danger", _("Database error: ").$e->getMessage()); } 599 600 return $lang; 601 } 602 603 /** 604 * Sets available authentication methods 605 * 606 * Can be extended by reading set properties from set field options 607 * 608 * @access public 609 * @return array 610 */ 611 public function fetch_available_auth_method_types () { 612 return array("AD", "LDAP", "NetIQ", "Radius", "SAML2"); 613 } 614 615 616 617 618 619 620 621 622 623 624 /** 625 * @favourite methods 626 * ------------------------------ 627 */ 628 629 /** 630 * Fetches details for users favourite subnets 631 * 632 * @access public 633 * @return array|false 634 */ 635 public function fetch_favourite_subnets () { 636 # none 637 if(strlen($this->user->favourite_subnets)==0) { 638 return false; 639 } 640 # ok 641 else { 642 # store to array 643 $subnets = explode(";", $this->user->favourite_subnets); 644 $subnets = array_filter($subnets); 645 646 if(sizeof($subnets)>0) { 647 // init 648 $fsubnets = array(); 649 # fetch details for each subnet 650 foreach($subnets as $id) { 651 $query = "select `su`.`id` as `subnetId`,`se`.`id` as `sectionId`, `subnet`, `mask`,`isFull`,`su`.`description`,`se`.`description` as `section`, `vlanId`, `isFolder` 652 from `subnets` as `su`, `sections` as `se` where `su`.`id` = ? and `su`.`sectionId` = `se`.`id` limit 1;"; 653 654 try { $fsubnet = $this->Database->getObjectQuery($query, array($id)); } 655 catch (Exception $e) { 656 $this->Result->show("danger", _("Error: ").$e->getMessage()); 657 return false; 658 } 659 660 # out array 661 $fsubnets[] = (array) $fsubnet; 662 } 663 return $fsubnets; 664 } else { 665 return false; 666 } 667 } 668 } 669 670 /** 671 * Edit users favourites 672 * 673 * @access public 674 * @param mixed $action 675 * @param mixed $subnetId 676 * @return bool 677 */ 678 public function edit_favourite($action, $subnetId) { 679 # execute 680 if($action=="remove") { return $this->remove_favourite ($subnetId); } 681 elseif($action=="add") { return $this->add_favourite ($subnetId); } 682 else { return false; } 683 } 684 685 /** 686 * Remove subnet from user favourite subnets 687 * 688 * @access private 689 * @param mixed $subnetId 690 * @return bool 691 */ 692 private function remove_favourite ($subnetId) { 693 # set old favourite subnets 694 $old_favourites = explode(";", $this->user->favourite_subnets); 695 # set new 696 $new_favourites = implode(";", array_diff($old_favourites, array($subnetId))); 697 # update 698 try { $this->Database->updateObject("users", array("favourite_subnets"=>$new_favourites, "id"=>$this->user->id), "id"); } 699 catch (Exception $e) { 700 return false; 701 } 702 return true; 703 } 704 705 /** 706 * Add subnet to user favourite subnets 707 * 708 * @access private 709 * @param int $subnetId 710 * @return bool 711 */ 712 private function add_favourite ($subnetId) { 713 # set old favourite subnets 714 $old_favourites = explode(";", $this->user->favourite_subnets); 715 $old_favourites = is_array($old_favourites) ? $old_favourites : array(); 716 # set new 717 $new_favourites = implode(";",array_merge(array($subnetId), $old_favourites)); 718 # update 719 try { $this->Database->updateObject("users", array("favourite_subnets"=>$new_favourites, "id"=>$this->user->id), "id"); } 720 catch (Exception $e) { 721 return false; 722 } 723 return true; 724 } 725 726 /** 727 * Checks if subnet is in users favourite subnets 728 * 729 * @access public 730 * @param int $subnetId 731 * @return boolean 732 */ 733 public function is_subnet_favourite ($subnetId) { 734 $this->fetch_favourite_subnets (); 735 # check if in array 736 $subnets = explode(";", $this->user->favourite_subnets); 737 $subnets = array_filter($subnets); 738 # result 739 return in_array($subnetId, $subnets) ? true : false; 740 } 741 742 /** 743 * Checks if folder is favourite - alias for is subnet favourite 744 * 745 * @access public 746 * @param mixed $subnetId 747 * @return bool 748 */ 749 public function is_folder_favourite ($subnetId) { 750 return $this->is_subnet_favourite ($subnetId); 751 } 752 753 754 755 756 757 758 759 760 761 762 763 /** 764 * @authentication functions 765 * ------------------------------- 766 */ 767 768 /** 769 * Main function for authenticating users 770 * 771 * > tries to fetch user details from database by username 772 * > sets authentication method and checks validity 773 * > authenticates 774 * 775 * @access public 776 * @param string $username 777 * @param string $password 778 * @param bool $saml 779 * @return void 780 */ 781 public function authenticate ($username, $password, $saml = false) { 782 if(($saml !== false ) && (defined('MAP_SAML_USER')) && (MAP_SAML_USER !== false)) { 783 $username = SAML_USERNAME; 784 } 785 # first we need to check if username exists 786 $this->fetch_user_details ($username); 787 # set method type if set, otherwise presume local auth 788 $this->authmethodid = strlen(@$this->user->authMethod)>0 ? $this->user->authMethod : 1; 789 790 # 2fa 791 if ($this->user->{'2fa'}==1) { 792 $this->twofa = true; 793 } 794 795 # get authentication method details 796 $this->get_auth_method_type (); 797 798 # authenticate based on name of auth method 799 if(!method_exists($this, $this->authmethodtype)) { 800 $this->Log->write ("User login", _('Error: Invalid authentication method'), 2 ); 801 $this->Result->show("danger", _("Error: Invalid authentication method"), true); 802 } 803 # disabled 804 elseif ($this->user->disabled=="Yes") { 805 $this->Result->show("danger", _("Your account has been disabled").".", true); 806 } 807 else { 808 # set method name variable 809 $authmethodtype = $this->authmethodtype; 810 if($saml !== false) { 811 $authmethodtype = 'auth_SAML2'; 812 } 813 # is auth_SAML and $saml == false throw error 814 if ($authmethodtype=="auth_SAML2" && $saml===false) { 815 $this->Result->show("danger", "Please use <a href='".create_link('saml2')."'>login</a>!", true); 816 } 817 else { 818 # authenticate 819 $this->{$authmethodtype} ($username, $password); 820 } 821 } 822 } 823 824 /** 825 * tries to fetch user datails from database by username if not already existing locally 826 * 827 * @access private 828 * @param string $username 829 * @param bool $force 830 * @return void 831 */ 832 private function fetch_user_details ($username, $force = false) { 833 # only if not already active 834 if(!is_object($this->user) || $force) { 835 try { $user = $this->Database->findObject("users", "username", $username); } 836 catch (Exception $e) { $this->Result->show("danger", _("Error: ").$e->getMessage(), true);} 837 838 # if not result return false 839 $usert = (array) $user; 840 841 # admin? 842 if($user->role == "Administrator") { $this->isadmin = true; } 843 844 if(sizeof($usert)==0) { $this->block_ip (); $this->Log->write ("User login", _('Invalid username'), 2, $username ); $this->Result->show("danger", _("Invalid username or password"), true);} 845 else { $this->user = $user; } 846 847 // register permissions 848 $this->register_user_module_permissions (); 849 } 850 } 851 852 /** 853 * Fetch all languages from database. 854 * 855 * @access public 856 * @return array 857 */ 858 public function fetch_langs () { 859 try { $langs = $this->Database->getObjects("lang", "l_id"); } 860 catch (Exception $e) { 861 $this->Result->show("danger", _("Error: ").$e->getMessage()); 862 return false; 863 } 864 # return 865 return $langs; 866 } 867 868 /** 869 * fetches language details from database 870 * 871 * @access private 872 * @return string 873 */ 874 private function fetch_lang_details () { 875 // fetch from db 876 try { $lang = $this->Database->findObject("lang", "l_id", $this->user->lang); } 877 catch (Exception $e) { 878 $this->Result->show("danger", _("Error: ").$e->getMessage(), true); 879 return false; 880 } 881 // return code 882 return $lang->l_code; 883 } 884 885 /** 886 * Fetches name and details of authentication method (local, AD, LDAP, ...) from DB and saves them to var 887 * 888 * @access private 889 * @return void 890 */ 891 private function get_auth_method_type () { 892 # for older versions - only local is available! 893 if($this->settings->version=="1.1") { 894 $this->authmethodtype = "auth_local"; 895 } 896 else { 897 try { $method = $this->Database->getObject("usersAuthMethod", $this->authmethodid); } 898 catch (Exception $e) { 899 $this->Result->show("danger", _("Error: ").$e->getMessage(), true); 900 } 901 # save method name if existing 902 if($method!==false) { 903 $this->authmethodtype = "auth_".$method->type; 904 $this->authmethodparams = $method->params; 905 } 906 } 907 } 908 909 /** 910 * local user authentication method, authenticates users through local DB entry 911 * we provide user object from DB, and username/password entered by users 912 * 913 * @access private 914 * @param mixed $username 915 * @param mixed $password 916 * @return void 917 */ 918 private function auth_local ($username, $password) { 919 # auth ok 920 if(hash_equals($this->user->password, crypt($password, $this->user->password))) { 921 # save to session 922 $this->write_session_parameters (); 923 924 $this->Result->show("success", _("Login successful")); 925 $this->Log->write( "User login", "User ".$this->user->real_name." logged in", 0, $username ); 926 927 # write last logintime 928 $this->update_login_time (); 929 930 # remove possible blocked IP 931 $this->block_remove_entry (); 932 } 933 # auth failed 934 else { 935 # add blocked count 936 $this->block_ip (); 937 938 $this->Log->write( "User login", "Invalid username or password", 2, $username ); 939 940 # apache 941 if (!empty($_SERVER['PHP_AUTH_USER']) && $this->api!==true) { $this->show_http_login(); } 942 else { $this->Result->show("danger", _("Invalid username or password"), true); } 943 } 944 } 945 946 /** 947 * HTTP REMOTE_USER authentication, the user is already authenticated 948 * by the web server so just create the session 949 * 950 * @access private 951 * @param mixed $username 952 * @param mixed $password 953 * @return void 954 */ 955 public function auth_http ($username, $password) { 956 # save to session 957 $this->write_session_parameters (); 958 959 $this->Result->show("success", _("Login successful")); 960 $this->Log->write( "User login", "User ".$this->user->real_name." logged in", 0, $username ); 961 962 # write last logintime 963 $this->update_login_time (); 964 965 # remove possible blocked IP 966 $this->block_remove_entry (); 967 } 968 969 /** 970 * Shows login prompt for apache logins 971 * 972 * @access private 973 * @return void 974 */ 975 private function show_http_login () { 976 header('WWW-Authenticate: Basic realm="phpIPAM authentication"'); 977 header('HTTP/1.0 401 Unauthorized'); 978 echo 'Authentication failed'; 979 exit; 980 } 981 982 /** 983 * Connect to a directory given our auth method settings 984 * 985 *Connect using adLDAP 986 * 987 * @access private 988 * @param mixed $authparams 989 * @return adLDAP object 990 */ 991 private function directory_connect ($authparams) { 992 # adLDAP script 993 require(dirname(__FILE__) . "/../adLDAP/src/adLDAP.php"); 994 $dirparams = Array(); 995 $dirparams['base_dn'] = @$authparams['base_dn']; 996 $dirparams['ad_port'] = @$authparams['ad_port']; 997 $dirparams['account_suffix'] = @$authparams['account_suffix']; 998 $dirparams['domain_controllers'] = explode(";", str_replace(" ", "", $authparams['domain_controllers'])); 999 // set ssl and tls separate for ldap and AD 1000 if ($this->ldap) { 1001 // set ssl and tls 1002 $dirparams['use_ssl'] = false; 1003 $dirparams['use_tls'] = false; 1004 // Support the pre-1.2 auth settings as well as the current version 1005 // TODO: remove legacy support at some point 1006 if ($authparams['ldap_security'] == 'tls' || $authparams['use_tls'] == 1) { $dirparams['use_tls'] = true; } 1007 elseif ($authparams['ldap_security'] == 'ssl' || $authparams['use_ssl'] == 1) { $dirparams['use_ssl'] = true; } 1008 if (isset($authparams['admin_username']) && isset($authparams['admin_password'])) { 1009 $dirparams['admin_username'] = $authparams['adminUsername']; 1010 $dirparams['admin_password'] = $authparams['adminPassword']; 1011 } 1012 } 1013 else { 1014 $dirparams['use_ssl'] = @$authparams['use_ssl']; 1015 $dirparams['use_tls'] = @$authparams['use_tls']; 1016 } 1017 # open connection 1018 try { 1019 # Initialize adLDAP 1020 $dirconn = new adLDAP($dirparams); 1021 } catch (adLDAPException $e) { 1022 $this->Log->write("Directory connection error", "Failed to connect: " . $e->getMessage(), 2, null); 1023 $this->Result->show("danger", _("Error: ") . $e->getMessage(), true); 1024 } 1025 return $dirconn; 1026 } 1027 1028 /** 1029 * Authenticate against a directory 1030 * 1031 * Authenticates users against a directory - AD or LDAP 1032 * Using library > adLDAP - LDAP Authentication with PHP for Active Directory 1033 * http://adldap.sourceforge.net 1034 * 1035 * @access private 1036 * @param array $authparams 1037 * @param string $username 1038 * @param string $password 1039 * @return void 1040 */ 1041 private function directory_authenticate ($authparams, $username, $password) { 1042 // set method 1043 $method = $this->ldap ? "LDAP" : "AD"; 1044 // connect 1045 $adldap = $this->directory_connect($authparams); 1046 1047 # authenticate 1048 try { 1049 if ($adldap->authenticate($username, $password)) { 1050 # save to session 1051 $this->write_session_parameters(); 1052 1053 $this->Log->write($method . " login", "User " . $this->user->real_name . " logged in via " . $method, 0, $username); 1054 $this->Result->show("success", _($method . " Login successful")); 1055 1056 # write last logintime 1057 $this->update_login_time(); 1058 # remove possible blocked IP 1059 $this->block_remove_entry(); 1060 } # wrong user/pass by default 1061 else { 1062 # add blocked count 1063 $this->block_ip(); 1064 $this->Log->write($method . " login", "User $username failed to authenticate against " . $method, 1, $username); 1065 $this->Result->show("danger", _("Invalid username or password"), true); 1066 1067 } 1068 } catch (adLDAPException $e) { 1069 $this->Log->write("Error", "Something went wrong during auth: " . $e->getMessage(), 2, $username); 1070 $this->Result->show("danger", _("Error: ") . $e->getMessage(), true); 1071 } 1072 } 1073 1074 /** 1075 * AD (Active directory) authentication function 1076 * 1077 * 1078 * @access private 1079 * @param mixed $username 1080 * @param mixed $password 1081 * @return void 1082 */ 1083 private function auth_AD ($username, $password) { 1084 // parse settings for LDAP connection and store them to array 1085 $authparams = json_decode($this->authmethodparams, true); 1086 // authenticate 1087 $this->directory_authenticate($authparams, $username, $password); 1088 } 1089 1090 /** 1091 * LDAP authentication 1092 * same as AD authentication, only set the LDAP flag to true 1093 * 1094 * @access private 1095 * @param mixed $username 1096 * @param mixed $password 1097 * @return void 1098 */ 1099 private function auth_LDAP ($username, $password) { 1100 // parse settings for LDAP connection and store them to array 1101 $authparams = json_decode($this->authmethodparams, true); 1102 $this->ldap = true; //set ldap flag 1103 1104 // set uid 1105 if (!empty($authparams['uid_attr'])) { $udn = $authparams['uid_attr'] . '=' . $username; } 1106 else { $udn = 'uid=' . $username; } 1107 // set DN 1108 if (!empty($authparams['users_base_dn'])) { $udn = $udn . "," . $authparams['users_base_dn']; } 1109 else { $udn = $udn . "," . $authparams['base_dn']; } 1110 // authenticate 1111 $this->directory_authenticate($authparams, $udn, $password); 1112 } 1113 1114 /** 1115 * NetIQ authentication 1116 * same as AD authentication, only add cn= before username 1117 * 1118 * @access private 1119 * @param mixed $username 1120 * @param mixed $password 1121 * @return void 1122 */ 1123 private function auth_NetIQ ($username, $password) { 1124 $this->auth_AD ("cn=".$username, $password); 1125 } 1126 1127 /** 1128 * Authenticates user on radius server 1129 * 1130 * @access private 1131 * @param mixed $username 1132 * @param mixed $password 1133 * @return void 1134 */ 1135 private function auth_radius ($username, $password) { 1136 # decode radius parameters 1137 $params = json_decode($this->authmethodparams); 1138 1139 # check for socket support ! 1140 if(!in_array("sockets", get_loaded_extensions())) { 1141 $this->Log->write( "Radius login", "php Socket extension missing", 2 ); 1142 $this->Result->show("danger", _("php Socket extension missing"), true); 1143 } 1144 1145 # initialize radius class 1146 require( dirname(__FILE__) . '/class.Radius.php' ); 1147 $Radius = new Radius ($params->hostname, $params->secret, $params->suffix, $params->timeout, $params->port); 1148 //debugging 1149 $this->debugging!==true ? : $Radius->SetDebugMode(TRUE); 1150 1151 # authenticate 1152 $auth = $Radius->AccessRequest($username, $password); 1153 # debug? 1154 if($this->debugging) { 1155 print "<pre style='width:700px;margin:auto;margin-top:10px;'>"; 1156 print(implode("<br>", $Radius->debug_text)); 1157 print "</pre>"; 1158 } 1159 1160 # authenticate user 1161 if($auth) { 1162 # save to session 1163 $this->write_session_parameters (); 1164 1165 $this->Log->write( "Radius login", "User ".$this->user->real_name." logged in via radius", 0, $username ); 1166 $this->Result->show("success", _("Radius login successful")); 1167 1168 # write last logintime 1169 $this->update_login_time (); 1170 # remove possible blocked IP 1171 $this->block_remove_entry (); 1172 } 1173 else { 1174 # add blocked count 1175 $this->block_ip (); 1176 $this->Log->write( "Radius login", "Failed to authenticate user on radius server", 2, $username ); 1177 $this->Result->show("danger", _("Invalid username or password"), true); 1178 } 1179 } 1180 1181 /** 1182 * SAML2 auth 1183 * 1184 * @access private 1185 * @param mixed $username 1186 * @param mixed $password (default: null) 1187 * @return void 1188 */ 1189 private function auth_SAML2 ($username, $password = null) { 1190 # save to session 1191 $this->write_session_parameters (); 1192 1193 $this->Log->write( "SAML2 login", "User ".$this->user->real_name." logged in via SAML2", 0, $username ); 1194 $this->Result->show("success", _("SAML2 login successful")); 1195 1196 # write last logintime 1197 $this->update_login_time (); 1198 # remove possible blocked IP 1199 $this->block_remove_entry (); 1200 } 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 /** 1212 * @crypt functions 1213 * ------------------------------ 1214 */ 1215 1216 1217 /** 1218 * function to crypt user pass, randomly generates salt. Use sha256 if possible, otherwise Blowfish or md5 as fallback 1219 * 1220 * types: 1221 * CRYPT_MD5 == 1 (Salt starting with $1$, 12 characters ) 1222 * CRYPT_BLOWFISH == 1 (Salt starting with $2a$. The two digit cost parameter: 09. 22 characters ) 1223 * CRYPT_SHA256 == 1 (Salt starting with $5$rounds=5000$, 16 character salt.) 1224 * CRYPT_SHA512 == 1 (Salt starting with $6$rounds=5000$, 16 character salt.) 1225 * 1226 * @access public 1227 * @param mixed $input 1228 * @return string 1229 */ 1230 public function crypt_user_pass ($input) { 1231 # initialize salt 1232 $salt = ""; 1233 # set possible salt characters in array 1234 $salt_chars = array_merge(range('A','Z'), range('a','z'), range(0,9)); 1235 # loop to create salt 1236 for($i=0; $i < 22; $i++) { $salt .= $salt_chars[array_rand($salt_chars)]; } 1237 # get prefix 1238 $prefix = $this->detect_crypt_type (); 1239 # return crypted variable 1240 return crypt($input, $prefix.$salt); 1241 } 1242 1243 /** 1244 * this function will detect highest crypt type to use for system 1245 * 1246 * @access public 1247 * @return string 1248 */ 1249 private function detect_crypt_type () { 1250 if(CRYPT_SHA512 == 1) { return '$6$rounds=3000$'; } 1251 elseif(CRYPT_SHA256 == 1) { return '$5$rounds=3000$'; } 1252 elseif(CRYPT_BLOWFISH == 1) { return '$2y$'.str_pad(rand(4,31),2,0, STR_PAD_LEFT).'$'; } 1253 elseif(CRYPT_MD5 == 1) { return '$5$rounds=3000$'; } 1254 else { $this->Result->show("danger", _("No crypt types supported"), true); } 1255 } 1256 1257 /** 1258 * Returns crypt type used to encrypt password 1259 * 1260 * @access public 1261 * @return string 1262 */ 1263 public function return_crypt_type () { 1264 if(CRYPT_SHA512 == 1) { return 'CRYPT_SHA512'; } 1265 elseif(CRYPT_SHA256 == 1) { return 'CRYPT_SHA256'; } 1266 elseif(CRYPT_BLOWFISH == 1) { return 'CRYPT_BLOWFISH'; } 1267 elseif(CRYPT_MD5 == 1) { return 'CRYPT_MD5'; } 1268 else { return "No crypt types supported"; } 1269 } 1270 1271 /** 1272 * Updates users password 1273 * 1274 * @access public 1275 * @param mixed $password 1276 * @return void 1277 */ 1278 public function update_user_pass ($password) { 1279 try { $this->Database->updateObject("users", array("password"=>$this->crypt_user_pass ($password), "passChange"=>"No", "id"=>$this->user->id), "id"); } 1280 catch (Exception $e) { $this->Result->show("danger", $e->getMessage(), true); } 1281 1282 $this->Result->show("success", "Hi, ".$this->user->real_name.", "._("your password was updated").". <a class='btn btn-sm btn-default' href='".create_link("dashboard")."'>Dashboard</a>", false); 1283 } 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 /** 1295 * @updating user methods 1296 * ------------------------------ 1297 */ 1298 1299 /** 1300 * User self update method 1301 * 1302 * @access public 1303 * @param array|object $post //posted user details 1304 * @return bool 1305 */ 1306 public function self_update($post) { 1307 # remove theme 1308 if($post['theme'] == "default") { $post['theme'] = ""; } 1309 # set items to update 1310 $items = array("real_name" => escape_input(strip_tags($post['real_name'])), 1311 "mailNotify" => $post['mailNotify'] == "Yes" ? "Yes" : "No", 1312 "mailChangelog" => $post['mailChangelog'] == "Yes" ? "Yes" : "No", 1313 "email" => $this->validate_email($post['email']) ? escape_input($post['email']) : '', 1314 "lang" => escape_input(strip_tags($post['lang'])), 1315 "id" => $this->user->id, 1316 //display 1317 "compressOverride" => escape_input(strip_tags($post['compressOverride'])), 1318 "hideFreeRange" => $this->verify_checkbox(@$post['hideFreeRange']), 1319 "menuType" => $this->verify_checkbox(@$post['menuType']), 1320 "menuCompact" => $this->verify_checkbox(@$post['menuCompact']), 1321 "theme" => $post['theme'], 1322 "2fa" => $this->verify_checkbox(@$post['2fa']), 1323 ); 1324 if(strlen($post['password1'])>0) { 1325 $items['password'] = $this->crypt_user_pass ($post['password1']); 1326 } 1327 1328 # prepare log file 1329 $log = $this->array_to_log ($post); 1330 1331 # update 1332 try { $this->Database->updateObject("users", $items); } 1333 catch (Exception $e) { 1334 $this->Result->show("danger", _("Error: ").$e->getMessage(), false); 1335 $this->Log->write( "User self update", "User self update failed!<br>".$log, 2 ); 1336 return false; 1337 } 1338 # update language 1339 $this->update_session_language (); 1340 1341 # ok, update log table 1342 $this->Log->write( "User self update", "User self update suceeded!", 0 ); 1343 return true; 1344 } 1345 1346 /** 1347 * User self update widgets. 1348 * 1349 * @access public 1350 * @param mixed $widgets 1351 * @return bool 1352 */ 1353 public function self_update_widgets ($widgets) { 1354 # update 1355 try { $this->Database->updateObject("users", array("widgets"=>$widgets, "id"=>$this->user->id)); } 1356 catch (Exception $e) { 1357 $this->Result->show("danger", _("Error: ").$e->getMessage(), false); 1358 return false; 1359 } 1360 # ok, update log table 1361 return true; 1362 } 1363 1364 /** 1365 * Updates last users login time 1366 * 1367 * @access public 1368 * @return bool 1369 */ 1370 public function update_login_time () { 1371 # fix for older versions 1372 if($this->settings->version!="1.1") { 1373 # update 1374 try { $this->Database->updateObject("users", array("lastLogin"=>date("Y-m-d H:i:s"), "id"=>$this->user->id)); } 1375 catch (Exception $e) { 1376 $this->Result->show("danger", _("Error: ").$e->getMessage(), false); 1377 return false; 1378 } 1379 } 1380 } 1381 1382 /** 1383 * Updates last users activity time 1384 * 1385 * @access public 1386 * @return void 1387 */ 1388 public function update_activity_time () { 1389 # update 1390 try { $this->Database->updateObject("users", array("lastActivity"=>date("Y-m-d H:i:s"), "id"=>$this->user->id)); } 1391 catch (Exception $e) { } 1392 } 1393 1394 1395 1396 1397 1398 1399 1400 1401 /** 1402 * @blocking IP functions 1403 * ------------------------------ 1404 */ 1405 1406 1407 /** 1408 * sets limit for failed login attempts 1409 * 1410 * @access public 1411 * @param int $limit 1412 * @return none 1413 */ 1414 public function set_block_limit ($limit) { 1415 $this->blocklimit = $limit; 1416 } 1417 1418 /** 1419 * checks if IP is blocked and returns count for entries 1420 * 1421 * @access public 1422 * @param none 1423 * @return int|false 1424 */ 1425 public function block_check_ip () { 1426 # first purge 1427 $this->purge_blocked_entries (); 1428 $this->block_get_ip (); 1429 # set date and query 1430 $now = date("Y-m-d H:i:s", time() - 5*60); 1431 $query = "select count from `loginAttempts` where `ip` = ? and `datetime` > ?;"; 1432 # fetch 1433 try { $cnt = $this->Database->getObjectQuery($query, array($this->ip, $now)); } 1434 catch (Exception $e) { !$this->debugging ? : $this->Result->show("danger", $e->getMessage(), false); } 1435 1436 # verify 1437 return @$cnt->count>0 ? $cnt->count : false; 1438 } 1439 1440 /** 1441 * adds new IP to block or updates count if already present 1442 * 1443 * @access public 1444 * @return bool 1445 */ 1446 public function block_ip () { 1447 # validate IP 1448 if(!filter_var($this->ip, FILTER_VALIDATE_IP)) { return false; } 1449 1450 # first check if already in 1451 if($this->block_check_ip ()) { $this->block_update_count(); } 1452 # if not in add first entry 1453 else { $this->block_add_entry(); } 1454 } 1455 1456 /** 1457 * sets IP address to block 1458 * needed for proxy access to block end user not whole proxy 1459 * 1460 * @access private 1461 * @return void 1462 */ 1463 private function block_get_ip () { 1464 # set IP 1465 if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $this->ip = @$_SERVER['HTTP_X_FORWARDED_FOR']; } 1466 else { $this->ip = @$_SERVER['REMOTE_ADDR']; } 1467 } 1468 1469 /** 1470 * purges login attampts more than 5 minutes old (since last attempt) 1471 * 1472 * @access private 1473 * @return void 1474 */ 1475 private function purge_blocked_entries () { 1476 # set date 5 min ago and query 1477 $ago = date("Y-m-d H:i:s", time() - 5*60); 1478 $query = "delete from `loginAttempts` where `datetime` < ?; "; 1479 1480 try { $this->Database->runQuery($query, array($ago)); } 1481 catch (Exception $e) { !$this->debugging ? : $this->Result->show("danger", $e->getMessage(), false); } 1482 } 1483 1484 /** 1485 * updates existing log attampt count 1486 * 1487 * @access private 1488 * @return void 1489 */ 1490 private function block_update_count() { 1491 # query 1492 $query = "update `loginAttempts` set `count`=`count`+1 where `ip` = ?; "; 1493 try { $this->Database->runQuery($query, array($this->ip)); } 1494 catch (Exception $e) { !$this->debugging ? : $this->Result->show("danger", $e->getMessage(), false); } 1495 } 1496 1497 /** 1498 * adds new IP entry to block with count 1 1499 * 1500 * @access private 1501 * @return void 1502 */ 1503 private function block_add_entry() { 1504 try { $this->Database->insertObject("loginAttempts", array("ip"=>$this->ip, "count"=>1)); } 1505 catch (Exception $e) { !$this->debugging ? : $this->Result->show("danger", $e->getMessage(), false); } 1506 } 1507 1508 /** 1509 * removes blocked IP entry if it exists on successfull login 1510 * 1511 * @access private 1512 * @return void 1513 */ 1514 private function block_remove_entry() { 1515 try { $this->Database->deleteRow("loginAttempts", "ip", $this->ip); } 1516 catch (Exception $e) { !$this->debugging ? : $this->Result->show("danger", $e->getMessage(), false); } 1517 } 1518 1519 1520 1521 /* @users and groups -------------------- */ 1522 1523 /** 1524 * From json {"2":"2","3":"1"}, get user list + perm 1525 * 1526 * @method get_user_permissions_from_json 1527 * @param json $json 1528 * @return array 1529 */ 1530 public function get_user_permissions_from_json ($json) { 1531 // Check cache 1532 $cached_item = $this->cache_check('get_user_permissions_from_json', $json); 1533 if(is_object($cached_item)) return $cached_item->result; 1534 1535 $groups = array(); 1536 foreach((array) json_decode($json, true) as $group_id => $perm) { 1537 $group_details = $this->groups_parse (array($group_id)); 1538 1539 $tmp = array(); 1540 $tmp['group_id'] = $group_id; 1541 $tmp['permission'] = $perm; 1542 $tmp['name'] = $group_details[$group_id]['g_name']; 1543 $tmp['desc'] = $group_details[$group_id]['g_desc']; 1544 $tmp['members'] = $group_details[$group_id]['members']; 1545 1546 $groups[] = $tmp; 1547 } 1548 // Cache results to avoid repeat database queries. 1549 $this->cache_write('get_user_permissions_from_json', (object) ["id"=>$json, "result" => $groups]); 1550 return $groups; 1551 } 1552 1553 /** 1554 * Parse user groups 1555 * 1556 * input: array of group ids 1557 * output: array of groups ( "id"=>array($group) ) 1558 * 1559 * @method groups_parse 1560 * @param array $group_ids 1561 * @return array 1562 */ 1563 private function groups_parse ($group_ids) { 1564 if(sizeof($group_ids)>0) { 1565 foreach($group_ids as $g_id) { 1566 // group details 1567 $group = $this->fetch_object ("userGroups", "g_id", $g_id); 1568 $out[$group->g_id] = (array) $group; 1569 $out[$group->g_id]['members'] = $this->fetch_multiple_objects("users", "groups", "%\"$g_id\"%", "real_name", true, true, array("username")); 1570 } 1571 } 1572 # return array of groups 1573 return isset($out) ? $out : array(); 1574 } 1575 1576 /** 1577 * Get user l2domain access permissions 1578 * 1579 * Result can be the following: 1580 * - 0 : no access 1581 * - 1 : read-only 1582 * - 2 ; read-write 1583 * - 3 : admin 1584 * 1585 * @method get_l2domain_permissions 1586 * @param object $l2domain 1587 * @return int 1588 */ 1589 public function get_l2domain_permissions ($l2domain) { 1590 if ($this->is_admin(false)) 1591 return 3; 1592 1593 // Default l2domain is assigned to all sections 1594 if ($l2domain->id == 1) { 1595 $sections_ids = []; 1596 $all_sections = $this->fetch_all_objects("sections"); 1597 if (is_array($all_sections)) { 1598 foreach($all_sections as $section){ 1599 $sections_ids[] = $section->id; 1600 } 1601 } 1602 $valid_sections = implode(';', $sections_ids); 1603 } else { 1604 $valid_sections = $l2domain->permissions; 1605 } 1606 1607 $cached_item = $this->cache_check('l2domain_permissions', $valid_sections); 1608 if(is_object($cached_item)) return $cached_item->result; 1609 1610 if (empty($valid_sections)) { 1611 $this->cache_write('l2domain_permissions', (object) ["id"=>$valid_sections, "result" => 0]); 1612 return 0; 1613 } 1614 1615 $max_permission = 0; 1616 1617 $ids = explode(";", $valid_sections); 1618 foreach($ids as $id) { 1619 $section = $this->fetch_object("sections", "id", $id); 1620 1621 if (!is_object($section)) continue; 1622 1623 # Get Section permissions 1624 $sectionP = json_decode($section->permissions, true); 1625 1626 # ok, user has section access, check also for any higher access from subnet 1627 if(!is_array($sectionP)) continue; 1628 1629 # get all user groups 1630 $groups = json_decode($this->user->groups, true); 1631 1632 foreach($sectionP as $sk=>$sp) { 1633 # check each group if user is in it and if so check for permissions for that group 1634 foreach($groups as $uk=>$up) { 1635 if($uk == $sk) { 1636 if($sp > $max_permission) { $max_permission = $sp; } 1637 } 1638 } 1639 } 1640 } 1641 1642 # return result 1643 $this->cache_write('l2domain_permissions', (object) ["id"=>$valid_sections, "result" => $max_permission]); 1644 return $max_permission; 1645 } 1646 1647 /** 1648 * Check if user has l2domain permissions for specific access level 1649 * 1650 * @method check_l2domain_permissions 1651 * @param object $l2domain 1652 * @param int $required_level 1653 * @param bool $die 1654 * @param bool $popup 1655 * @return bool|void 1656 */ 1657 public function check_l2domain_permissions($l2domain, $required_level = 1, $die = true, $popup = false) { 1658 // check if valid 1659 $valid = $this->get_l2domain_permissions($l2domain)>=$required_level; 1660 // return or die ? 1661 if ($die===true && !$valid) { 1662 $this->Result->show ("danger", _("You do not have permissions to access this object"), true, $popup); 1663 } 1664 else { 1665 return $valid; 1666 } 1667 } 1668 1669 /** 1670 * Register use module permissions from json 1671 * 1672 * @method register_user_module_permissions 1673 * @return void 1674 */ 1675 private function register_user_module_permissions () { 1676 // decode 1677 $permissions = json_decode($this->user->module_permissions, true); 1678 // check for each module 1679 foreach ($this->get_modules_with_permissions() as $m) { 1680 if (!is_array($permissions)) { 1681 $this->user->{'perm_'.$m} = 0; 1682 } 1683 elseif(array_key_exists($m, $permissions)) { 1684 $this->user->{'perm_'.$m} = $permissions[$m]; 1685 } 1686 else { 1687 $this->user->{'perm_'.$m} = 0; 1688 } 1689 } 1690 } 1691 1692 /** 1693 * Get module permissions for user 1694 * 1695 * Result can be the following: 1696 * - 0 : no access 1697 * - 1 : read-only 1698 * - 2 ; read-write 1699 * - 3 : admin 1700 * 1701 * @method get_module_permissions 1702 * @param string $module_name 1703 * @return int 1704 */ 1705 public function get_module_permissions ($module_name = "") { 1706 if(in_array($module_name, $this->get_modules_with_permissions())) { 1707 // admin 1708 if($this->is_admin(false)) { 1709 return 3; 1710 } 1711 else { 1712 return $this->user->{'perm_'.$module_name}; 1713 } 1714 } 1715 else { 1716 return 0; 1717 } 1718 } 1719 1720 /** 1721 * Check if user has module permissions for specific access level 1722 * 1723 * @method check_module_permissions 1724 * @param string $module_name 1725 * @param int $required_level 1726 * @param bool $die 1727 * @param bool $popup 1728 * @return bool|void 1729 */ 1730 public function check_module_permissions ($module_name = "", $required_level = 1, $die = true, $popup = false) { 1731 // check if valid 1732 $valid = $this->get_module_permissions($module_name)>=$required_level; 1733 // return or die ? 1734 if ($die===true && !$valid) { 1735 $this->Result->show ("danger", _("You do not have permissions to access this module"), true, $popup); 1736 } 1737 else { 1738 return $valid; 1739 } 1740 } 1741 1742 /** 1743 * Return array of all modules with permissions 1744 * 1745 * @method get_modules_with_permissions 1746 * @return array 1747 */ 1748 public function get_modules_with_permissions () { 1749 return [ 1750 "vlan", 1751 "vrf", 1752 "pdns", 1753 "circuits", 1754 "racks", 1755 "nat", 1756 "pstn", 1757 "customers", 1758 "locations", 1759 "devices", 1760 "dhcp", 1761 "routing" 1762 ]; 1763 } 1764 1765 /** 1766 * Prints permission badge 1767 * 1768 * @method print_permission_badge 1769 * @param int $level 1770 * @return string 1771 */ 1772 public function print_permission_badge ($level) { 1773 // null level 1774 if(is_null($level)) $level = 0; 1775 // return 1776 return $level=="0" ? "<span class='badge badge1 badge5 alert-danger'>"._($this->parse_permissions ($level))."</span>" : "<span class='badge badge1 badge5 alert-success'>"._($this->parse_permissions ($level))."</span>"; 1777 } 1778}