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