Casuser auth backend: add user access filters feature

This commit is contained in:
Benjamin Renard 2024-02-21 10:13:27 +01:00
parent 82122089f9
commit 57aedc4869
Signed by: bn8
GPG key ID: 3E2E1CE1907115BC
8 changed files with 183 additions and 32 deletions

File diff suppressed because one or more lines are too long

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: 2024-01-23 18:15+0000\n"
"POT-Creation-Date: 2024-02-21 09:12+0000\n"
"PO-Revision-Date: \n"
"Last-Translator: Benjamin Renard <brenard@easter-eggs.com>\n"
"Language-Team: \n"
@ -30,7 +30,7 @@ msgstr ""
msgid "Unknown"
msgstr "Inconnu"
#: Db.php:78
#: Db.php:93
msgid "Unable to connect to the database."
msgstr "Impossible de se connecter à la base de données."
@ -46,7 +46,7 @@ msgstr "Connection"
msgid "Authentication required"
msgstr "Authentication requise"
#: Auth/Http.php:124 Auth/Http.php:127 Url.php:185
#: Auth/Http.php:124 Auth/Http.php:127 Url.php:185 Auth.php:340 Auth.php:343
msgid "Access denied"
msgstr "Accès interdit"
@ -54,6 +54,10 @@ msgstr "Accès interdit"
msgid "You must login to access this page."
msgstr "Vous devez vous connecter pour accéder à cette page."
#: Auth/Casuser.php:88 Auth/Casuser.php:112
msgid "Configuration error in CAS auth backend."
msgstr "Erreur de configuration dans le backend d'authentification CAS."
#: Url.php:177
msgid "Bad request"
msgstr "Mauvaise requête"
@ -120,6 +124,14 @@ msgstr "Authentication requise mais impossible pour vous authentifier."
msgid "This request could not be processed correctly."
msgstr "Cette requête n'a put être traitée correctement."
#: Auth.php:344
msgid "You do not have access to this application."
msgstr "Vous n'avez pas accès à cette application."
#: Auth.php:348
msgid "Details:"
msgstr "Détails :"
#: Cli.php:44
msgid "Create a new project using EesyPHP framework"
msgstr "Créer un nouveau project utilisant le framework EesyPHP"
@ -261,13 +273,7 @@ msgstr ""
"Port d'écoute spécifié invalid. Il doit s'agir d'un entier positif entre 1 "
"et 65535."
#: Cli.php:418
msgid "Can't invoke bash. Can't ask password prompt."
msgstr ""
"Impossible d'utiliser bash. Impossible de demander à l'utilisateur de saisir "
"un not de passe."
#: Cli.php:421
#: Cli.php:415
msgid "Please enter password:"
msgstr "Merci de saisir le not de passe :"
@ -300,19 +306,19 @@ msgstr "ns"
msgid "Less than 1%s"
msgstr "Moins de 1%s"
#: App.php:239 I18n.php:119
#: App.php:242 I18n.php:119
msgid "Hello world !"
msgstr "Bonjour tout le monde !"
#: App.php:241
#: App.php:244
msgid "Hello world!"
msgstr "Salut tout le monde !"
#: App.php:252
#: App.php:255
msgid "Disconnected"
msgstr "Déconnecté"
#: App.php:254
#: App.php:257
msgid "You are now disconnected."
msgstr "Vous êtes maintenant déconnecté."
@ -606,12 +612,12 @@ msgstr ""
"\n"
"Mail originalement destiné à %s."
#: Email.php:139
#: Email.php:137
#, php-format
msgid "<p><small>%s: %s</small></p>"
msgstr "<p><small>%s: %s</small></p>"
#: Email.php:140
#: Email.php:138
#, php-format
msgid ""
"\n"
@ -657,6 +663,10 @@ msgstr "Erreur : %1"
msgid "Back"
msgstr "Retour"
#: templates/access_denied.tpl:12
msgid "Details: %1"
msgstr "Détails : %1"
#: templates/empty.tpl:74
msgid "Sign out"
msgstr "Déconnexion"
@ -701,6 +711,11 @@ msgstr ""
"fichier <em>homepage.tpl</em> pour l'écraser. Vous pouvez également écraser "
"le gestionnaire de l'URL racine de l'application web."
#~ msgid "Can't invoke bash. Can't ask password prompt."
#~ msgstr ""
#~ "Impossible d'utiliser bash. Impossible de demander à l'utilisateur de "
#~ "saisir un not de passe."
#~ msgid "Confirmation"
#~ msgstr "Confirmation"

