Added SAML-Toolkits php-saml to composer and installed it to the vendor folder. Implemented SSO with JumpCloud
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 31s
🚀 Deploy website on push / 🎉 Deploy (push) Successful in 31s
Signed-off-by: rodude123 <rodude123@gmail.com>
This commit is contained in:
@@ -5,6 +5,7 @@ namespace api\user;
|
||||
use Firebase\JWT\JWT;
|
||||
use PDO;
|
||||
use function api\utils\dbConn;
|
||||
use function api\utils\getSAMLSettings;
|
||||
use function api\utils\getSecretKey;
|
||||
|
||||
require_once __DIR__ . "/../utils/config.php";
|
||||
@@ -138,5 +139,38 @@ class userData
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+76
-24
@@ -5,6 +5,8 @@ require_once __DIR__ . "/../utils/routesInterface.php";
|
||||
require_once "userData.php";
|
||||
|
||||
use api\utils\routesInterface;
|
||||
use OneLogin\Saml2\Auth;
|
||||
use OneLogin\Saml2\Error;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Slim\App;
|
||||
@@ -12,14 +14,17 @@ use Slim\App;
|
||||
class userRoutes implements routesInterface
|
||||
{
|
||||
private userData $user;
|
||||
private Auth $samlAuth;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws Error
|
||||
*/
|
||||
public function __construct(App $app)
|
||||
{
|
||||
$this->user = new userData();
|
||||
$this->samlAuth = new Auth($this->user->getSamlConf());
|
||||
$this->createRoutes($app);
|
||||
}
|
||||
|
||||
@@ -30,31 +35,9 @@ class userRoutes implements routesInterface
|
||||
*/
|
||||
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
|
||||
$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);
|
||||
$this->samlAuth->login();
|
||||
});
|
||||
|
||||
$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)
|
||||
{
|
||||
if (empty($args["email"]))
|
||||
@@ -139,6 +136,61 @@ class userRoutes implements routesInterface
|
||||
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)
|
||||
{
|
||||
if (empty($_SESSION["resetToken"]) && empty($_SESSION["resetEmail"]))
|
||||
|
||||
@@ -190,6 +190,10 @@ div.categories {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.form input[type="submit"] {
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.image img, .image_resized img {
|
||||
max-width: 100%;
|
||||
-webkit-border-radius: 10px;
|
||||
|
||||
@@ -162,11 +162,6 @@ div.form .formControl.passwordControl {
|
||||
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 .ck.ck-editor__top .ck-sticky-panel .ck-toolbar,
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
div.btnContainer {
|
||||
width: 100%;
|
||||
width: 60%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: 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) {
|
||||
|
||||
@@ -32,8 +32,9 @@
|
||||
|
||||
<div class="btnContainer">
|
||||
<input type="submit" value="Submit" class="btn btnPrimary boxShadowIn boxShadowOut">
|
||||
|
||||
<a href="#" id="resetPwd">Reset Password</a>
|
||||
<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>
|
||||
@@ -54,7 +55,8 @@
|
||||
|
||||
<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>
|
||||
<button type="button" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut" id="loginBtn">Login
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -75,7 +77,9 @@
|
||||
|
||||
<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>
|
||||
<button type="button" class="loginBtn btn btnPrimary boxShadowIn boxShadowOut" id="resendEmail">Resend
|
||||
Email
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -102,7 +106,7 @@
|
||||
|
||||
<div class="btnContainer">
|
||||
<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>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user