forked from Business/AccountHub
		
	Add Portal API integration, add icon/style settings, add navbar and icon
options to PAGES
This commit is contained in:
		
							parent
							
								
									16cbf2a5f1
								
							
						
					
					
						commit
						3110011596
					
				
							
								
								
									
										70
									
								
								app.php
									
									
									
									
									
								
							
							
						
						
									
										70
									
								
								app.php
									
									
									
									
									
								
							| @ -36,10 +36,18 @@ if (!is_empty($_GET['page'])) { | ||||
|         <div class="container"> | ||||
|             <div class="row"> | ||||
|                 <div class="col-xs-12 col-sm-6 col-md-4 col-lg-4 col-sm-offset-3 col-md-offset-4 col-lg-offset-4"> | ||||
|                     <img class="img-responsive banner-image" src="static/img/banner.png" /> | ||||
|                     <?php | ||||
|                     if ((SHOW_ICON == "both" || SHOW_ICON == "app") && ICON_POSITION != "menu") { | ||||
|                         if (MENU_BAR_STYLE != "fixed") { | ||||
|                             ?>
 | ||||
|                             <img class="img-responsive banner-image" src="static/img/logo.png" /> | ||||
|                             <?php | ||||
|                         } | ||||
|                     } | ||||
|                     ?>
 | ||||
|                 </div> | ||||
|             </div> | ||||
|             <nav class="navbar navbar-inverse"> | ||||
|             <nav class="navbar navbar-inverse navbar-<?php echo MENU_BAR_STYLE; ?>-top"> | ||||
|                 <div class="container-fluid"> | ||||
|                     <div class="navbar-header"> | ||||
|                         <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse"> | ||||
| @ -48,34 +56,70 @@ if (!is_empty($_GET['page'])) { | ||||
|                             <span class="icon-bar"></span> | ||||
|                             <span class="icon-bar"></span> | ||||
|                         </button> | ||||
|                         <a class="navbar-brand" href="app.php?page=home"> | ||||
|                         <?php | ||||
|                         if (SHOW_ICON == "both" || SHOW_ICON == "app") { | ||||
|                             if (MENU_BAR_STYLE == "fixed" || ICON_POSITION == "menu") { | ||||
|                                 ?>
 | ||||
|                                 <a class="navbar-brand" href="app.php"> | ||||
|                                     <img style="height: 35px; padding-bottom: 12px; padding-left: 5px;" src="static/img/logo.png" /> | ||||
|                                 </a> | ||||
|                                 <?php | ||||
|                             } | ||||
|                         } | ||||
|                         ?>
 | ||||
|                         <a class="navbar-brand" href="app.php"> | ||||
|                             <?php | ||||
|                             echo SITE_TITLE; | ||||
|                             // add breadcrumb-y thing
 | ||||
|                             //lang("home");
 | ||||
|                             //echo " <i class=\"fa fa-caret-right\"></i> ";
 | ||||
|                             lang(PAGES[$pageid]['title']); | ||||
|                             //lang(PAGES[$pageid]['title']);
 | ||||
|                             ?>
 | ||||
|                         </a> | ||||
|                     </div> | ||||
| 
 | ||||
|                     <div class="collapse navbar-collapse" id="navbar-collapse"> | ||||
|                         <ul class="nav navbar-nav"> | ||||
|                             <?php | ||||
|                             foreach (PAGES as $id => $pg) { | ||||
|                                 if ($pg['navbar'] === TRUE) { | ||||
|                                     if ($pageid == $id) { | ||||
|                                         ?>
 | ||||
|                                         <li class="active"> | ||||
|                                             <?php | ||||
|                                         } else { | ||||
|                                             ?>
 | ||||
|                                         <li> | ||||
|                                         <?php } ?>
 | ||||
|                                         <a href="app.php?page=<?php echo $id; ?>"> | ||||
|                                             <?php | ||||
|                                             if (isset($pg['icon'])) { | ||||
|                                                 ?>
 | ||||
|                                                 <i class="fa fa-<?php echo $pg['icon']; ?> fa-fw"></i>  | ||||
|                                             <?php } ?>
 | ||||
|                                             <?php lang($pg['title']) ?>
 | ||||
|                                         </a> | ||||
|                                     </li> | ||||
|                                     <?php | ||||
|                                 } | ||||
|                             } | ||||
|                             ?>
 | ||||
|                         </ul> | ||||
|                         <ul class="nav navbar-nav navbar-right"> | ||||
|                             <li class="dropdown"> | ||||
|                                 <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><i class="fa fa-gears fa-fw"></i> <?php lang("options") ?> <span class="caret"></span></a>
 | ||||
|                                 <ul class="dropdown-menu" role="menu"> | ||||
|                                     <li><a href="app.php?page=security"><i class="fa fa-lock fa-fw"></i> <?php lang("account security") ?></a></li>
 | ||||
|                                     <li class="divider"></li> | ||||
|                                     <li><a href="action.php?action=signout"><i class="fa fa-sign-out fa-fw"></i> <?php lang("sign out") ?></a></li>
 | ||||
|                                 </ul> | ||||
|                             </li> | ||||
|                             <li><a href="action.php?action=signout"><i class="fa fa-sign-out fa-fw"></i> <?php lang("sign out") ?></a></li>
 | ||||
|                         </ul> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </nav> | ||||
|             <?php | ||||
|             // Alert messages
 | ||||
|             if (MENU_BAR_STYLE == "fixed") { | ||||
|                 ?>
 | ||||
|                 <div style="height: 75px;"></div> | ||||
|                 <?php | ||||
|             } | ||||
|             ?>
 | ||||
|             <?php | ||||
| // Alert messages
 | ||||
|             if (!is_empty($_GET['msg']) && array_key_exists($_GET['msg'], MESSAGES)) { | ||||
|                 // optional string generation argument
 | ||||
|                 if (is_empty($_GET['arg'])) { | ||||
|  | ||||
| @ -4,7 +4,8 @@ | ||||
|     "type": "project", | ||||
|     "require": { | ||||
|         "catfan/medoo": "^1.2", | ||||
|         "spomky-labs/otphp": "^8.3" | ||||
|         "spomky-labs/otphp": "^8.3", | ||||
|         "guzzlehttp/guzzle": "^6.2" | ||||
|     }, | ||||
|     "license": "MIT", | ||||
|     "authors": [ | ||||
|  | ||||
							
								
								
									
										230
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										230
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							| @ -4,7 +4,7 @@ | ||||
|         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", | ||||
|         "This file is @generated automatically" | ||||
|     ], | ||||
|     "content-hash": "51c1672b4dea32e60865b4c0cd9ff8e1", | ||||
|     "content-hash": "e0730a4c33d1a1cbf8738481ba9a1f1e", | ||||
|     "packages": [ | ||||
|         { | ||||
|             "name": "beberlei/assert", | ||||
| @ -170,6 +170,184 @@ | ||||
|             ], | ||||
|             "time": "2016-05-05T11:49:03+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "guzzlehttp/guzzle", | ||||
|             "version": "6.2.3", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/guzzle/guzzle.git", | ||||
|                 "reference": "8d6c6cc55186db87b7dc5009827429ba4e9dc006" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/guzzle/guzzle/zipball/8d6c6cc55186db87b7dc5009827429ba4e9dc006", | ||||
|                 "reference": "8d6c6cc55186db87b7dc5009827429ba4e9dc006", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
|                 "guzzlehttp/promises": "^1.0", | ||||
|                 "guzzlehttp/psr7": "^1.4", | ||||
|                 "php": ">=5.5" | ||||
|             }, | ||||
|             "require-dev": { | ||||
|                 "ext-curl": "*", | ||||
|                 "phpunit/phpunit": "^4.0", | ||||
|                 "psr/log": "^1.0" | ||||
|             }, | ||||
|             "type": "library", | ||||
|             "extra": { | ||||
|                 "branch-alias": { | ||||
|                     "dev-master": "6.2-dev" | ||||
|                 } | ||||
|             }, | ||||
|             "autoload": { | ||||
|                 "files": [ | ||||
|                     "src/functions_include.php" | ||||
|                 ], | ||||
|                 "psr-4": { | ||||
|                     "GuzzleHttp\\": "src/" | ||||
|                 } | ||||
|             }, | ||||
|             "notification-url": "https://packagist.org/downloads/", | ||||
|             "license": [ | ||||
|                 "MIT" | ||||
|             ], | ||||
|             "authors": [ | ||||
|                 { | ||||
|                     "name": "Michael Dowling", | ||||
|                     "email": "mtdowling@gmail.com", | ||||
|                     "homepage": "https://github.com/mtdowling" | ||||
|                 } | ||||
|             ], | ||||
|             "description": "Guzzle is a PHP HTTP client library", | ||||
|             "homepage": "http://guzzlephp.org/", | ||||
|             "keywords": [ | ||||
|                 "client", | ||||
|                 "curl", | ||||
|                 "framework", | ||||
|                 "http", | ||||
|                 "http client", | ||||
|                 "rest", | ||||
|                 "web service" | ||||
|             ], | ||||
|             "time": "2017-02-28T22:50:30+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "guzzlehttp/promises", | ||||
|             "version": "v1.3.1", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/guzzle/promises.git", | ||||
|                 "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", | ||||
|                 "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
|                 "php": ">=5.5.0" | ||||
|             }, | ||||
|             "require-dev": { | ||||
|                 "phpunit/phpunit": "^4.0" | ||||
|             }, | ||||
|             "type": "library", | ||||
|             "extra": { | ||||
|                 "branch-alias": { | ||||
|                     "dev-master": "1.4-dev" | ||||
|                 } | ||||
|             }, | ||||
|             "autoload": { | ||||
|                 "psr-4": { | ||||
|                     "GuzzleHttp\\Promise\\": "src/" | ||||
|                 }, | ||||
|                 "files": [ | ||||
|                     "src/functions_include.php" | ||||
|                 ] | ||||
|             }, | ||||
|             "notification-url": "https://packagist.org/downloads/", | ||||
|             "license": [ | ||||
|                 "MIT" | ||||
|             ], | ||||
|             "authors": [ | ||||
|                 { | ||||
|                     "name": "Michael Dowling", | ||||
|                     "email": "mtdowling@gmail.com", | ||||
|                     "homepage": "https://github.com/mtdowling" | ||||
|                 } | ||||
|             ], | ||||
|             "description": "Guzzle promises library", | ||||
|             "keywords": [ | ||||
|                 "promise" | ||||
|             ], | ||||
|             "time": "2016-12-20T10:07:11+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "guzzlehttp/psr7", | ||||
|             "version": "1.4.2", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/guzzle/psr7.git", | ||||
|                 "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c", | ||||
|                 "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
|                 "php": ">=5.4.0", | ||||
|                 "psr/http-message": "~1.0" | ||||
|             }, | ||||
|             "provide": { | ||||
|                 "psr/http-message-implementation": "1.0" | ||||
|             }, | ||||
|             "require-dev": { | ||||
|                 "phpunit/phpunit": "~4.0" | ||||
|             }, | ||||
|             "type": "library", | ||||
|             "extra": { | ||||
|                 "branch-alias": { | ||||
|                     "dev-master": "1.4-dev" | ||||
|                 } | ||||
|             }, | ||||
|             "autoload": { | ||||
|                 "psr-4": { | ||||
|                     "GuzzleHttp\\Psr7\\": "src/" | ||||
|                 }, | ||||
|                 "files": [ | ||||
|                     "src/functions_include.php" | ||||
|                 ] | ||||
|             }, | ||||
|             "notification-url": "https://packagist.org/downloads/", | ||||
|             "license": [ | ||||
|                 "MIT" | ||||
|             ], | ||||
|             "authors": [ | ||||
|                 { | ||||
|                     "name": "Michael Dowling", | ||||
|                     "email": "mtdowling@gmail.com", | ||||
|                     "homepage": "https://github.com/mtdowling" | ||||
|                 }, | ||||
|                 { | ||||
|                     "name": "Tobias Schultze", | ||||
|                     "homepage": "https://github.com/Tobion" | ||||
|                 } | ||||
|             ], | ||||
|             "description": "PSR-7 message implementation that also provides common utility methods", | ||||
|             "keywords": [ | ||||
|                 "http", | ||||
|                 "message", | ||||
|                 "request", | ||||
|                 "response", | ||||
|                 "stream", | ||||
|                 "uri", | ||||
|                 "url" | ||||
|             ], | ||||
|             "time": "2017-03-20T17:10:46+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "paragonie/random_compat", | ||||
|             "version": "v2.0.10", | ||||
| @ -218,6 +396,56 @@ | ||||
|             ], | ||||
|             "time": "2017-03-13T16:27:32+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "psr/http-message", | ||||
|             "version": "1.0.1", | ||||
|             "source": { | ||||
|                 "type": "git", | ||||
|                 "url": "https://github.com/php-fig/http-message.git", | ||||
|                 "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" | ||||
|             }, | ||||
|             "dist": { | ||||
|                 "type": "zip", | ||||
|                 "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", | ||||
|                 "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", | ||||
|                 "shasum": "" | ||||
|             }, | ||||
|             "require": { | ||||
|                 "php": ">=5.3.0" | ||||
|             }, | ||||
|             "type": "library", | ||||
|             "extra": { | ||||
|                 "branch-alias": { | ||||
|                     "dev-master": "1.0.x-dev" | ||||
|                 } | ||||
|             }, | ||||
|             "autoload": { | ||||
|                 "psr-4": { | ||||
|                     "Psr\\Http\\Message\\": "src/" | ||||
|                 } | ||||
|             }, | ||||
|             "notification-url": "https://packagist.org/downloads/", | ||||
|             "license": [ | ||||
|                 "MIT" | ||||
|             ], | ||||
|             "authors": [ | ||||
|                 { | ||||
|                     "name": "PHP-FIG", | ||||
|                     "homepage": "http://www.php-fig.org/" | ||||
|                 } | ||||
|             ], | ||||
|             "description": "Common interface for HTTP messages", | ||||
|             "homepage": "https://github.com/php-fig/http-message", | ||||
|             "keywords": [ | ||||
|                 "http", | ||||
|                 "http-message", | ||||
|                 "psr", | ||||
|                 "psr-7", | ||||
|                 "request", | ||||
|                 "response" | ||||
|             ], | ||||
|             "time": "2016-08-06T14:39:51+00:00" | ||||
|         }, | ||||
|         { | ||||
|             "name": "spomky-labs/otphp", | ||||
|             "version": "v8.3.0", | ||||
|  | ||||
							
								
								
									
										15
									
								
								index.php
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								index.php
									
									
									
									
									
								
							| @ -39,9 +39,12 @@ if ($VARS['progress'] == "1") { | ||||
|     } | ||||
| } else if ($VARS['progress'] == "2") { | ||||
|     if (verifyTOTP($VARS['username'], $VARS['authcode'])) { | ||||
|         doLoginUser($VARS['username'], $VARS['password']); | ||||
|         header('Location: app.php'); | ||||
|         die("Logged in, go to app.php"); | ||||
|         if (doLoginUser($VARS['username'])) { | ||||
|             header('Location: app.php'); | ||||
|             die("Logged in, go to app.php"); | ||||
|         } else { | ||||
|             $alert = lang("login server user data error", false); | ||||
|         } | ||||
|     } else { | ||||
|         $alert = lang("2fa incorrect", false); | ||||
|     } | ||||
| @ -64,7 +67,11 @@ if ($VARS['progress'] == "1") { | ||||
|             <div class="row"> | ||||
|                 <div class="col-xs-12 col-sm-6 col-md-4 col-lg-4 col-sm-offset-3 col-md-offset-4 col-lg-offset-4"> | ||||
|                     <div> | ||||
|                         <img class="img-responsive banner-image" src="static/img/banner.png" /> | ||||
|                         <?php | ||||
|                         if (SHOW_ICON == "both" || SHOW_ICON == "index") { | ||||
|                             ?>
 | ||||
|                             <img class="img-responsive banner-image" src="static/img/logo.png" /> | ||||
|                         <?php } ?>
 | ||||
|                     </div> | ||||
|                     <div class="panel panel-primary"> | ||||
|                         <div class="panel-heading"> | ||||
|  | ||||
| @ -13,30 +13,14 @@ define("STRINGS", [ | ||||
|     "password expired" => "You must change your password before continuing.", | ||||
|     "account terminated" => "Account terminated.  Access denied.", | ||||
|     "account state error" => "Your account state is not stable.  Log out, restart your browser, and try again.", | ||||
|     "password on 500 list" => "The given password is ranked number {arg} out of the 500 most common passwords.  Try a different one.", | ||||
|     "welcome user" => "Welcome, {user}!", | ||||
|     "change password" => "Change password", | ||||
|     "security options" => "Security options", | ||||
|     "account security" => "Account security", | ||||
|     "sign out" => "Sign out", | ||||
|     "settings" => "Settings", | ||||
|     "options" => "Options", | ||||
|     "404 error" => "404 Error", | ||||
|     "page not found" => "Page not found.", | ||||
|     "current password incorrect" => "The current password is incorrect.  Try again.", | ||||
|     "new password mismatch" => "The new passwords did not match.  Try again.", | ||||
|     "weak password" => "Password does not meet requirements.", | ||||
|     "password updated" => "Password updated successfully.", | ||||
|     "setup 2fa" => "Setup 2-factor authentication", | ||||
|     "2fa removed" => "2-factor authentication disabled.", | ||||
|     "2fa enabled" => "2-factor authentication activated.", | ||||
|     "remove 2fa" => "Disable 2-factor authentication", | ||||
|     "2fa explained" => "2-factor authentication adds more security to your account. You'll need an app such as Google Authenticator on your smartphone. When you have the app installed, you can enable 2-factor authentication by clicking the button below and scanning a QR code with the app. Whenever you sign in in the future, you'll need to input a six-digit code from your phone into the login page when prompted. You can disable 2-factor authentication from this page if you change your mind.", | ||||
|     "2fa active" => "2-factor authentication is active on your account.  To remove 2fa, reset your authentication secret, or change to a new security device, click the button below.", | ||||
|     "enable 2fa" => "Enable 2-factor authentication", | ||||
|     "scan 2fa qrcode" => "Scan the QR Code with the authenticator app, or enter the secret key manually.", | ||||
|     "confirm 2fa" => "Finish setup", | ||||
|     "invalid parameters" => "Invalid request parameters.", | ||||
|     "ldap server error" => "The LDAP server returned an error: {arg}", | ||||
|     "login server error" => "The login server returned an error: {arg}", | ||||
|     "login server user data error" => "The login server refused to provide account information.  Try again or contact technical support.", | ||||
|     "home" => "Home", | ||||
| ]); | ||||
							
								
								
									
										369
									
								
								lib/login.php
									
									
									
									
									
								
							
							
						
						
									
										369
									
								
								lib/login.php
									
									
									
									
									
								
							| @ -1,147 +1,98 @@ | ||||
| <?php | ||||
| 
 | ||||
| /** | ||||
|  * Authentication and account functions | ||||
|  * Authentication and account functions.  Connects to a Portal instance. | ||||
|  */ | ||||
| use Base32\Base32; | ||||
| use OTPHP\TOTP; | ||||
| use LdapTools\LdapManager; | ||||
| use LdapTools\Connection\ADResponseCodes; | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| //                           Account handling                                 //
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| /** | ||||
|  * Add a user to the system.  /!\ Assumes input is OK /!\ | ||||
|  * @param string $username Username, saved in lowercase. | ||||
|  * @param string $password Password, will be hashed before saving. | ||||
|  * @param string $realname User's real legal name | ||||
|  * @param string $email User's email address. | ||||
|  * @return int The new user's ID number in the database. | ||||
|  */ | ||||
| function adduser($username, $password, $realname, $email = null, $phone1 = "", $phone2 = "") { | ||||
|     global $database; | ||||
|     $database->debug()->insert('accounts', [ | ||||
|         'username' => strtolower($username), | ||||
|         'password' => (is_null($password) ? null : encryptPassword($password)), | ||||
|         'realname' => $realname, | ||||
|         'email' => $email, | ||||
|         'phone1' => $phone1, | ||||
|         'phone2' => $phone2, | ||||
|         'acctstatus' => 1 | ||||
|     ]); | ||||
| 
 | ||||
|     return $database->id(); | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Get where a user's account actually is. | ||||
|  * @param string $username | ||||
|  * @return string "LDAP", "LOCAL", "LDAP_ONLY", or "NONE". | ||||
|  */ | ||||
| function account_location($username, $password) { | ||||
|     global $database; | ||||
|     $user_exists = user_exists($username); | ||||
|     if (!$user_exists && !LDAP_ENABLED) { | ||||
|         return false; | ||||
|     } | ||||
|     if ($user_exists) { | ||||
|         $userinfo = $database->select('accounts', ['password'], ['username' => $username])[0]; | ||||
|         // if password empty, it's an LDAP user
 | ||||
|         if (is_empty($userinfo['password']) && LDAP_ENABLED) { | ||||
|             return "LDAP"; | ||||
|         } else if (is_empty($userinfo['password']) && !LDAP_ENABLED) { | ||||
|             return "NONE"; | ||||
|         } else { | ||||
|             return "LOCAL"; | ||||
|         } | ||||
|     } else { | ||||
|         if (user_exists_ldap($username, $password)) { | ||||
|             return "LDAP_ONLY"; | ||||
|         } else { | ||||
|             return "NONE"; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Checks the given credentials against the database. | ||||
|  * Checks the given credentials against the API. | ||||
|  * @param string $username | ||||
|  * @param string $password | ||||
|  * @return boolean True if OK, else false | ||||
|  */ | ||||
| function authenticate_user($username, $password) { | ||||
|     global $database; | ||||
|     global $ldap_config; | ||||
|     if (is_empty($username) || is_empty($password)) { | ||||
|         return false; | ||||
|     $client = new GuzzleHttp\Client(); | ||||
| 
 | ||||
|     $response = $client | ||||
|             ->request('POST', PORTAL_API, [ | ||||
|         'form_params' => [ | ||||
|             'key' => PORTAL_KEY, | ||||
|             'action' => "auth", | ||||
|             'username' => $username, | ||||
|             'password' => $password | ||||
|         ] | ||||
|     ]); | ||||
| 
 | ||||
|     if ($response->getStatusCode() > 299) { | ||||
|         sendError("Login server error: " . $response->getBody()); | ||||
|     } | ||||
|     $loc = account_location($username, $password); | ||||
|     if ($loc == "NONE") { | ||||
|         return false; | ||||
|     } else if ($loc == "LOCAL") { | ||||
|         $hash = $database->select('accounts', ['password'], ['username' => $username, "LIMIT" => 1])[0]['password']; | ||||
|         return (comparePassword($password, $hash)); | ||||
|     } else if ($loc == "LDAP") { | ||||
|         return authenticate_user_ldap($username, $password); | ||||
|     } else if ($loc == "LDAP_ONLY") { | ||||
|         if (authenticate_user_ldap($username, $password) === TRUE) { | ||||
|             try { | ||||
|                 $user = (new LdapManager($ldap_config))->getRepository('user')->findOneByUsername($username); | ||||
|                 var_dump($user); | ||||
|                 adduser($user->getUsername(), null, $user->getName(), ($user->hasEmailAddress() ? $user->getEmailAddress() : null)); | ||||
|                 return true; | ||||
|             } catch (Exception $e) { | ||||
|                 sendError("LDAP error: " . $e->getMessage()); | ||||
|             } | ||||
|         } else { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|     $resp = json_decode($response->getBody(), TRUE); | ||||
|     if ($resp['status'] == "OK") { | ||||
|         return true; | ||||
|     } else { | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Check if a username exists in the local database. | ||||
|  * Check if a username exists. | ||||
|  * @param String $username | ||||
|  */ | ||||
| function user_exists($username) { | ||||
|     global $database; | ||||
|     return $database->has('accounts', ['username' => $username, "LIMIT" => QUERY_LIMIT]); | ||||
|     $client = new GuzzleHttp\Client(); | ||||
| 
 | ||||
|     $response = $client | ||||
|             ->request('POST', PORTAL_API, [ | ||||
|         'form_params' => [ | ||||
|             'key' => PORTAL_KEY, | ||||
|             'action' => "userexists", | ||||
|             'username' => $username | ||||
|         ] | ||||
|     ]); | ||||
| 
 | ||||
|     if ($response->getStatusCode() > 299) { | ||||
|         sendError("Login server error: " . $response->getBody()); | ||||
|     } | ||||
| 
 | ||||
|     $resp = json_decode($response->getBody(), TRUE); | ||||
|     if ($resp['status'] == "OK" && $resp['exists'] === true) { | ||||
|         return true; | ||||
|     } else { | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Get the account status: NORMAL, TERMINATED, LOCKED_OR_DISABLED, | ||||
|  * CHANGE_PASSWORD, or ALERT_ON_ACCESS | ||||
|  * @global $database $database | ||||
|  * @param string $username | ||||
|  * @return string | ||||
|  */ | ||||
| function get_account_status($username) { | ||||
|     global $database; | ||||
|     $loc = account_location($username); | ||||
|     if ($loc == "LOCAL") { | ||||
|         $statuscode = $database->select('accounts', [ | ||||
|                     '[>]acctstatus' => [ | ||||
|                         'acctstatus' => 'statusid' | ||||
|                     ] | ||||
|                         ], [ | ||||
|                     'accounts.acctstatus', | ||||
|                     'acctstatus.statuscode' | ||||
|                         ], [ | ||||
|                     'username' => $username, | ||||
|                     "LIMIT" => 1 | ||||
|                         ] | ||||
|                 )[0]['statuscode']; | ||||
|         return $statuscode; | ||||
|     } else if ($loc == "LDAP") { | ||||
|         // TODO: Read actual account status from AD servers
 | ||||
|         return "NORMAL"; | ||||
|     $client = new GuzzleHttp\Client(); | ||||
| 
 | ||||
|     $response = $client | ||||
|             ->request('POST', PORTAL_API, [ | ||||
|         'form_params' => [ | ||||
|             'key' => PORTAL_KEY, | ||||
|             'action' => "acctstatus", | ||||
|             'username' => $username | ||||
|         ] | ||||
|     ]); | ||||
| 
 | ||||
|     if ($response->getStatusCode() > 299) { | ||||
|         sendError("Login server error: " . $response->getBody()); | ||||
|     } | ||||
| 
 | ||||
|     $resp = json_decode($response->getBody(), TRUE); | ||||
|     if ($resp['status'] == "OK") { | ||||
|         return $resp['account']; | ||||
|     } else { | ||||
|         // account isn't setup properly
 | ||||
|         return "LOCKED_OR_DISABLED"; | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -150,93 +101,64 @@ function get_account_status($username) { | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| /** | ||||
|  * Setup $_SESSION values to log in a user | ||||
|  * Setup $_SESSION values with user data and set loggedin flag to true | ||||
|  * @param string $username | ||||
|  */ | ||||
| function doLoginUser($username, $password) { | ||||
|     global $database; | ||||
|     $userinfo = $database->select('accounts', ['email', 'uid', 'realname'], ['username' => $username])[0]; | ||||
|     $_SESSION['username'] = $username; | ||||
|     $_SESSION['uid'] = $userinfo['uid']; | ||||
|     $_SESSION['email'] = $userinfo['email']; | ||||
|     $_SESSION['realname'] = $userinfo['realname']; | ||||
|     $_SESSION['password'] = $password; // needed for things like EWS
 | ||||
|     $_SESSION['loggedin'] = true; | ||||
| } | ||||
| function doLoginUser($username) { | ||||
|     $client = new GuzzleHttp\Client(); | ||||
| 
 | ||||
| /** | ||||
|  * Send an alert email to the system admin | ||||
|  *  | ||||
|  * Used when an account with the status ALERT_ON_ACCESS logs in | ||||
|  * @param String $username the account username | ||||
|  */ | ||||
| function sendLoginAlertEmail($username) { | ||||
|     // TODO: add email code
 | ||||
| } | ||||
|     $response = $client | ||||
|             ->request('POST', PORTAL_API, [ | ||||
|         'form_params' => [ | ||||
|             'key' => PORTAL_KEY, | ||||
|             'action' => "userinfo", | ||||
|             'username' => $username | ||||
|         ] | ||||
|     ]); | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| //                              LDAP handling                                 //
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| /** | ||||
|  * Checks the given credentials against the LDAP server. | ||||
|  * @param string $username | ||||
|  * @param string $password | ||||
|  * @return mixed True if OK, else false or the error code from the server | ||||
|  */ | ||||
| function authenticate_user_ldap($username, $password) { | ||||
|     global $ldap_config; | ||||
|     if (is_empty($username) || is_empty($password)) { | ||||
|         return false; | ||||
|     if ($response->getStatusCode() > 299) { | ||||
|         sendError("Login server error: " . $response->getBody()); | ||||
|     } | ||||
|     $ldapManager = new LdapManager($ldap_config); | ||||
|     $msg = ""; | ||||
|     $code = 0; | ||||
|     if ($ldapManager->authenticate($username, $password, $msg, $code)) { | ||||
| 
 | ||||
|     $resp = json_decode($response->getBody(), TRUE); | ||||
|     var_dump($resp); | ||||
|     if ($resp['status'] == "OK") { | ||||
|         $userinfo = $resp['data']; | ||||
|         $_SESSION['username'] = $username; | ||||
|         $_SESSION['uid'] = $userinfo['uid']; | ||||
|         $_SESSION['email'] = $userinfo['email']; | ||||
|         $_SESSION['realname'] = $userinfo['name']; | ||||
|         $_SESSION['password'] = $password; | ||||
|         $_SESSION['loggedin'] = true; | ||||
|         return true; | ||||
|     } else { | ||||
|         return $code; | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Check if a username exists on the LDAP server. | ||||
|  * @global type $ldap_config | ||||
|  * @param type $username | ||||
|  * @return boolean true if yes, else false | ||||
|  */ | ||||
| function user_exists_ldap($username, $password) { | ||||
|     global $ldap_config; | ||||
|     $ldap = new LdapManager($ldap_config); | ||||
|     if (!$ldap->authenticate($username, $password, $message, $code)) { | ||||
|         switch ($code) { | ||||
|             case ADResponseCodes::ACCOUNT_INVALID: | ||||
|                 return false; | ||||
|             case ADResponseCodes::ACCOUNT_CREDENTIALS_INVALID: | ||||
|                 return true; | ||||
|             case ADResponseCodes::ACCOUNT_RESTRICTIONS: | ||||
|                 return true; | ||||
|             case ADResponseCodes::ACCOUNT_RESTRICTIONS_TIME: | ||||
|                 return true; | ||||
|             case ADResponseCodes::ACCOUNT_RESTRICTIONS_DEVICE: | ||||
|                 return true; | ||||
|             case ADResponseCodes::ACCOUNT_PASSWORD_EXPIRED: | ||||
|                 return true; | ||||
|             case ADResponseCodes::ACCOUNT_DISABLED: | ||||
|                 return true; | ||||
|             case ADResponseCodes::ACCOUNT_CONTEXT_IDS: | ||||
|                 return true; | ||||
|             case ADResponseCodes::ACCOUNT_EXPIRED: | ||||
|                 return false; | ||||
|             case ADResponseCodes::ACCOUNT_PASSWORD_MUST_CHANGE: | ||||
|                 return true; | ||||
|             case ADResponseCodes::ACCOUNT_LOCKED: | ||||
|                 return true; | ||||
|             default: | ||||
|                 return false; | ||||
|         } | ||||
| function simLogin($username, $password) { | ||||
|     $client = new GuzzleHttp\Client(); | ||||
| 
 | ||||
|     $response = $client | ||||
|             ->request('POST', PORTAL_API, [ | ||||
|         'form_params' => [ | ||||
|             'key' => PORTAL_KEY, | ||||
|             'action' => "login", | ||||
|             'username' => $username, | ||||
|             'password' => $password | ||||
|         ] | ||||
|     ]); | ||||
| 
 | ||||
|     if ($response->getStatusCode() > 299) { | ||||
|         sendError("Login server error: " . $response->getBody()); | ||||
|     } | ||||
| 
 | ||||
|     $resp = json_decode($response->getBody(), TRUE); | ||||
|     if ($resp['status'] == "OK") { | ||||
|         return true; | ||||
|     } else { | ||||
|         return $resp['msg']; | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| @ -245,43 +167,31 @@ function user_exists_ldap($username, $password) { | ||||
| 
 | ||||
| /** | ||||
|  * Check if a user has TOTP setup | ||||
|  * @global $database $database | ||||
|  * @param string $username | ||||
|  * @return boolean true if TOTP secret exists, else false | ||||
|  */ | ||||
| function userHasTOTP($username) { | ||||
|     global $database; | ||||
|     $secret = $database->select('accounts', 'authsecret', ['username' => $username])[0]; | ||||
|     if (is_empty($secret)) { | ||||
|     $client = new GuzzleHttp\Client(); | ||||
| 
 | ||||
|     $response = $client | ||||
|             ->request('POST', PORTAL_API, [ | ||||
|         'form_params' => [ | ||||
|             'key' => PORTAL_KEY, | ||||
|             'action' => "hastotp", | ||||
|             'username' => $username | ||||
|         ] | ||||
|     ]); | ||||
| 
 | ||||
|     if ($response->getStatusCode() > 299) { | ||||
|         sendError("Login server error: " . $response->getBody()); | ||||
|     } | ||||
| 
 | ||||
|     $resp = json_decode($response->getBody(), TRUE); | ||||
|     if ($resp['status'] == "OK") { | ||||
|         return $resp['otp']; | ||||
|     } else { | ||||
|         return false; | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Generate a TOTP secret for the given user. | ||||
|  * @param string $username | ||||
|  * @return string OTP provisioning URI (for generating a QR code) | ||||
|  */ | ||||
| function newTOTP($username) { | ||||
|     global $database; | ||||
|     $secret = random_bytes(20); | ||||
|     $encoded_secret = Base32::encode($secret); | ||||
|     $userdata = $database->select('accounts', ['email', 'authsecret', 'realname'], ['username' => $username])[0]; | ||||
|     $totp = new TOTP((is_null($userdata['email']) ? $userdata['realname'] : $userdata['email']), $encoded_secret); | ||||
|     $totp->setIssuer(SYSTEM_NAME); | ||||
|     return $totp->getProvisioningUri(); | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Save a TOTP secret for the user. | ||||
|  * @global $database $database | ||||
|  * @param string $username | ||||
|  * @param string $secret | ||||
|  */ | ||||
| function saveTOTP($username, $secret) { | ||||
|     global $database; | ||||
|     $database->update('accounts', ['authsecret' => $secret], ['username' => $username]); | ||||
| } | ||||
| 
 | ||||
| /** | ||||
| @ -292,11 +202,26 @@ function saveTOTP($username, $secret) { | ||||
|  * @return boolean true if it's legit, else false | ||||
|  */ | ||||
| function verifyTOTP($username, $code) { | ||||
|     global $database; | ||||
|     $userdata = $database->select('accounts', ['email', 'authsecret'], ['username' => $username])[0]; | ||||
|     if (is_empty($userdata['authsecret'])) { | ||||
|     $client = new GuzzleHttp\Client(); | ||||
| 
 | ||||
|     $response = $client | ||||
|             ->request('POST', PORTAL_API, [ | ||||
|         'form_params' => [ | ||||
|             'key' => PORTAL_KEY, | ||||
|             'action' => "verifytotp", | ||||
|             'username' => $username, | ||||
|             'code' => $code | ||||
|         ] | ||||
|     ]); | ||||
| 
 | ||||
|     if ($response->getStatusCode() > 299) { | ||||
|         sendError("Login server error: " . $response->getBody()); | ||||
|     } | ||||
| 
 | ||||
|     $resp = json_decode($response->getBody(), TRUE); | ||||
|     if ($resp['status'] == "OK") { | ||||
|         return $resp['valid']; | ||||
|     } else { | ||||
|         return false; | ||||
|     } | ||||
|     $totp = new TOTP(null, $userdata['authsecret']); | ||||
|     return $totp->verify($code); | ||||
| } | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
|     <type>org.netbeans.modules.php.project</type> | ||||
|     <configuration> | ||||
|         <data xmlns="http://www.netbeans.org/ns/php-project/1"> | ||||
|             <name>WebAppTemplate</name> | ||||
|             <name>BusinessAppTemplate</name> | ||||
|         </data> | ||||
|     </configuration> | ||||
| </project> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
| // List of pages and metadata
 | ||||
| define("PAGES", [ | ||||
|     "home" => [ | ||||
|         "title" => "home" | ||||
|         "title" => "home", | ||||
|         "navbar" => true, | ||||
|         "icon" => "home" | ||||
|     ], | ||||
|     "404" => [ | ||||
|         "title" => "404 error" | ||||
|  | ||||
| @ -18,6 +18,20 @@ define("SITE_TITLE", "Web App Template"); | ||||
| // Used to identify the system in OTP and other places
 | ||||
| define("SYSTEM_NAME", "Web App Template"); | ||||
| 
 | ||||
| // Which pages to show the app icon on:
 | ||||
| // index, app, both, none
 | ||||
| define("SHOW_ICON", "both"); | ||||
| // Where to put the icon: top or menu
 | ||||
| // Overridden to 'menu' if MENU_BAR_STYLE is 'fixed'.
 | ||||
| define("ICON_POSITION", "menu"); | ||||
| // App menu bar style: fixed or static
 | ||||
| define("MENU_BAR_STYLE", "fixed"); | ||||
| 
 | ||||
| // URL of the Business Portal API endpoint
 | ||||
| define("PORTAL_API", "http://localhost/api.php"); | ||||
| // Business Portal API Key
 | ||||
| define("PORTAL_KEY", "123"); | ||||
| 
 | ||||
| // For supported values, see http://php.net/manual/en/timezones.php
 | ||||
| define("TIMEZONE", "America/Denver"); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								static/img/logo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								static/img/logo.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 12 KiB | 
							
								
								
									
										78
									
								
								static/img/logo.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								static/img/logo.svg
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,78 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
| 
 | ||||
| <svg | ||||
|    xmlns:dc="http://purl.org/dc/elements/1.1/" | ||||
|    xmlns:cc="http://creativecommons.org/ns#" | ||||
|    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    width="512" | ||||
|    height="512" | ||||
|    viewBox="0 0 512.00001 512.00001" | ||||
|    id="svg2" | ||||
|    version="1.1" | ||||
|    inkscape:version="0.91 r13725" | ||||
|    sodipodi:docname="logo.svg" | ||||
|    inkscape:export-filename="/home/skylar/Documents/Projects/Sources/WebAppTemplate/static/img/logo.png" | ||||
|    inkscape:export-xdpi="90" | ||||
|    inkscape:export-ydpi="90"> | ||||
|   <defs | ||||
|      id="defs4"> | ||||
|     <inkscape:perspective | ||||
|        sodipodi:type="inkscape:persp3d" | ||||
|        inkscape:vp_x="-493.3276 : 245.89848 : 1" | ||||
|        inkscape:vp_y="0 : 1000 : 0" | ||||
|        inkscape:vp_z="464.45088 : 245.89848 : 1" | ||||
|        inkscape:persp3d-origin="-14.438371 : 160.56515 : 1" | ||||
|        id="perspective4236" /> | ||||
|   </defs> | ||||
|   <sodipodi:namedview | ||||
|      id="base" | ||||
|      pagecolor="#ffffff" | ||||
|      bordercolor="#666666" | ||||
|      borderopacity="1.0" | ||||
|      inkscape:pageopacity="0.0" | ||||
|      inkscape:pageshadow="2" | ||||
|      inkscape:zoom="0.49497475" | ||||
|      inkscape:cx="-135.9681" | ||||
|      inkscape:cy="352.66131" | ||||
|      inkscape:document-units="px" | ||||
|      inkscape:current-layer="layer1" | ||||
|      showgrid="false" | ||||
|      units="px" /> | ||||
|   <metadata | ||||
|      id="metadata7"> | ||||
|     <rdf:RDF> | ||||
|       <cc:Work | ||||
|          rdf:about=""> | ||||
|         <dc:format>image/svg+xml</dc:format> | ||||
|         <dc:type | ||||
|            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||||
|         <dc:title></dc:title> | ||||
|       </cc:Work> | ||||
|     </rdf:RDF> | ||||
|   </metadata> | ||||
|   <g | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      id="layer1" | ||||
|      transform="translate(0,-540.36216)"> | ||||
|     <rect | ||||
|        style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.74509804" | ||||
|        id="rect4726" | ||||
|        width="512" | ||||
|        height="512" | ||||
|        x="0" | ||||
|        y="540.36218" | ||||
|        rx="50" | ||||
|        ry="50" /> | ||||
|     <path | ||||
|        id="path4348" | ||||
|        style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:9.87128067;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" | ||||
|        d="m 132.93564,682.51771 213.96788,-43.14304 0,313.97496 -213.96788,-37.9643 z m 213.96788,-43.14304 0,313.97496 32.16084,-45.18373 0,-217.44396 z m -213.96788,43.14304 213.96788,-43.14304 32.16084,51.34727 -167.21823,22.47784 z m 78.91049,30.68207 167.21823,-22.47784 0,217.44396 -167.21823,-19.77968 z m -78.91049,-30.68207 0,232.86762 78.91049,-26.99911 0,-175.18644 z m 0,232.86762 213.96788,37.9643 32.16084,-45.18373 -167.21823,-19.77968 z" | ||||
|        inkscape:connector-curvature="0" /> | ||||
|   </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 2.9 KiB | 
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user