Files
fmgapp/app/controllers/SSO.php

254 lines
8.2 KiB
PHP
Executable File

<?php declare(strict_types=1); namespace IR\App\Controllers; if (!defined('IR_START')) exit('<pre>No direct script access allowed</pre>');
/**
* @framework iResponse Framework
* @version 1.0
* @author Amine Idrissi <contact@iresponse.tech>
* @date 2019
* @name Auth.php
*/
# core
use Exception;
use IR\Core\Application as Application;
# mvc
use IR\Mvc\Controller as Controller;
# helpers
use IR\App\Helpers\Authentication as Authentication;
use IR\App\Helpers\Page as Page;
use IR\App\Helpers\XmlCertificateExtractor;
# models
use IR\App\Models\Admin\User as User;
use OneLogin\Saml2\Auth;
use IR\Logs\Logger;
/**
* @name SSO
* @description SSO Controller
*/
class SSO extends Controller
{
/**
* @app
* @readwrite
*/
public $app;
private $keys;
/**
* @name init
* @description initializing process before the action method executed
* @once
* @protected
*/
public function init()
{
# set the current application to a local variable
$this->app = Application::getCurrent();
# connect to the database
$this->app->database('system')->connect();
$this->keys = XmlCertificateExtractor::extractCertificate();
}
/**
* @name login
* @description the login action
* @before init
* @after closeConnections
*/
public function login()
{
$ssoParams = $this->app->getSetting('sso');
$data['SSO_BASE_URL'] = $this->app->utils->arrays->get($ssoParams, 'SSO_BASE_URL');
$data['SSO_SP_ENTITY_ID'] = $this->app->utils->arrays->get($ssoParams, 'SSO_SP_ENTITY_ID');
$data['SSO_SP_ACS'] = $this->app->utils->arrays->get($ssoParams, 'SSO_SP_ACS');
$data['SSO_IDP_ENTITY_ID'] = $this->app->utils->arrays->get($ssoParams, 'SSO_IDP_ENTITY_ID');
$data['SSO_IDP_URL'] = $this->app->utils->arrays->get($ssoParams, 'SSO_IDP_URL');
$settings = [
'strict' => false,
'debug' => true,
'baseurl' => "{$data['SSO_BASE_URL']}",
'sp' => [
'entityId' => "{$data['SSO_SP_ENTITY_ID']}",
'assertionConsumerService' => [
'url' => "{$data['SSO_SP_ACS']}",
'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'
],
'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified',
],
'idp' => [
'entityId' => "{$data['SSO_IDP_ENTITY_ID']}",
'singleSignOnService' => [
'url' => "{$data['SSO_IDP_URL']}",
'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
],
'x509certMulti' => $this->keys
],
];
$samlAuth = new Auth($settings);
$samlAuth->login();
}
private function setSOOSettings() {
$ssoParams = $this->app->getSetting('sso');
$data['SSO_BASE_URL'] = $this->app->utils->arrays->get($ssoParams, 'SSO_BASE_URL');
$data['SSO_SP_ENTITY_ID'] = $this->app->utils->arrays->get($ssoParams, 'SSO_SP_ENTITY_ID');
$data['SSO_SP_ACS'] = $this->app->utils->arrays->get($ssoParams, 'SSO_SP_ACS');
$data['SSO_IDP_ENTITY_ID'] = $this->app->utils->arrays->get($ssoParams, 'SSO_IDP_ENTITY_ID');
$data['SSO_IDP_URL'] = $this->app->utils->arrays->get($ssoParams, 'SSO_IDP_URL');
$settings = [
'strict' => false,
'debug' => true,
'baseurl' => "{$data['SSO_BASE_URL']}",
'sp' => [
'entityId' => "{$data['SSO_SP_ENTITY_ID']}",
'assertionConsumerService' => [
'url' => "{$data['SSO_SP_ACS']}",
'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'
],
'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified',
],
'idp' => [
'entityId' => "{$data['SSO_IDP_ENTITY_ID']}",
'singleSignOnService' => [
'url' => "{$data['SSO_IDP_URL']}",
'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
],
'x509certMulti' => $this->keys
],
];
$samlAuth = new Auth($settings);
return $samlAuth;
}
private function SSOAuthentication($message) {
$samlAuth = $this->setSOOSettings();
$samlAuth->processResponse();
if (!$samlAuth->isAuthenticated())
{
$message = "Not authenticated";
}
$errors = $samlAuth->getErrors();
if (!empty($errors))
{
$message = "Authentication error: " . implode(", ", $errors);
}
return [$samlAuth, $message];
}
/**
* @name acs
* @description the acs action
* @before init
* @after closeConnections
*/
public function acs()
{
$message = 'Incorrect email or password !';
try
{
[$samlAuth, $message] = $this->SSOAuthentication($message);
$attributes = $samlAuth->getAttributes();
$email = $attributes['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name'][0];
$displayname = $attributes['http://schemas.microsoft.com/identity/claims/displayname'][0];
$displayname = strtolower($displayname);
$user = User::first(User::FETCH_OBJECT,['email = ? or concat(lower("first_name"), \' \', lower("last_name")) = ?',[$email, $displayname]]);
if(isset($user) && is_object($user) && $user instanceof User)
{
# remove the password from the session
$user->setPassword('');
# check if this user is activated or not
if($user->getStatus() != 'Activated')
{
$message = 'This user is inactivated !';
}
else
{
$userRoles = $this->app->database('system')->query()->from('admin.users_roles')->where('user_id = ?',$user->getId())->count();
if($user->getMasterAccess() != 'Enabled' && $userRoles == 0)
{
$message = 'This user has no role in this application !';
}
else
{
if($user->getAvatarName() == "" || $user->getAvatarName() == null)
{
$user->setAvatarName("default.png");
}
Authentication::registerUser($user);
# redirect to dashboard page
Page::redirect($this->app->http->request->getBaseURL() . RDS . DEFAULT_CONTROLLER . '.' . DEFAULT_EXTENSION);
}
}
}
die("<p style='margin-top: 24px;margin-left: 16px;'>$message</p>");
}
catch (Exception $e)
{
$message = $e->getMessage();
die("<p style='margin-top: 24px;margin-left: 16px;'>$message</p>");
}
}
/**
* @name logout
* @description the logout function
*/
public function logout()
{
die('
<!DOCTYPE html>
<html>
<head>
<title>Logout Confirmation</title>
<style>
body {
font-family: Arial, sans-serif;
}
.container {
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
</style>
</head>
<body>
<div class="container">
<h1>You have been logged out</h1>
<p>You have been successfully logged out.</p>
</div>
</body>
</html>
');
}
/**
* @name closeConnections
* @description close all connections
* @once
* @protected
*/
public function closeConnections()
{
# connect to the database
$this->app->database('system')->disconnect();
$this->app->database('clients')->disconnect();
}
}