View file

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2024-01-23 18:19+0000\n"
"PO-Revision-Date: 2024-01-23 18:19+0000\n"
"POT-Creation-Date: 2024-02-21 09:12+0000\n"
"PO-Revision-Date: 2024-02-21 09:12+0000\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@ -22,7 +22,7 @@ msgstr ""
msgid "Unknown"
msgstr ""
#: Db.php:78
#: Db.php:93
msgid "Unable to connect to the database."
msgstr ""
@ -38,7 +38,7 @@ msgstr ""
msgid "Authentication required"
msgstr ""
#: Auth/Http.php:124 Auth/Http.php:127 Url.php:185
#: Auth/Http.php:124 Auth/Http.php:127 Url.php:185 Auth.php:340 Auth.php:343
msgid "Access denied"
msgstr ""
@ -46,6 +46,10 @@ msgstr ""
msgid "You must login to access this page."
msgstr ""
#: Auth/Casuser.php:88 Auth/Casuser.php:112
msgid "Configuration error in CAS auth backend."
msgstr ""
#: Url.php:177
msgid "Bad request"
msgstr ""
@ -104,6 +108,14 @@ msgstr ""
msgid "This request could not be processed correctly."
msgstr ""
#: Auth.php:344
msgid "You do not have access to this application."
msgstr ""
#: Auth.php:348
msgid "Details:"
msgstr ""
#: Cli.php:44
msgid "Create a new project using EesyPHP framework"
msgstr ""
@ -223,11 +235,7 @@ msgid ""
"65535."
msgstr ""
#: Cli.php:418
msgid "Can't invoke bash. Can't ask password prompt."
msgstr ""
#: Cli.php:421
#: Cli.php:415
msgid "Please enter password:"
msgstr ""
@ -260,19 +268,19 @@ msgstr ""
msgid "Less than 1%s"
msgstr ""
#: App.php:239 I18n.php:119
#: App.php:242 I18n.php:119
msgid "Hello world !"
msgstr ""
#: App.php:241
#: App.php:244
msgid "Hello world!"
msgstr ""
#: App.php:252
#: App.php:255
msgid "Disconnected"
msgstr ""
#: App.php:254
#: App.php:257
msgid "You are now disconnected."
msgstr ""
@ -523,12 +531,12 @@ msgid ""
"Mail initially intended for %s."
msgstr ""
#: Email.php:139
#: Email.php:137
#, php-format
msgid "<p><small>%s: %s</small></p>"
msgstr ""
#: Email.php:140
#: Email.php:138
#, php-format
msgid ""
"\n"
@ -569,6 +577,10 @@ msgstr ""
msgid "Back"
msgstr ""
#: templates/access_denied.tpl:12
msgid "Details: %1"
msgstr ""
#: templates/empty.tpl:74
msgid "Sign out"
msgstr ""

View file

@ -328,4 +328,27 @@ class Auth {
public static function user() {
return self :: $user;
}
/**
* Helper function to trigger access denied error
* @param string|null $details Reason or details about this error
* @return never
*/
public static function access_denied($details=null) {
if (Tpl::initialized()) {
Tpl :: assign("details", $details);
Tpl :: display("access_denied.tpl", I18n::_("Access denied"));
}
else {
printf("<h1>%s</h1>", I18n::_("Access denied"));
printf("<p>%s</p>", I18n::_("You do not have access to this application."));
if ($details)
printf(
"<p><small>%s%s</small></p>",
I18n::_("Details:"),
$details
);
}
exit();
}
}

