Added SAML-Toolkits php-saml to composer and installed it to the vendor folder. Implemented SSO with JumpCloud
All checks were successful
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 31s
All checks were successful
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 31s
Signed-off-by: rodude123 <rodude123@gmail.com>
This commit is contained in:
parent
430e1c65ca
commit
7b8e81e1f7
@ -17,7 +17,8 @@
|
|||||||
"ext-dom": "*",
|
"ext-dom": "*",
|
||||||
"ext-libxml": "*",
|
"ext-libxml": "*",
|
||||||
"donatello-za/rake-php-plus": "^1.0",
|
"donatello-za/rake-php-plus": "^1.0",
|
||||||
"phpmailer/phpmailer": "^6.9"
|
"phpmailer/phpmailer": "^6.9",
|
||||||
|
"onelogin/php-saml": "^4.1"
|
||||||
},
|
},
|
||||||
"repositories": [
|
"repositories": [
|
||||||
{
|
{
|
||||||
|
100
composer.lock
generated
100
composer.lock
generated
@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "f156a57e5e895727417d4274c8ad414c",
|
"content-hash": "a0850a84ff9d5a207b7b0724563015c7",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "donatello-za/rake-php-plus",
|
"name": "donatello-za/rake-php-plus",
|
||||||
@ -873,6 +873,62 @@
|
|||||||
],
|
],
|
||||||
"time": "2023-11-08T09:30:43+00:00"
|
"time": "2023-11-08T09:30:43+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "onelogin/php-saml",
|
||||||
|
"version": "4.1.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/onelogin/php-saml.git",
|
||||||
|
"reference": "b22a57ebd13e838b90df5d3346090bc37056409d"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/onelogin/php-saml/zipball/b22a57ebd13e838b90df5d3346090bc37056409d",
|
||||||
|
"reference": "b22a57ebd13e838b90df5d3346090bc37056409d",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.3",
|
||||||
|
"robrichards/xmlseclibs": ">=3.1.1"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"pdepend/pdepend": "^2.8.0",
|
||||||
|
"php-coveralls/php-coveralls": "^2.0",
|
||||||
|
"phploc/phploc": "^4.0 || ^5.0 || ^6.0 || ^7.0",
|
||||||
|
"phpunit/phpunit": "^9.5",
|
||||||
|
"sebastian/phpcpd": "^4.0 || ^5.0 || ^6.0 ",
|
||||||
|
"squizlabs/php_codesniffer": "^3.5.8"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-curl": "Install curl lib to be able to use the IdPMetadataParser for parsing remote XMLs",
|
||||||
|
"ext-dom": "Install xml lib",
|
||||||
|
"ext-openssl": "Install openssl lib in order to handle with x509 certs (require to support sign and encryption)",
|
||||||
|
"ext-zlib": "Install zlib"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"OneLogin\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"description": "OneLogin PHP SAML Toolkit",
|
||||||
|
"homepage": "https://developers.onelogin.com/saml/php",
|
||||||
|
"keywords": [
|
||||||
|
"SAML2",
|
||||||
|
"onelogin",
|
||||||
|
"saml"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"email": "sixto.garcia@onelogin.com",
|
||||||
|
"issues": "https://github.com/onelogin/php-saml/issues",
|
||||||
|
"source": "https://github.com/onelogin/php-saml/"
|
||||||
|
},
|
||||||
|
"time": "2022-07-15T20:44:36+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "php-di/invoker",
|
"name": "php-di/invoker",
|
||||||
"version": "2.3.4",
|
"version": "2.3.4",
|
||||||
@ -1614,6 +1670,48 @@
|
|||||||
},
|
},
|
||||||
"time": "2021-07-12T10:12:22+00:00"
|
"time": "2021-07-12T10:12:22+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "robrichards/xmlseclibs",
|
||||||
|
"version": "3.1.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/robrichards/xmlseclibs.git",
|
||||||
|
"reference": "f8f19e58f26cdb42c54b214ff8a820760292f8df"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/robrichards/xmlseclibs/zipball/f8f19e58f26cdb42c54b214ff8a820760292f8df",
|
||||||
|
"reference": "f8f19e58f26cdb42c54b214ff8a820760292f8df",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-openssl": "*",
|
||||||
|
"php": ">= 5.4"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"RobRichards\\XMLSecLibs\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
|
"description": "A PHP library for XML Security",
|
||||||
|
"homepage": "https://github.com/robrichards/xmlseclibs",
|
||||||
|
"keywords": [
|
||||||
|
"security",
|
||||||
|
"signature",
|
||||||
|
"xml",
|
||||||
|
"xmldsig"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/robrichards/xmlseclibs/issues",
|
||||||
|
"source": "https://github.com/robrichards/xmlseclibs/tree/3.1.1"
|
||||||
|
},
|
||||||
|
"time": "2020-09-05T13:00:25+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "selective/samesite-cookie",
|
"name": "selective/samesite-cookie",
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
|
34
dist/api/user/userData.php
vendored
34
dist/api/user/userData.php
vendored
@ -5,6 +5,7 @@ namespace api\user;
|
|||||||
use Firebase\JWT\JWT;
|
use Firebase\JWT\JWT;
|
||||||
use PDO;
|
use PDO;
|
||||||
use function api\utils\dbConn;
|
use function api\utils\dbConn;
|
||||||
|
use function api\utils\getSAMLSettings;
|
||||||
use function api\utils\getSecretKey;
|
use function api\utils\getSecretKey;
|
||||||
|
|
||||||
require_once __DIR__ . "/../utils/config.php";
|
require_once __DIR__ . "/../utils/config.php";
|
||||||
@ -138,5 +139,38 @@ class userData
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the SAML settings
|
||||||
|
* @return array - SAML settings
|
||||||
|
*/
|
||||||
|
public function getSamlConf(): array
|
||||||
|
{
|
||||||
|
return getSAMLSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the SAML user exists
|
||||||
|
* @param string $username - Username
|
||||||
|
* @param string $email - Email
|
||||||
|
* @return bool - True if the user exists, false if not
|
||||||
|
*/
|
||||||
|
public function checkSAMLUser(string $username, string $email): bool
|
||||||
|
{
|
||||||
|
$conn = dbConn();
|
||||||
|
$stmt = $conn->prepare("SELECT * FROM users WHERE username = :username AND email = :email");
|
||||||
|
$stmt->bindParam(":username", $username);
|
||||||
|
$stmt->bindParam(":email", $email);
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
// set the resulting array to associative
|
||||||
|
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if ($result)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
97
dist/api/user/userRoutes.php
vendored
97
dist/api/user/userRoutes.php
vendored
@ -5,6 +5,8 @@ require_once __DIR__ . "/../utils/routesInterface.php";
|
|||||||
require_once "userData.php";
|
require_once "userData.php";
|
||||||
|
|
||||||
use api\utils\routesInterface;
|
use api\utils\routesInterface;
|
||||||
|
use OneLogin\Saml2\Auth;
|
||||||
|
use OneLogin\Saml2\Error;
|
||||||
use Psr\Http\Message\ResponseInterface as Response;
|
use Psr\Http\Message\ResponseInterface as Response;
|
||||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||||
use Slim\App;
|
use Slim\App;
|
||||||
@ -12,14 +14,17 @@ use Slim\App;
|
|||||||
class userRoutes implements routesInterface
|
class userRoutes implements routesInterface
|
||||||
{
|
{
|
||||||
private userData $user;
|
private userData $user;
|
||||||
|
private Auth $samlAuth;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* constructor used to instantiate a base user routes, to be used in the index.php file.
|
* constructor used to instantiate a base user routes, to be used in the index.php file.
|
||||||
* @param App $app - the slim app used to create the routes
|
* @param App $app - the slim app used to create the routes
|
||||||
|
* @throws Error
|
||||||
*/
|
*/
|
||||||
public function __construct(App $app)
|
public function __construct(App $app)
|
||||||
{
|
{
|
||||||
$this->user = new userData();
|
$this->user = new userData();
|
||||||
|
$this->samlAuth = new Auth($this->user->getSamlConf());
|
||||||
$this->createRoutes($app);
|
$this->createRoutes($app);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,31 +35,9 @@ class userRoutes implements routesInterface
|
|||||||
*/
|
*/
|
||||||
public function createRoutes(App $app): void
|
public function createRoutes(App $app): void
|
||||||
{
|
{
|
||||||
$app->post("/user/login", function (Request $request, Response $response)
|
$app->get("/user/login", function (Request $request, Response $response)
|
||||||
{
|
{
|
||||||
// get request data
|
$this->samlAuth->login();
|
||||||
$data = $request->getParsedBody();
|
|
||||||
|
|
||||||
if (empty($data["username"]) || empty($data["password"]))
|
|
||||||
{
|
|
||||||
// uh oh user sent empty data
|
|
||||||
return $response->withStatus(400);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->user->checkUser($data["username"], $data["password"]))
|
|
||||||
{
|
|
||||||
// yay, user is logged in
|
|
||||||
$_SESSION["token"] = $this->user->createToken($data["username"]);
|
|
||||||
$_SESSION["username"] = $data["username"];
|
|
||||||
|
|
||||||
$inactive = 60 * 60 * 48; // 2 days
|
|
||||||
$_SESSION["timeout"] = time() + $inactive;
|
|
||||||
|
|
||||||
$response->getBody()->write(json_encode(array("token" => $_SESSION["token"])));
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
$response->getBody()->write(json_encode(array("error" => "Unauthorised")));
|
|
||||||
return $response->withStatus(401);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$app->get("/user/logout", function (Request $request, Response $response)
|
$app->get("/user/logout", function (Request $request, Response $response)
|
||||||
@ -92,6 +75,20 @@ class userRoutes implements routesInterface
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$app->get("/user/metadata", function (Request $request, Response $response)
|
||||||
|
{
|
||||||
|
$settings = $this->samlAuth->getSettings();
|
||||||
|
$metadata = $settings->getSPMetadata();
|
||||||
|
$errors = $settings->validateMetadata($metadata);
|
||||||
|
if (empty($errors))
|
||||||
|
{
|
||||||
|
$response->getBody()->write($metadata);
|
||||||
|
return $response->withHeader("Content-Type", "text/xml");
|
||||||
|
}
|
||||||
|
$response->getBody()->write(json_encode(array("error" => $errors)));
|
||||||
|
return $response->withStatus(500);
|
||||||
|
});
|
||||||
|
|
||||||
$app->get("/user/checkResetEmail/{email}", function (Request $request, Response $response, array $args)
|
$app->get("/user/checkResetEmail/{email}", function (Request $request, Response $response, array $args)
|
||||||
{
|
{
|
||||||
if (empty($args["email"]))
|
if (empty($args["email"]))
|
||||||
@ -139,6 +136,58 @@ class userRoutes implements routesInterface
|
|||||||
return $response->withStatus(401);
|
return $response->withStatus(401);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$app->post("/user/login", function (Request $request, Response $response)
|
||||||
|
{
|
||||||
|
// get request data
|
||||||
|
$data = $request->getParsedBody();
|
||||||
|
|
||||||
|
if (empty($data["username"]) || empty($data["password"]))
|
||||||
|
{
|
||||||
|
// uh oh user sent empty data
|
||||||
|
return $response->withStatus(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->user->checkUser($data["username"], $data["password"]))
|
||||||
|
{
|
||||||
|
// yay, user is logged in
|
||||||
|
$_SESSION["token"] = $this->user->createToken($data["username"]);
|
||||||
|
$_SESSION["username"] = $data["username"];
|
||||||
|
|
||||||
|
$inactive = 60 * 60 * 48; // 2 days
|
||||||
|
$_SESSION["timeout"] = time() + $inactive;
|
||||||
|
|
||||||
|
$response->getBody()->write(json_encode(array("token" => $_SESSION["token"])));
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
$response->getBody()->write(json_encode(array("error" => "Unauthorised")));
|
||||||
|
return $response->withStatus(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
$app->post("/user/acs", function (Request $request, Response $response)
|
||||||
|
{
|
||||||
|
$this->samlAuth->processResponse();
|
||||||
|
|
||||||
|
$attributes = $this->samlAuth->getAttributes();
|
||||||
|
$username = $attributes["username"][0];
|
||||||
|
$email = $attributes["email"][0];
|
||||||
|
|
||||||
|
if ($this->user->checkSAMLUser($username, $email))
|
||||||
|
{
|
||||||
|
// yay, user is logged in
|
||||||
|
$_SESSION["token"] = $this->user->createToken($username);
|
||||||
|
$_SESSION["username"] = $username;
|
||||||
|
$_SESSION["email"] = $email;
|
||||||
|
|
||||||
|
$inactive = 60 * 60 * 48; // 2 days
|
||||||
|
$_SESSION["timeout"] = time() + $inactive;
|
||||||
|
|
||||||
|
return $response->withHeader("Location", "https://rohitpai.co.uk/editor/editor.html")->withStatus(302);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response->getBody()->write(json_encode(array("error" => "Unauthorised")));
|
||||||
|
return $response->withStatus(401);
|
||||||
|
});
|
||||||
|
|
||||||
$app->post("/user/changePassword", function (Request $request, Response $response)
|
$app->post("/user/changePassword", function (Request $request, Response $response)
|
||||||
{
|
{
|
||||||
if (empty($_SESSION["resetToken"]) && empty($_SESSION["resetEmail"]))
|
if (empty($_SESSION["resetToken"]) && empty($_SESSION["resetEmail"]))
|
||||||
|
2
dist/blog/css/main.css
vendored
2
dist/blog/css/main.css
vendored
File diff suppressed because one or more lines are too long
2
dist/css/main.css
vendored
2
dist/css/main.css
vendored
File diff suppressed because one or more lines are too long
2
dist/editor/css/main.css
vendored
2
dist/editor/css/main.css
vendored
File diff suppressed because one or more lines are too long
2
dist/editor/index.html
vendored
2
dist/editor/index.html
vendored
@ -1 +1 @@
|
|||||||
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Editor</title><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="stylesheet" href="css/main.css"><script src="https://kit.fontawesome.com/ed3c25598e.js" crossorigin="anonymous"></script></head><body><main class="login"><div id="login" class="container shown"><h1>Login To Editor</h1><form action="" method="POST"><div class="formControl"><label for="username">Username</label> <input type="text" id="username" name="username" required></div><div class="formControl passwordControl"><label for="password">Password</label> <input type="password" id="password" name="password" required> <i class="fa-solid fa-eye"></i></div><div class="error hidden" id="loginError"><button class="close" type="button">×</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <a href="#" id="resetPwd">Reset Password</a></div></form></div><div id="resetPassword" class="container" style="display: none; transform: translateX(150vw)"><h1>Reset Password</h1><form action="#" method="POST"><div class="formControl"><label for="email">Email</label> <input type="email" id="email" name="email"></div><div class="error hidden" id="resetError"><button class="close" type="button">×</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <a href="#" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut" id="loginBtn">Login</a></div></form></div><div id="checkResetCode" class="container" style="display: none; transform: translateX(150vw)"><h1>Check Reset Code</h1><form action="#" method="POST"><div class="formControl"><label for="code">Code</label> <input type="text" id="code" name="code"></div><div class="error hidden" id="resetCodeError"><button class="close" type="button">×</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <a href="#" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut" id="resendEmail">Resend Email</a></div></form></div><div id="changePassword" class="container" style="display: none; transform: translateX(150vw)"><h1>Reset Password</h1><form action="" method="POST"><div class="formControl"><label for="pass">Password</label> <input type="password" name="pass" id="pass"> <i class="fa-solid fa-eye"></i></div><div class="formControl"><label for="rePass">Password</label> <input type="password" name="rePass" id="rePass"> <i class="fa-solid fa-eye"></i></div><div class="error hidden" id="changeError"><button class="close" type="button">×</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <a href="#" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut">Login</a></div></form></div></main><script src="js/index.js"></script></body></html>
|
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Editor</title><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="stylesheet" href="css/main.css"><script src="https://kit.fontawesome.com/ed3c25598e.js" crossorigin="anonymous"></script></head><body><main class="login"><div id="login" class="container shown"><h1>Login To Editor</h1><form action="" method="POST"><div class="formControl"><label for="username">Username</label> <input type="text" id="username" name="username" required></div><div class="formControl passwordControl"><label for="password">Password</label> <input type="password" id="password" name="password" required> <i class="fa-solid fa-eye"></i></div><div class="error hidden" id="loginError"><button class="close" type="button">×</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <a href="/api/user/login" class="btn btnPrimary boxShadowIn boxShadowOut">Login with Jump Cloud</a> <button type="button" id="resetPwd" class="btn btnPrimary boxShadowIn boxShadowOut">Reset Password</button></div></form></div><div id="resetPassword" class="container" style="display: none; transform: translateX(150vw)"><h1>Reset Password</h1><form action="#" method="POST"><div class="formControl"><label for="email">Email</label> <input type="email" id="email" name="email"></div><div class="error hidden" id="resetError"><button class="close" type="button">×</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <button type="button" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut" id="loginBtn">Login</button></div></form></div><div id="checkResetCode" class="container" style="display: none; transform: translateX(150vw)"><h1>Check Reset Code</h1><form action="#" method="POST"><div class="formControl"><label for="code">Code</label> <input type="text" id="code" name="code"></div><div class="error hidden" id="resetCodeError"><button class="close" type="button">×</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <button type="button" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut" id="resendEmail">Resend Email</button></div></form></div><div id="changePassword" class="container" style="display: none; transform: translateX(150vw)"><h1>Reset Password</h1><form action="" method="POST"><div class="formControl"><label for="pass">Password</label> <input type="password" name="pass" id="pass"> <i class="fa-solid fa-eye"></i></div><div class="formControl"><label for="rePass">Password</label> <input type="password" name="rePass" id="rePass"> <i class="fa-solid fa-eye"></i></div><div class="error hidden" id="changeError"><button class="close" type="button">×</button><div></div></div><div class="btnContainer"><input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut"> <button type="button" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut">Login</button></div></form></div></main><script src="js/index.js"></script></body></html>
|
@ -5,6 +5,7 @@ namespace api\user;
|
|||||||
use Firebase\JWT\JWT;
|
use Firebase\JWT\JWT;
|
||||||
use PDO;
|
use PDO;
|
||||||
use function api\utils\dbConn;
|
use function api\utils\dbConn;
|
||||||
|
use function api\utils\getSAMLSettings;
|
||||||
use function api\utils\getSecretKey;
|
use function api\utils\getSecretKey;
|
||||||
|
|
||||||
require_once __DIR__ . "/../utils/config.php";
|
require_once __DIR__ . "/../utils/config.php";
|
||||||
@ -138,5 +139,38 @@ class userData
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the SAML settings
|
||||||
|
* @return array - SAML settings
|
||||||
|
*/
|
||||||
|
public function getSamlConf(): array
|
||||||
|
{
|
||||||
|
return getSAMLSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the SAML user exists
|
||||||
|
* @param string $username - Username
|
||||||
|
* @param string $email - Email
|
||||||
|
* @return bool - True if the user exists, false if not
|
||||||
|
*/
|
||||||
|
public function checkSAMLUser(string $username, string $email): bool
|
||||||
|
{
|
||||||
|
$conn = dbConn();
|
||||||
|
$stmt = $conn->prepare("SELECT * FROM users WHERE username = :username AND email = :email");
|
||||||
|
$stmt->bindParam(":username", $username);
|
||||||
|
$stmt->bindParam(":email", $email);
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
// set the resulting array to associative
|
||||||
|
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if ($result)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -5,6 +5,8 @@ require_once __DIR__ . "/../utils/routesInterface.php";
|
|||||||
require_once "userData.php";
|
require_once "userData.php";
|
||||||
|
|
||||||
use api\utils\routesInterface;
|
use api\utils\routesInterface;
|
||||||
|
use OneLogin\Saml2\Auth;
|
||||||
|
use OneLogin\Saml2\Error;
|
||||||
use Psr\Http\Message\ResponseInterface as Response;
|
use Psr\Http\Message\ResponseInterface as Response;
|
||||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||||
use Slim\App;
|
use Slim\App;
|
||||||
@ -12,14 +14,17 @@ use Slim\App;
|
|||||||
class userRoutes implements routesInterface
|
class userRoutes implements routesInterface
|
||||||
{
|
{
|
||||||
private userData $user;
|
private userData $user;
|
||||||
|
private Auth $samlAuth;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* constructor used to instantiate a base user routes, to be used in the index.php file.
|
* constructor used to instantiate a base user routes, to be used in the index.php file.
|
||||||
* @param App $app - the slim app used to create the routes
|
* @param App $app - the slim app used to create the routes
|
||||||
|
* @throws Error
|
||||||
*/
|
*/
|
||||||
public function __construct(App $app)
|
public function __construct(App $app)
|
||||||
{
|
{
|
||||||
$this->user = new userData();
|
$this->user = new userData();
|
||||||
|
$this->samlAuth = new Auth($this->user->getSamlConf());
|
||||||
$this->createRoutes($app);
|
$this->createRoutes($app);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,31 +35,9 @@ class userRoutes implements routesInterface
|
|||||||
*/
|
*/
|
||||||
public function createRoutes(App $app): void
|
public function createRoutes(App $app): void
|
||||||
{
|
{
|
||||||
$app->post("/user/login", function (Request $request, Response $response)
|
$app->get("/user/login", function (Request $request, Response $response)
|
||||||
{
|
{
|
||||||
// get request data
|
$this->samlAuth->login();
|
||||||
$data = $request->getParsedBody();
|
|
||||||
|
|
||||||
if (empty($data["username"]) || empty($data["password"]))
|
|
||||||
{
|
|
||||||
// uh oh user sent empty data
|
|
||||||
return $response->withStatus(400);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->user->checkUser($data["username"], $data["password"]))
|
|
||||||
{
|
|
||||||
// yay, user is logged in
|
|
||||||
$_SESSION["token"] = $this->user->createToken($data["username"]);
|
|
||||||
$_SESSION["username"] = $data["username"];
|
|
||||||
|
|
||||||
$inactive = 60 * 60 * 48; // 2 days
|
|
||||||
$_SESSION["timeout"] = time() + $inactive;
|
|
||||||
|
|
||||||
$response->getBody()->write(json_encode(array("token" => $_SESSION["token"])));
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
$response->getBody()->write(json_encode(array("error" => "Unauthorised")));
|
|
||||||
return $response->withStatus(401);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$app->get("/user/logout", function (Request $request, Response $response)
|
$app->get("/user/logout", function (Request $request, Response $response)
|
||||||
@ -92,6 +75,20 @@ class userRoutes implements routesInterface
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$app->get("/user/metadata", function (Request $request, Response $response)
|
||||||
|
{
|
||||||
|
$settings = $this->samlAuth->getSettings();
|
||||||
|
$metadata = $settings->getSPMetadata();
|
||||||
|
$errors = $settings->validateMetadata($metadata);
|
||||||
|
if (empty($errors))
|
||||||
|
{
|
||||||
|
$response->getBody()->write($metadata);
|
||||||
|
return $response->withHeader("Content-Type", "text/xml");
|
||||||
|
}
|
||||||
|
$response->getBody()->write(json_encode(array("error" => $errors)));
|
||||||
|
return $response->withStatus(500);
|
||||||
|
});
|
||||||
|
|
||||||
$app->get("/user/checkResetEmail/{email}", function (Request $request, Response $response, array $args)
|
$app->get("/user/checkResetEmail/{email}", function (Request $request, Response $response, array $args)
|
||||||
{
|
{
|
||||||
if (empty($args["email"]))
|
if (empty($args["email"]))
|
||||||
@ -139,6 +136,61 @@ class userRoutes implements routesInterface
|
|||||||
return $response->withStatus(401);
|
return $response->withStatus(401);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$app->post("/user/login", function (Request $request, Response $response)
|
||||||
|
{
|
||||||
|
// get request data
|
||||||
|
$data = $request->getParsedBody();
|
||||||
|
|
||||||
|
if (empty($data["username"]) || empty($data["password"]))
|
||||||
|
{
|
||||||
|
// uh oh user sent empty data
|
||||||
|
return $response->withStatus(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->user->checkUser($data["username"], $data["password"]))
|
||||||
|
{
|
||||||
|
// yay, user is logged in
|
||||||
|
$_SESSION["token"] = $this->user->createToken($data["username"]);
|
||||||
|
$_SESSION["username"] = $data["username"];
|
||||||
|
|
||||||
|
$inactive = 60 * 60 * 48; // 2 days
|
||||||
|
$_SESSION["timeout"] = time() + $inactive;
|
||||||
|
|
||||||
|
$response->getBody()->write(json_encode(array("token" => $_SESSION["token"])));
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
$response->getBody()->write(json_encode(array("error" => "Unauthorised")));
|
||||||
|
return $response->withStatus(401);
|
||||||
|
});
|
||||||
|
|
||||||
|
$app->post("/user/acs", function (Request $request, Response $response)
|
||||||
|
{
|
||||||
|
$this->samlAuth->processResponse();
|
||||||
|
|
||||||
|
$attributes = $this->samlAuth->getAttributes();
|
||||||
|
// $username = $attributes["username"][0];
|
||||||
|
// $email = $attributes["email"][0];
|
||||||
|
|
||||||
|
$response->getBody()->write(json_encode($attributes));
|
||||||
|
return $response;
|
||||||
|
|
||||||
|
// if ($this->user->checkSAMLUser($username, $email))
|
||||||
|
// {
|
||||||
|
// // yay, user is logged in
|
||||||
|
// $_SESSION["token"] = $this->user->createToken($username);
|
||||||
|
// $_SESSION["username"] = $username;
|
||||||
|
// $_SESSION["email"] = $email;
|
||||||
|
//
|
||||||
|
// $inactive = 60 * 60 * 48; // 2 days
|
||||||
|
// $_SESSION["timeout"] = time() + $inactive;
|
||||||
|
//
|
||||||
|
// return $response->withHeader("Location", "https://rohitpai.co.uk/editor/editor.html")->withStatus(302);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// $response->getBody()->write(json_encode(array("error" => "Unauthorised")));
|
||||||
|
// return $response->withStatus(401);
|
||||||
|
});
|
||||||
|
|
||||||
$app->post("/user/changePassword", function (Request $request, Response $response)
|
$app->post("/user/changePassword", function (Request $request, Response $response)
|
||||||
{
|
{
|
||||||
if (empty($_SESSION["resetToken"]) && empty($_SESSION["resetEmail"]))
|
if (empty($_SESSION["resetToken"]) && empty($_SESSION["resetEmail"]))
|
||||||
|
@ -190,6 +190,10 @@ div.categories {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.form input[type="submit"] {
|
||||||
|
align-self: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
.image img, .image_resized img {
|
.image img, .image_resized img {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
-webkit-border-radius: 10px;
|
-webkit-border-radius: 10px;
|
||||||
|
@ -162,11 +162,6 @@ div.form .formControl.passwordControl {
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
form input[type="submit"],
|
|
||||||
div.form input[type="submit"] {
|
|
||||||
align-self: flex-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
form .formControl input:not([type="submit"]), form .formControl textarea,
|
form .formControl input:not([type="submit"]), form .formControl textarea,
|
||||||
form .formControl .ck.ck-editor__top .ck-sticky-panel .ck-toolbar,
|
form .formControl .ck.ck-editor__top .ck-sticky-panel .ck-toolbar,
|
||||||
form .formControl .ck.ck-editor__main .ck-content, div.menu input:not([type="submit"]),
|
form .formControl .ck.ck-editor__main .ck-content, div.menu input:not([type="submit"]),
|
||||||
|
@ -66,14 +66,22 @@ div#login input[type=submit]{
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
div.btnContainer {
|
div.btnContainer {
|
||||||
width: 100%;
|
width: 60%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: column;
|
||||||
justify-content: space-between;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: stretch;
|
||||||
|
gap: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.btnContainer a {
|
||||||
|
justify-content: center;
|
||||||
|
text-transform: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
form div.btnContainer input[type="submit"] {
|
||||||
|
align-self: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.btnContainer a:not(.btn) {
|
div.btnContainer a:not(.btn) {
|
||||||
|
@ -32,8 +32,9 @@
|
|||||||
|
|
||||||
<div class="btnContainer">
|
<div class="btnContainer">
|
||||||
<input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut">
|
<input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut">
|
||||||
|
<a href="/api/user/login" class="btn btnPrimary boxShadowIn boxShadowOut">Login with Jump Cloud</a>
|
||||||
<a href="#" id="resetPwd">Reset Password</a>
|
<button type="button" id="resetPwd" class="btn btnPrimary boxShadowIn boxShadowOut">Reset Password
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -54,7 +55,8 @@
|
|||||||
|
|
||||||
<div class="btnContainer">
|
<div class="btnContainer">
|
||||||
<input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut">
|
<input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut">
|
||||||
<a href="#" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut" id="loginBtn">Login</a>
|
<button type="button" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut" id="loginBtn">Login
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -75,7 +77,9 @@
|
|||||||
|
|
||||||
<div class="btnContainer">
|
<div class="btnContainer">
|
||||||
<input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut">
|
<input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut">
|
||||||
<a href="#" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut" id="resendEmail">Resend Email</a>
|
<button type="button" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut" id="resendEmail">Resend
|
||||||
|
Email
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -102,7 +106,7 @@
|
|||||||
|
|
||||||
<div class="btnContainer">
|
<div class="btnContainer">
|
||||||
<input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut">
|
<input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut">
|
||||||
<a href="#" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut">Login</a>
|
<button type="button" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut">Login</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user