Add API, auth logging, AD support
TODO: Test changing AD passwords
This commit is contained in:
parent
8b091c59f6
commit
5929d13147
35
action.php
35
action.php
@ -3,10 +3,14 @@
|
||||
/**
|
||||
* Make things happen when buttons are pressed and forms submitted.
|
||||
*/
|
||||
use LdapTools\LdapManager;
|
||||
use LdapTools\Object\LdapObjectType;
|
||||
|
||||
require_once __DIR__ . "/required.php";
|
||||
|
||||
dieifnotloggedin();
|
||||
|
||||
require_once __DIR__ . "/lib/login.php";
|
||||
require_once __DIR__ . "/lib/worst_passwords.php";
|
||||
|
||||
function returnToSender($msg, $arg = "") {
|
||||
@ -21,12 +25,12 @@ function returnToSender($msg, $arg = "") {
|
||||
|
||||
switch ($VARS['action']) {
|
||||
case "signout":
|
||||
insertAuthLog(11, $_SESSION['uid']);
|
||||
session_destroy();
|
||||
header('Location: index.php');
|
||||
die("Logged out.");
|
||||
case "chpasswd":
|
||||
$oldmatch = comparePassword($VARS['oldpass'], $database->select('accounts', 'password', ['uid' => $_SESSION['uid']])[0]);
|
||||
if ($oldmatch) {
|
||||
if ($_SESSION['password'] == $VARS['oldpass']) {
|
||||
if ($VARS['newpass'] == $VARS['conpass']) {
|
||||
$passrank = checkWorst500List($VARS['newpass']);
|
||||
if ($passrank !== FALSE) {
|
||||
@ -35,8 +39,29 @@ switch ($VARS['action']) {
|
||||
if (strlen($VARS['newpass']) < MIN_PASSWORD_LENGTH) {
|
||||
returnToSender("weak_password");
|
||||
}
|
||||
$database->update('accounts', ['password' => encryptPassword($VARS['newpass'])], ['uid' => $_SESSION['uid']]);
|
||||
returnToSender("password_updated");
|
||||
|
||||
$acctloc = account_location($_SESSION['username'], $_SESSION['password']);
|
||||
|
||||
if ($acctloc == "LOCAL") {
|
||||
$database->update('accounts', ['password' => encryptPassword($VARS['newpass'])], ['uid' => $_SESSION['uid']]);
|
||||
$_SESSION['password'] = $VARS['newpass'];
|
||||
insertAuthLog(3, $_SESSION['uid']);
|
||||
returnToSender("password_updated");
|
||||
} else if ($acctloc == "LDAP") {
|
||||
$ldapManager = new LdapManager($ldap_config);
|
||||
$repository = $ldapManager->getRepository(LdapObjectType::USER);
|
||||
$user = $repository->findOneByUsername($_SESSION['username']);
|
||||
$user->setPassword($VARS['newpass']);
|
||||
try {
|
||||
$ldapManager->persist($user);
|
||||
insertAuthLog(3, $_SESSION['uid']);
|
||||
returnToSender("password_updated");
|
||||
} catch (\Exception $e) {
|
||||
returnToSender("ldap_error", $e->getMessage());
|
||||
}
|
||||
} else {
|
||||
returnToSender("account_state_error");
|
||||
}
|
||||
} else {
|
||||
returnToSender("new_password_mismatch");
|
||||
}
|
||||
@ -49,9 +74,11 @@ switch ($VARS['action']) {
|
||||
returnToSender("invalid_parameters");
|
||||
}
|
||||
$database->update('accounts', ['authsecret' => $VARS['secret']], ['uid' => $_SESSION['uid']]);
|
||||
insertAuthLog(9, $_SESSION['uid']);
|
||||
returnToSender("2fa_enabled");
|
||||
case "rm2fa":
|
||||
$database->update('accounts', ['authsecret' => ""], ['uid' => $_SESSION['uid']]);
|
||||
insertAuthLog(10, $_SESSION['uid']);
|
||||
returnToSender("2fa_removed");
|
||||
break;
|
||||
}
|
119
api.php
Normal file
119
api.php
Normal file
@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Simple JSON API to allow other apps to access accounts in this system.
|
||||
*
|
||||
* Requests can be sent via either GET or POST requests. POST is recommended
|
||||
* as it has a lower chance of being logged on the server, exposing unencrypted
|
||||
* user passwords.
|
||||
*/
|
||||
require __DIR__ . '/required.php';
|
||||
require_once __DIR__ . '/lib/login.php';
|
||||
header("Content-Type: application/json");
|
||||
|
||||
//try {
|
||||
$key = $VARS['key'];
|
||||
if ($database->has('apikeys', ['key' => $key]) !== TRUE) {
|
||||
header("HTTP/1.1 403 Unauthorized");
|
||||
die("\"403 Unauthorized\"");
|
||||
}
|
||||
|
||||
switch ($VARS['action']) {
|
||||
case "ping":
|
||||
exit(json_encode(["status" => "OK"]));
|
||||
break;
|
||||
case "auth":
|
||||
if (authenticate_user($VARS['username'], $VARS['password'])) {
|
||||
insertAuthLog(12);
|
||||
exit(json_encode(["status" => "OK", "msg" => lang("login successful", false)]));
|
||||
} else {
|
||||
insertAuthLog(13);
|
||||
exit(json_encode(["status" => "ERROR", "msg" => lang("login incorrect", false)]));
|
||||
}
|
||||
break;
|
||||
case "userinfo":
|
||||
if (user_exists($VARS['username'])) {
|
||||
$data = $database->select("accounts", ["uid", "realname (name)", "email", "phone" => ["phone1 (1)", "phone2 (2)"]], ["username" => $VARS['username']])[0];
|
||||
exit(json_encode(["status" => "OK", "data" => $data]));
|
||||
} else {
|
||||
exit(json_encode(["status" => "ERROR", "msg" => lang("login incorrect", false)]));
|
||||
}
|
||||
break;
|
||||
case "userexists":
|
||||
if (user_exists($VARS['username'])) {
|
||||
exit(json_encode(["status" => "OK", "exists" => true]));
|
||||
} else {
|
||||
exit(json_encode(["status" => "OK", "exists" => false]));
|
||||
}
|
||||
break;
|
||||
case "hastotp":
|
||||
if (userHasTOTP($VARS['username'])) {
|
||||
exit(json_encode(["status" => "OK", "otp" => true]));
|
||||
} else {
|
||||
exit(json_encode(["status" => "OK", "otp" => false]));
|
||||
}
|
||||
break;
|
||||
case "verifytotp":
|
||||
if (verifyTOTP($VARS['username'], $VARS['code'])) {
|
||||
exit(json_encode(["status" => "OK", "valid" => true]));
|
||||
} else {
|
||||
insertAuthLog(7);
|
||||
exit(json_encode(["status" => "ERROR", "msg" => lang("2fa incorrect", false), "valid" => false]));
|
||||
}
|
||||
break;
|
||||
case "acctstatus":
|
||||
exit(json_encode(["status" => "OK", "account" => get_account_status($VARS['username'])]));
|
||||
case "login":
|
||||
// simulate a login, checking account status and alerts
|
||||
if (authenticate_user($VARS['username'], $VARS['password'])) {
|
||||
switch (get_account_status($VARS['username'])) {
|
||||
case "LOCKED_OR_DISABLED":
|
||||
insertAuthLog(5);
|
||||
exit(json_encode(["status" => "ERROR", "msg" => lang("account locked", false)]));
|
||||
case "TERMINATED":
|
||||
insertAuthLog(5);
|
||||
exit(json_encode(["status" => "ERROR", "msg" => lang("account terminated", false)]));
|
||||
case "CHANGE_PASSWORD":
|
||||
insertAuthLog(5);
|
||||
exit(json_encode(["status" => "ERROR", "msg" => lang("password expired", false)]));
|
||||
case "NORMAL":
|
||||
insertAuthLog(4);
|
||||
exit(json_encode(["status" => "OK"]));
|
||||
case "ALERT_ON_ACCESS":
|
||||
sendLoginAlertEmail($VARS['username']);
|
||||
insertAuthLog(4);
|
||||
exit(json_encode(["status" => "OK", "alert" => true]));
|
||||
default:
|
||||
insertAuthLog(5);
|
||||
exit(json_encode(["status" => "ERROR", "msg" => lang("account state error", false)]));
|
||||
}
|
||||
} else {
|
||||
insertAuthLog(5);
|
||||
exit(json_encode(["status" => "ERROR", "msg" => lang("login incorrect", false)]));
|
||||
}
|
||||
break;
|
||||
case "ismanagerof":
|
||||
if (user_exists($VARS['manager'])) {
|
||||
if (user_exists($VARS['employee'])) {
|
||||
$managerid = $database->select('accounts', 'uid', ['username' => $VARS['manager']]);
|
||||
$employeeid = $database->select('accounts', 'uid', ['username' => $VARS['employee']]);
|
||||
if ($database->has('managers', ['AND' => ['managerid' => $managerid, 'employeeid' => $employeeid]])) {
|
||||
exit(json_encode(["status" => "OK", "managerof" => true]));
|
||||
} else {
|
||||
exit(json_encode(["status" => "OK", "managerof" => false]));
|
||||
}
|
||||
} else {
|
||||
exit(json_encode(["status" => "ERROR", "msg" => lang("user does not exist", false), "user" => $VARS['employee']]));
|
||||
}
|
||||
} else {
|
||||
exit(json_encode(["status" => "ERROR", "msg" => lang("user does not exist", false), "user" => $VARS['manager']]));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
header("HTTP/1.1 400 Bad Request");
|
||||
die("\"400 Bad Request\"");
|
||||
}
|
||||
/* } catch (Exception $e) {
|
||||
header("HTTP/1.1 500 Internal Server Error");
|
||||
die("\"500 Internal Server Error\"");
|
||||
} */
|
@ -5,7 +5,9 @@
|
||||
"require": {
|
||||
"catfan/medoo": "^1.2",
|
||||
"spomky-labs/otphp": "^8.3",
|
||||
"endroid/qrcode": "^1.9"
|
||||
"endroid/qrcode": "^1.9",
|
||||
"ldaptools/ldaptools": "^0.24.0",
|
||||
"guzzlehttp/guzzle": "^6.2"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
|
487
composer.lock
generated
487
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": "3d5a548f8a7cbbd0c911987b1fab33a5",
|
||||
"content-hash": "4965262916e04d361db07e7f14ed06d6",
|
||||
"packages": [
|
||||
{
|
||||
"name": "beberlei/assert",
|
||||
@ -230,6 +230,244 @@
|
||||
],
|
||||
"time": "2017-04-08T09:13:59+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": "ldaptools/ldaptools",
|
||||
"version": "v0.24.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ldaptools/ldaptools.git",
|
||||
"reference": "31e05ae6082fc7e61afc666e2c773ee8cb0e47b5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ldaptools/ldaptools/zipball/31e05ae6082fc7e61afc666e2c773ee8cb0e47b5",
|
||||
"reference": "31e05ae6082fc7e61afc666e2c773ee8cb0e47b5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-ldap": "*",
|
||||
"php": ">=5.6",
|
||||
"ramsey/uuid": ">=3.0",
|
||||
"symfony/event-dispatcher": ">=2.0",
|
||||
"symfony/yaml": ">=2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/cache": "~1.0",
|
||||
"friendsofphp/php-cs-fixer": "~1.0",
|
||||
"phpspec/phpspec": "~3.0",
|
||||
"tedivm/stash": ">=0.14.1"
|
||||
},
|
||||
"suggest": {
|
||||
"doctrine/cache": "Provides the cache_type 'doctrine' to help increase performance.",
|
||||
"ext-intl": "Better UTF-8 handling.",
|
||||
"ext-mbstring": "Better UTF-8 handling.",
|
||||
"tedivm/stash": "Provides the cache_type 'stash' to help increase performance."
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"LdapTools\\": "src/LdapTools"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Chad Sikorra",
|
||||
"email": "Chad.Sikorra@gmail.com",
|
||||
"homepage": "http://www.chadsikorra.com"
|
||||
}
|
||||
],
|
||||
"description": "LdapTools is a feature-rich LDAP library for PHP 5.6+.",
|
||||
"homepage": "http://www.phpldaptools.com",
|
||||
"keywords": [
|
||||
"Microsoft Exchange",
|
||||
"active directory",
|
||||
"ldap",
|
||||
"openldap"
|
||||
],
|
||||
"time": "2017-04-09T23:39:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/random_compat",
|
||||
"version": "v2.0.10",
|
||||
@ -278,6 +516,138 @@
|
||||
],
|
||||
"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": "ramsey/uuid",
|
||||
"version": "3.6.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ramsey/uuid.git",
|
||||
"reference": "4ae32dd9ab8860a4bbd750ad269cba7f06f7934e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ramsey/uuid/zipball/4ae32dd9ab8860a4bbd750ad269cba7f06f7934e",
|
||||
"reference": "4ae32dd9ab8860a4bbd750ad269cba7f06f7934e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"paragonie/random_compat": "^1.0|^2.0",
|
||||
"php": "^5.4 || ^7.0"
|
||||
},
|
||||
"replace": {
|
||||
"rhumsaa/uuid": "self.version"
|
||||
},
|
||||
"require-dev": {
|
||||
"apigen/apigen": "^4.1",
|
||||
"codeception/aspect-mock": "^1.0 | ^2.0",
|
||||
"doctrine/annotations": "~1.2.0",
|
||||
"goaop/framework": "1.0.0-alpha.2 | ^1.0 | ^2.1",
|
||||
"ircmaxell/random-lib": "^1.1",
|
||||
"jakub-onderka/php-parallel-lint": "^0.9.0",
|
||||
"mockery/mockery": "^0.9.4",
|
||||
"moontoast/math": "^1.1",
|
||||
"php-mock/php-mock-phpunit": "^0.3|^1.1",
|
||||
"phpunit/phpunit": "^4.7|>=5.0 <5.4",
|
||||
"satooshi/php-coveralls": "^0.6.1",
|
||||
"squizlabs/php_codesniffer": "^2.3"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator",
|
||||
"ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator",
|
||||
"ircmaxell/random-lib": "Provides RandomLib for use with the RandomLibAdapter",
|
||||
"moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).",
|
||||
"ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid",
|
||||
"ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Ramsey\\Uuid\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Marijn Huizendveld",
|
||||
"email": "marijn.huizendveld@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Thibaud Fabre",
|
||||
"email": "thibaud@aztech.io"
|
||||
},
|
||||
{
|
||||
"name": "Ben Ramsey",
|
||||
"email": "ben@benramsey.com",
|
||||
"homepage": "https://benramsey.com"
|
||||
}
|
||||
],
|
||||
"description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).",
|
||||
"homepage": "https://github.com/ramsey/uuid",
|
||||
"keywords": [
|
||||
"guid",
|
||||
"identifier",
|
||||
"uuid"
|
||||
],
|
||||
"time": "2017-03-26T20:37:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spomky-labs/otphp",
|
||||
"version": "v8.3.0",
|
||||
@ -342,6 +712,66 @@
|
||||
],
|
||||
"time": "2016-12-08T10:46:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/event-dispatcher",
|
||||
"version": "v3.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/event-dispatcher.git",
|
||||
"reference": "154bb1ef7b0e42ccc792bd53edbce18ed73440ca"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/154bb1ef7b0e42ccc792bd53edbce18ed73440ca",
|
||||
"reference": "154bb1ef7b0e42ccc792bd53edbce18ed73440ca",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5.9"
|
||||
},
|
||||
"require-dev": {
|
||||
"psr/log": "~1.0",
|
||||
"symfony/config": "~2.8|~3.0",
|
||||
"symfony/dependency-injection": "~2.8|~3.0",
|
||||
"symfony/expression-language": "~2.8|~3.0",
|
||||
"symfony/stopwatch": "~2.8|~3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/dependency-injection": "",
|
||||
"symfony/http-kernel": ""
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\EventDispatcher\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony EventDispatcher Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-04-04T07:26:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/options-resolver",
|
||||
"version": "v3.2.7",
|
||||
@ -562,6 +992,61 @@
|
||||
"shim"
|
||||
],
|
||||
"time": "2016-11-14T01:06:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v3.2.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "62b4cdb99d52cb1ff253c465eb1532a80cebb621"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/62b4cdb99d52cb1ff253c465eb1532a80cebb621",
|
||||
"reference": "62b4cdb99d52cb1ff253c465eb1532a80cebb621",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5.9"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/console": "~2.8|~3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/console": "For validating YAML files using the lint command"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Yaml\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-03-20T09:45:15+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
|
BIN
database.mwb
BIN
database.mwb
Binary file not shown.
7
home.php
7
home.php
@ -34,7 +34,7 @@ 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" />
|
||||
<img class="img-responsive banner-image" src="static/img/logo.svg" />
|
||||
</div>
|
||||
</div>
|
||||
<nav class="navbar navbar-inverse">
|
||||
@ -130,17 +130,18 @@ END;
|
||||
if ($appcount == 1) {
|
||||
?>
|
||||
<div class="hidden-xs col-sm-3 col-md-4 col-lg-4">
|
||||
<!-- Placeholder column for nice center-align -->
|
||||
<!-- Empty placeholder column for nice center-align -->
|
||||
</div>
|
||||
<?php
|
||||
} else if ($appcount == 2) {
|
||||
?>
|
||||
<div class="hidden-xs hidden-sm col-md-2 col-lg-2">
|
||||
<!-- Placeholder column for nice center-align -->
|
||||
<!-- Empty placeholder column for nice center-align -->
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
// Load app widgets
|
||||
foreach (APPS[$pageid] as $app) {
|
||||
if (file_exists(__DIR__ . "/apps/" . $app . ".php")) {
|
||||
include_once __DIR__ . "/apps/" . $app . ".php";
|
||||
|
72
index.php
72
index.php
@ -7,43 +7,52 @@ require_once __DIR__ . "/lib/login.php";
|
||||
$userpass_ok = false;
|
||||
$multiauth = false;
|
||||
if ($VARS['progress'] == "1") {
|
||||
if (authenticate_user($VARS['username'], $VARS['password'])) {
|
||||
switch (get_account_status($VARS['username'])) {
|
||||
case "LOCKED_OR_DISABLED":
|
||||
$alert = lang("account locked", false);
|
||||
break;
|
||||
case "TERMINATED":
|
||||
$alert = lang("account terminated", false);
|
||||
break;
|
||||
case "CHANGE_PASSWORD":
|
||||
$alert = lang("password expired", false);
|
||||
case "NORMAL":
|
||||
$userpass_ok = true;
|
||||
break;
|
||||
case "ALERT_ON_ACCESS":
|
||||
sendAlertEmail($VARS['username']);
|
||||
$userpass_ok = true;
|
||||
break;
|
||||
}
|
||||
if ($userpass_ok) {
|
||||
if (userHasTOTP($VARS['username'])) {
|
||||
$multiauth = true;
|
||||
} else {
|
||||
doLoginUser($VARS['username']);
|
||||
header('Location: home.php');
|
||||
die("Logged in, go to home.php");
|
||||
if (!RECAPTCHA_ENABLED || (RECAPTCHA_ENABLED && verifyReCaptcha($VARS['g-recaptcha-response']))) {
|
||||
if (authenticate_user($VARS['username'], $VARS['password'])) {
|
||||
switch (get_account_status($VARS['username'])) {
|
||||
case "LOCKED_OR_DISABLED":
|
||||
$alert = lang("account locked", false);
|
||||
break;
|
||||
case "TERMINATED":
|
||||
$alert = lang("account terminated", false);
|
||||
break;
|
||||
case "CHANGE_PASSWORD":
|
||||
$alert = lang("password expired", false);
|
||||
case "NORMAL":
|
||||
$userpass_ok = true;
|
||||
break;
|
||||
case "ALERT_ON_ACCESS":
|
||||
sendLoginAlertEmail($VARS['username']);
|
||||
$userpass_ok = true;
|
||||
break;
|
||||
}
|
||||
if ($userpass_ok) {
|
||||
if (userHasTOTP($VARS['username'])) {
|
||||
$multiauth = true;
|
||||
} else {
|
||||
doLoginUser($VARS['username'], $VARS['password']);
|
||||
insertAuthLog(1, $_SESSION['uid']);
|
||||
header('Location: home.php');
|
||||
die("Logged in, go to home.php");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$alert = lang("login incorrect", false);
|
||||
insertAuthLog(2);
|
||||
}
|
||||
} else {
|
||||
$alert = lang("login incorrect", false);
|
||||
$alert = lang("captcha error", false);
|
||||
insertAuthLog(8);
|
||||
}
|
||||
} else if ($VARS['progress'] == "2") {
|
||||
if (verifyTOTP($VARS['username'], $VARS['authcode'])) {
|
||||
doLoginUser($VARS['username']);
|
||||
doLoginUser($VARS['username'], $VARS['password']);
|
||||
insertAuthLog(1, $_SESSION['uid']);
|
||||
header('Location: home.php');
|
||||
die("Logged in, go to home.php");
|
||||
} else {
|
||||
$alert = lang("2fa incorrect", false);
|
||||
insertAuthLog(6);
|
||||
}
|
||||
}
|
||||
?>
|
||||
@ -58,13 +67,16 @@ if ($VARS['progress'] == "1") {
|
||||
|
||||
<link href="static/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="static/css/app.css" rel="stylesheet">
|
||||
<?php if (RECAPTCHA_ENABLED) { ?>
|
||||
<script src='https://www.google.com/recaptcha/api.js'></script>
|
||||
<?php } ?>
|
||||
</head>
|
||||
<body>
|
||||
<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">
|
||||
<div>
|
||||
<img class="img-responsive banner-image" src="static/img/banner.png" />
|
||||
<img class="img-responsive banner-image" src="static/img/logo.svg" />
|
||||
</div>
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
@ -85,6 +97,10 @@ if ($VARS['progress'] == "1") {
|
||||
?>
|
||||
<input type="text" class="form-control" name="username" placeholder="<?php lang("username"); ?>" required="required" autofocus /><br />
|
||||
<input type="password" class="form-control" name="password" placeholder="<?php lang("password"); ?>" required="required" /><br />
|
||||
<?php if (RECAPTCHA_ENABLED) { ?>
|
||||
<div class="g-recaptcha" data-sitekey="<?php echo RECAPTCHA_SITE_KEY; ?>"></div>
|
||||
<br />
|
||||
<?php } ?>
|
||||
<input type="hidden" name="progress" value="1" />
|
||||
<?php
|
||||
} else if ($multiauth) {
|
||||
|
@ -9,9 +9,11 @@ define("STRINGS", [
|
||||
"2fa prompt" => "Enter the six-digit code from your mobile authenticator app.",
|
||||
"2fa incorrect" => "Authentication code incorrect.",
|
||||
"login incorrect" => "Login incorrect.",
|
||||
"login successful" => "Login successful.",
|
||||
"account locked" => "This account has been disabled. Contact technical support.",
|
||||
"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",
|
||||
@ -36,5 +38,8 @@ define("STRINGS", [
|
||||
"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}",
|
||||
"user does not exist" => "User does not exist.",
|
||||
"captcha error" => "There was a problem with the CAPTCHA (robot test). Try again.",
|
||||
"home" => "Home",
|
||||
]);
|
@ -32,5 +32,13 @@ define("MESSAGES", [
|
||||
"password_500" => [
|
||||
"string" => "password on 500 list",
|
||||
"type" => "danger"
|
||||
],
|
||||
"account_state_error" => [
|
||||
"string" => "account state error",
|
||||
"type" => "danger"
|
||||
],
|
||||
"ldap_error" => [
|
||||
"string" => "ldap server error",
|
||||
"type" => "danger"
|
||||
]
|
||||
]);
|
||||
|
317
lib/login.php
317
lib/login.php
@ -1,7 +1,177 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Authentication and account functions
|
||||
*/
|
||||
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.
|
||||
* @param string $phone1 Phone number #1
|
||||
* @param string $phone2 Phone number #2
|
||||
* @param string $type Account type
|
||||
* @return int The new user's ID number in the database.
|
||||
*/
|
||||
function adduser($username, $password, $realname, $email = null, $phone1 = "", $phone2 = "", $type) {
|
||||
global $database;
|
||||
$database->insert('accounts', [
|
||||
'username' => strtolower($username),
|
||||
'password' => (is_null($password) ? null : encryptPassword($password)),
|
||||
'realname' => $realname,
|
||||
'email' => $email,
|
||||
'phone1' => $phone1,
|
||||
'phone2' => $phone2,
|
||||
'acctstatus' => 1,
|
||||
'accttype' => $type
|
||||
]);
|
||||
var_dump($database->error());
|
||||
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;
|
||||
$username = strtolower($username);
|
||||
$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.
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @return boolean True if OK, else false
|
||||
*/
|
||||
function authenticate_user($username, $password) {
|
||||
global $database;
|
||||
global $ldap_config;
|
||||
$username = strtolower($username);
|
||||
if (is_empty($username) || is_empty($password)) {
|
||||
return false;
|
||||
}
|
||||
$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) === TRUE;
|
||||
} else if ($loc == "LDAP_ONLY") {
|
||||
try {
|
||||
if (authenticate_user_ldap($username, $password) === TRUE) {
|
||||
$user = (new LdapManager($ldap_config))->getRepository('user')->findOneByUsername($username);
|
||||
//var_dump($user);
|
||||
adduser($user->getUsername(), null, $user->getName(), ($user->hasEmailAddress() ? $user->getEmailAddress() : null), "", "", 2);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
sendError("LDAP error: " . $e->getMessage());
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a username exists in the local database.
|
||||
* @param String $username
|
||||
*/
|
||||
function user_exists($username) {
|
||||
global $database;
|
||||
$username = strtolower($username);
|
||||
return $database->has('accounts', ['username' => $username, "LIMIT" => QUERY_LIMIT]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
$username = strtolower($username);
|
||||
$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";
|
||||
} else {
|
||||
// account isn't setup properly
|
||||
return "LOCKED_OR_DISABLED";
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Login handling //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Setup $_SESSION values to log in a user
|
||||
* @param string $username
|
||||
*/
|
||||
function doLoginUser($username, $password) {
|
||||
global $database;
|
||||
$username = strtolower($username);
|
||||
$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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an alert email to the system admin
|
||||
@ -9,24 +179,139 @@ use OTPHP\TOTP;
|
||||
* Used when an account with the status ALERT_ON_ACCESS logs in
|
||||
* @param String $username the account username
|
||||
*/
|
||||
function sendAlertEmail($username) {
|
||||
function sendLoginAlertEmail($username) {
|
||||
// TODO: add email code
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup $_SESSION values to log in a user
|
||||
* @param string $username
|
||||
*/
|
||||
function doLoginUser($username) {
|
||||
function insertAuthLog($type, $uid = null) {
|
||||
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['loggedin'] = true;
|
||||
$ip = "";
|
||||
if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
|
||||
$ip = $_SERVER["HTTP_CF_CONNECTING_IP"];
|
||||
} else if (isset($_SERVER["HTTP_CLIENT_IP"])) {
|
||||
$ip = $_SERVER["HTTP_CLIENT_IP"];
|
||||
} else if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) {
|
||||
$ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
|
||||
} else if (isset($_SERVER["HTTP_X_FORWARDED"])) {
|
||||
$ip = $_SERVER["HTTP_X_FORWARDED"];
|
||||
} else if (isset($_SERVER["HTTP_FORWARDED_FOR"])) {
|
||||
$ip = $_SERVER["HTTP_FORWARDED_FOR"];
|
||||
} else if (isset($_SERVER["HTTP_FORWARDED"])) {
|
||||
$ip = $_SERVER["HTTP_FORWARDED"];
|
||||
} else if (isset($_SERVER["REMOTE_ADDR"])) {
|
||||
$ip = $_SERVER["REMOTE_ADDR"];
|
||||
} else {
|
||||
$ip = "NOT FOUND";
|
||||
}
|
||||
$database->insert("authlog", ['#logtime' => 'NOW()', 'logtype' => $type, 'uid' => $uid, 'ip' => $ip]);
|
||||
}
|
||||
|
||||
function verifyReCaptcha($response) {
|
||||
try {
|
||||
$client = new GuzzleHttp\Client();
|
||||
|
||||
$response = $client
|
||||
->request('POST', "https://www.google.com/recaptcha/api/siteverify", [
|
||||
'form_params' => [
|
||||
'secret' => RECAPTCHA_SECRET_KEY,
|
||||
'response' => $response
|
||||
]
|
||||
]);
|
||||
|
||||
if ($response->getStatusCode() != 200) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$resp = json_decode($response->getBody(), TRUE);
|
||||
if ($resp['success'] === true) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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;
|
||||
}
|
||||
$username = strtolower($username);
|
||||
try {
|
||||
$ldapManager = new LdapManager($ldap_config);
|
||||
$msg = "";
|
||||
$code = 0;
|
||||
if ($ldapManager->authenticate($username, $password, $msg, $code) === TRUE) {
|
||||
return true;
|
||||
} else {
|
||||
return $code;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
sendError("LDAP error: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
try {
|
||||
$ldap = new LdapManager($ldap_config);
|
||||
$username = strtolower($username);
|
||||
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;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
sendError("LDAP error: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 2-factor authentication //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Check if a user has TOTP setup
|
||||
* @global $database $database
|
||||
@ -35,6 +320,7 @@ function doLoginUser($username) {
|
||||
*/
|
||||
function userHasTOTP($username) {
|
||||
global $database;
|
||||
$username = strtolower($username);
|
||||
$secret = $database->select('accounts', 'authsecret', ['username' => $username])[0];
|
||||
if (is_empty($secret)) {
|
||||
return false;
|
||||
@ -49,10 +335,11 @@ function userHasTOTP($username) {
|
||||
*/
|
||||
function newTOTP($username) {
|
||||
global $database;
|
||||
$username = strtolower($username);
|
||||
$secret = random_bytes(20);
|
||||
$encoded_secret = Base32::encode($secret);
|
||||
$userdata = $database->select('accounts', ['email', 'authsecret'], ['username' => $username])[0];
|
||||
$totp = new TOTP($userdata['email'], $encoded_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();
|
||||
}
|
||||
@ -65,6 +352,7 @@ function newTOTP($username) {
|
||||
*/
|
||||
function saveTOTP($username, $secret) {
|
||||
global $database;
|
||||
$username = strtolower($username);
|
||||
$database->update('accounts', ['authsecret' => $secret], ['username' => $username]);
|
||||
}
|
||||
|
||||
@ -77,6 +365,7 @@ function saveTOTP($username, $secret) {
|
||||
*/
|
||||
function verifyTOTP($username, $code) {
|
||||
global $database;
|
||||
$username = strtolower($username);
|
||||
$userdata = $database->select('accounts', ['email', 'authsecret'], ['username' => $username])[0];
|
||||
if (is_empty($userdata['authsecret'])) {
|
||||
return false;
|
||||
|
@ -3,7 +3,7 @@
|
||||
<type>org.netbeans.modules.php.project</type>
|
||||
<configuration>
|
||||
<data xmlns="http://www.netbeans.org/ns/php-project/1">
|
||||
<name>NetsymsBusinessSSO</name>
|
||||
<name>BusinessPortal</name>
|
||||
</data>
|
||||
</configuration>
|
||||
</project>
|
||||
|
105
required.php
105
required.php
@ -16,9 +16,10 @@ $session_length = 60 * 60; // 1 hour
|
||||
session_set_cookie_params($session_length, "/", null, false, true);
|
||||
|
||||
session_start(); // stick some cookies in it
|
||||
|
||||
//
|
||||
// Composer
|
||||
require __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
// Settings file
|
||||
require __DIR__ . '/settings.php';
|
||||
// List of alert messages
|
||||
@ -123,27 +124,6 @@ function lang2($key, $replace, $echo = true) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = "NOEMAIL@EXAMPLE.COM", $phone1 = "", $phone2 = "") {
|
||||
global $database;
|
||||
$database->insert('accounts', [
|
||||
'username' => strtolower($username),
|
||||
'password' => encryptPassword($password),
|
||||
'realname' => $realname,
|
||||
'email' => $email,
|
||||
'phone1' => $phone1,
|
||||
'phone2' => $phone2
|
||||
]);
|
||||
return $database->id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an email address is valid.
|
||||
* @param string $email Email to check
|
||||
@ -153,87 +133,6 @@ function isValidEmail($email) {
|
||||
return filter_var($email, FILTER_VALIDATE_EMAIL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an email exists in the database.
|
||||
* @param String $email
|
||||
*/
|
||||
function email_exists($email) {
|
||||
global $database;
|
||||
return $database->has('accounts', ['email' => $email, "LIMIT" => QUERY_LIMIT]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a username exists in the database.
|
||||
* @param String $username
|
||||
*/
|
||||
function user_exists($username) {
|
||||
global $database;
|
||||
return $database->has('accounts', ['username' => $username, "LIMIT" => QUERY_LIMIT]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the given credentials against the database.
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @return boolean True if OK, else false
|
||||
*/
|
||||
function authenticate_user($username, $password) {
|
||||
global $database;
|
||||
if (is_empty($username) || is_empty($password)) {
|
||||
return false;
|
||||
}
|
||||
if (!user_exists($username)) {
|
||||
return false;
|
||||
}
|
||||
$hash = $database->select('accounts', ['password'], ['username' => $username, "LIMIT" => 1])[0]['password'];
|
||||
return (comparePassword($password, $hash));
|
||||
}
|
||||
|
||||
function get_account_status($username) {
|
||||
global $database;
|
||||
$statuscode = $database->select('accounts', [
|
||||
'[>]acctstatus' => [
|
||||
'acctstatus' => 'statusid'
|
||||
]
|
||||
], [
|
||||
'accounts.acctstatus',
|
||||
'acctstatus.statuscode'
|
||||
], [
|
||||
'username' => $username,
|
||||
"LIMIT" => 1
|
||||
]
|
||||
)[0]['statuscode'];
|
||||
return $statuscode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the given credentials to see if they're legit.
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @return boolean True if OK, else false
|
||||
*/
|
||||
function authenticate_user_ldap($username, $password) {
|
||||
$ds = ldap_connect(LDAP_SERVER);
|
||||
if ($ds) {
|
||||
$sr = ldap_search($ds, LDAP_BASEDN, "(|(uid=" . $username . ")(mail=" . $username . "))", ['cn', 'uid', 'mail']);
|
||||
if (ldap_count_entries($ds, $sr) == 1) {
|
||||
$info = ldap_get_entries($ds, $sr);
|
||||
$name = $info[0]["cn"][0];
|
||||
$uid = $info[0]["uid"][0];
|
||||
$mail = $info[0]["mail"][0];
|
||||
$_SESSION['uid'] = $uid;
|
||||
$_SESSION['name'] = $name;
|
||||
$_SESSION['mail'] = $mail;
|
||||
return true;
|
||||
} else if (ldap_count_entries($ds, $sr) > 1) {
|
||||
sendError("Multiple users matched search criteria. Unsure which one you are.");
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
sendError("Login server offline.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashes the given plaintext password
|
||||
|
@ -13,8 +13,28 @@ define("DB_USER", "sso");
|
||||
define("DB_PASS", "");
|
||||
define("DB_CHARSET", "utf8");
|
||||
|
||||
define("LDAP_SERVER", "example.com");
|
||||
define("LDAP_BASEDN", "ou=users,dc=example,dc=com");
|
||||
define("LDAP_ENABLED", TRUE);
|
||||
|
||||
// See https://github.com/ldaptools/ldaptools/blob/master/docs/en/reference/Main-Configuration.md
|
||||
// for info on the LDAP config
|
||||
/*
|
||||
* Begin LDAP Configuration
|
||||
*/
|
||||
use LdapTools\Configuration;
|
||||
use LdapTools\DomainConfiguration;
|
||||
|
||||
$ldap_config = new Configuration();
|
||||
$ldap_config_domain = (new DomainConfiguration('example'))
|
||||
->setDomainName("example.com")
|
||||
->setServers(['192.168.25.131'])
|
||||
->setLazyBind(TRUE)
|
||||
->setUsername("readonly-bind")
|
||||
->setPassword("password")
|
||||
->setUseTls(TRUE);
|
||||
$ldap_config->addDomain($ldap_config_domain);
|
||||
/*
|
||||
* End LDAP Configuration
|
||||
*/
|
||||
|
||||
define("SITE_TITLE", "Netsyms Business Apps :: Single Sign On");
|
||||
|
||||
@ -27,6 +47,12 @@ define("TIMEZONE", "America/Denver");
|
||||
// Base URL for site links.
|
||||
define('URL', 'http://localhost:8000/');
|
||||
|
||||
// Use reCAPTCHA on login screen
|
||||
// https://www.google.com/recaptcha/
|
||||
define("RECAPTCHA_ENABLED", FALSE);
|
||||
define('RECAPTCHA_SITE_KEY', '');
|
||||
define('RECAPTCHA_SECRET_KEY', '');
|
||||
|
||||
// See lang folder for language options
|
||||
define('LANGUAGE', "en_us");
|
||||
|
||||
@ -46,9 +72,10 @@ define("QUERY_LIMIT", 1000);
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// /!\ Warning: Changing these values may violate the terms of your license agreement! /!\ //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////
|
||||
// /!\ Warning: Changing these values may /!\ //
|
||||
// /!\ violate the terms of your license agreement! /!\ //
|
||||
//////////////////////////////////////////////////////////////
|
||||
define("LICENSE_TEXT", "<b>Unlicensed Demo: For Trial Use Only</b>");
|
||||
define("COPYRIGHT_NAME", "Netsyms Technologies");
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////
|
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/Assets/BusinessPortal/logo_512.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<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 />
|
||||
</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" />
|
||||
<ellipse
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#2196f3;stroke-width:50;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path4155"
|
||||
cx="901.47205"
|
||||
cy="-256"
|
||||
rx="68.690376"
|
||||
ry="193.9493"
|
||||
transform="matrix(0,1,-1,0,0,0)" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 257.45991,599.83707 c 9.94158,-3.2506 20.98401,-3.01096 30.77413,0.67362 8.13772,3.03356 15.37803,8.41343 20.65625,15.31019 5.7326,7.42341 9.11199,16.6258 9.55504,25.99551 0.63974,11.77034 -3.4201,23.71233 -11.14414,32.62095 6.11458,6.07391 10.75535,13.62837 13.37297,21.84299 3.28899,10.26035 3.40883,21.51078 0.35265,31.84111 -2.44585,8.32302 -6.96227,16.01318 -12.98644,22.24763 -5.15388,5.31434 -11.38153,9.60704 -18.23981,12.40548 -0.0129,14.28395 -0.007,28.56791 -0.004,42.85187 -0.50863,0 -1.01271,-0.0143 -1.51227,-0.0143 0.0129,30.01462 -10e-4,60.02924 0.009,90.04386 0.0543,0.47919 -0.14918,0.95395 -0.54929,1.23189 -4.56391,3.42459 -9.12781,6.85389 -13.69623,10.2762 -0.5787,0.4362 -1.43991,0.42506 -2.02089,0.0143 -5.08607,-3.42245 -10.18796,-6.8199 -15.26953,-10.24677 -0.44305,-0.26224 -0.65099,-0.76871 -0.58547,-1.26589 0.0159,-30.01462 -0.0129,-60.02696 0.0159,-90.04172 -2.60182,0 -5.20363,0 -7.80317,0 -0.0114,-4.06875 0.0339,-8.13992 -0.0181,-12.20652 -0.53574,1.44442 -1.03529,2.90698 -1.60493,4.3424 -0.43399,-0.18082 -0.86577,-0.34593 -1.29978,-0.50632 -9.53697,26.00443 -19.14397,51.98187 -28.70129,77.97974 -0.13112,0.4272 -0.38428,0.85668 -0.859,0.94937 -5.01825,1.51913 -10.04102,3.01768 -15.06381,4.52094 -0.74369,0.26452 -1.57784,-0.1014 -1.97343,-0.75727 -3.15789,-4.37183 -6.3248,-8.7368 -9.50077,-13.09491 -0.37071,-0.47476 -0.80472,-1.06922 -0.486,-1.6908 7.00975,-19.06727 14.04209,-38.12755 21.05862,-57.19253 2.5566,-6.99387 5.19005,-13.96288 7.69466,-20.97717 -2.25143,-0.78213 -4.48025,-1.62982 -6.71587,-2.45493 4.56389,-12.36478 9.10972,-24.73398 13.66911,-37.10119 -6.0965,-5.61043 -10.75082,-12.76712 -13.42272,-20.60638 -3.3568,-9.71789 -3.59191,-20.48227 -0.62388,-30.32899 3.38618,-11.61193 11.17807,-21.8587 21.46999,-28.21756 -5.26461,-8.55355 -7.54771,-18.87946 -6.50336,-28.85942 0.91548,-9.41942 4.851,-18.50206 11.03791,-25.65645 5.5314,-6.43108 12.84403,-11.32052 20.91847,-13.92679 m -13.13113,14.70443 c -6.2276,5.76422 -10.57903,13.53348 -12.16813,21.8746 -1.94174,9.85347 -0.052,20.40536 5.25335,28.94094 4.48253,-2.07972 9.27248,-3.49243 14.16418,-4.18643 0.74819,-0.10855 1.51225,-0.12855 2.24914,-0.3278 7.64496,-2.25365 15.79171,-2.74188 23.66271,-1.53254 9.18205,1.406 17.95044,5.28493 25.23598,11.04019 2.56112,-3.05396 4.71761,-6.46055 6.29543,-10.12481 4.19092,-9.57528 4.426,-20.79176 0.65329,-30.53671 -2.92507,-7.68337 -8.28467,-14.40606 -15.09097,-19.01291 -7.28325,-4.97078 -16.23022,-7.42788 -25.03026,-6.89669 -9.32448,0.49954 -18.40936,4.3808 -25.22472,10.76216 m 20.4596,59.08886 c -3.87446,1.01265 -7.05947,4.14802 -8.22589,7.9681 7.28328,2.99525 15.45491,3.74567 23.17444,2.22669 -0.36167,-3.1128 -1.94175,-6.08077 -4.4102,-8.02923 -2.90697,-2.33281 -6.94871,-3.20306 -10.53835,-2.16556 m -7.45051,14.82199 c 1.12344,2.37566 2.91375,4.45081 5.19004,5.78911 3.65069,2.2017 8.43386,2.41865 12.2337,0.46562 1.66825,-1.08506 2.90924,-2.7103 3.84961,-4.44181 -7.10695,1.04193 -14.43996,0.39321 -21.27335,-1.81292 z"
|
||||
id="path3"
|
||||
style="fill:#ff9100;fill-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.2 KiB |
BIN
static/img/logo_512.png
Normal file
BIN
static/img/logo_512.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
Loading…
x
Reference in New Issue
Block a user