View file

@ -57,6 +57,16 @@ class Cas extends Method {
'default' => null,
),
),
/*
* CAS user backend access filters:
* [
* attr => regex,
* attr => callable (will receive the username and the attr value as parameters),
* callable, (will receive the username and an associative array of all attrs values as
* parameters)
* ]
*/
'user_filters' => array(),
)
);
self :: $fake_authenticated_user = App :: get(

View file

@ -3,10 +3,14 @@
namespace EesyPHP\Auth;
use EesyPHP\App;
use EesyPHP\Auth;
use EesyPHP\Auth\User;
use EesyPHP\Check;
use EesyPHP\Config;
use EesyPHP\I18n;
use EesyPHP\Log;
use function EesyPHP\cast;
use function EesyPHP\format_callable;
use function EesyPHP\vardump;
use phpCAS;
@ -37,6 +41,9 @@ class Casuser extends Backend {
return null;
}
// Check user filters and denied access if not match
self :: check_user_filters($username);
$info = array();
foreach(Config::get('auth.cas.user_attributes') as $name => $attr_config) {
$cas_name = Config::get("cas_name", null, 'string', false, $attr_config);
@ -52,4 +59,68 @@ class Casuser extends Backend {
return new User($username, '\\EesyPHP\\Auth\\Casuser', $info);
}
/**
* Check authenticated user match with configured filters and denied access if not
* @param string $username
* @return void|never
*/
public static function check_user_filters($username) {
foreach(Config::get('auth.cas.user_filters', [], 'array') as $attr => $filter) {
if (is_callable($filter)) {
if (
!$filter(
$username,
is_string($attr)?phpCAS::getAttribute($attr):phpCAS::getAttributes()
)
)
{
Log::warning("get_user(%s): filter out by %s", $username, format_callable($filter));
Auth::access_denied();
}
}
else if (is_string($attr)) {
$regex_valid = Check :: regex($filter, true);
if ($regex_valid !== true) {
Log::error(
"Casuser auth backend: Invalid regex provided for attribute %s: %s (%s)",
$attr, $regex_valid, $filter
);
Log::fatal(I18n::_("Configuration error in CAS auth backend."));
}
$attr_values = self :: get_attr($attr, [], 'array');
if (!$attr_values) {
Log::warning(
"get_user(%s): filter out by attribute %s (not defined)",
$username, $attr
);
Auth::access_denied();
}
$match = false;
foreach ($attr_values as $attr_value) {
if (preg_match($filter, $attr_value)) {
$match = true;
break;
}
}
if (!$match) {
Log::warning(
"get_user(%s): filter out by attribute %s (not match with '%s')",
$username, $attr, $filter
);
Auth::access_denied();
}
}
else {
Log::error(
"Casuser auth backend: Invalid filter rule configured (%s => %s)",
vardump($attr), vardump($filter)
);
Log::fatal(I18n::_("Configuration error in CAS auth backend."));
}
}
}
}

View file

@ -0,0 +1,20 @@
{extends file='Tpl:empty.tpl'}
{block name="pagetitle"}{/block}
{block name="content"}
<div class="p-5 mb-4 bg-light rounded-3">
<div class="container-fluid py-5">
<h1 class="display-5 fw-bold">{t domain=$CORE_TEXT_DOMAIN}Access denied{/t}</h1>
<p class="col-md-8 fs-4">
{t escape=off domain=$CORE_TEXT_DOMAIN}You do not have access to this application.{/t}
</p>
{if $details}
<p class="col-md-8 fs-6 fw-lighter fst-italic">
{t 1=$details domain=$CORE_TEXT_DOMAIN}Details: %1{/t}
</p>
{/if}
</div>
</div>
{/block}
{*
# vim: autoindent expandtab tabstop=2 shiftwidth=2 softtabstop=2
*}