Compare commits
3 commits
16659cdaf6
...
a4d2e3369c
Author | SHA1 | Date | |
---|---|---|---|
a4d2e3369c | |||
3edf176dc2 | |||
610cdb0f7c |
29 changed files with 1530 additions and 128 deletions
|
@ -27,7 +27,8 @@
|
|||
"ext-pdo": "^7.3",
|
||||
"ext-json": "*",
|
||||
"ext-yaml": "^2.0",
|
||||
"league/mime-type-detection": "^1.11"
|
||||
"league/mime-type-detection": "^1.11",
|
||||
"apereo/phpcas": "^1.6"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^1.9"
|
||||
|
|
|
@ -134,6 +134,140 @@ db:
|
|||
#datetime_format: '%Y-%m-%d %H:%M:%S' # Exemple : 2018-10-12 18:06:59
|
||||
|
||||
|
||||
#
|
||||
# Authentication
|
||||
#
|
||||
auth:
|
||||
# Enabled authentication
|
||||
enabled: false
|
||||
|
||||
# Methods to authenticate users
|
||||
methods:
|
||||
- form
|
||||
- http
|
||||
#- cas
|
||||
|
||||
# User backends
|
||||
backends:
|
||||
- ldap
|
||||
|
||||
#
|
||||
# Login form
|
||||
#
|
||||
login_form:
|
||||
# Display link for other authentication methods
|
||||
# Note: method as key and label as value
|
||||
display_other_methods:
|
||||
http: "HTTP"
|
||||
cas: "SSO"
|
||||
|
||||
#
|
||||
# HTTP Authentication Configuration
|
||||
#
|
||||
http:
|
||||
# HTTP Auth methods :
|
||||
# * AUTHORIZATION : use HTTP_AUTHORIZATION environnement. This mode could be use with PHP FPM.
|
||||
# Specific configuration is need in Apache to use this mode :
|
||||
# RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
|
||||
# * REMOTE_USER : use REMOTE_USER environnement variable to retreive authenticated user's login
|
||||
# This method could be only used with $http_auth_trust_without_password_challenge
|
||||
# enabled.
|
||||
# * PHP_AUTH : use PHP_AUTH_USER and PHP_AUTH_PW environnement variables (only available
|
||||
# using mod_php with Apache. (default)
|
||||
method: 'PHP_AUTH'
|
||||
|
||||
# Trust HTTP server authentication
|
||||
# If enabled, the application will no check user credentials and only retreive user's login
|
||||
# from HTTP server.
|
||||
#trust_without_password_challenge: true
|
||||
|
||||
# Realm (use when force HTTP login, optional)
|
||||
#realm: "Authentication required"
|
||||
|
||||
#
|
||||
# CAS Configuration
|
||||
#
|
||||
cas:
|
||||
# CAS host (just the domain name)
|
||||
host: 'idp.example.com'
|
||||
|
||||
# CAS context (the root path, default: '/idp/cas')
|
||||
# Example: for 'http://idp.example.com/idp/cas', put '/idp/cas'
|
||||
context: '/idp/cas'
|
||||
|
||||
# CAS HTTP port (default: 443)
|
||||
#port: 443
|
||||
|
||||
# CAS procotol version
|
||||
# Posssible values: "1.0", "2.0" (default), "3.0" or "S1" (SAML1)
|
||||
#version: '2.0'
|
||||
|
||||
# CAS server SSL certificate validation (set to false to disable)
|
||||
ca_cert_certificate_path: "/etc/ssl/certs/ca-certificates.crt"
|
||||
|
||||
# CAS Debug log file
|
||||
#debug_log_file: "${root_directory_path}/data/logs/cas.log"
|
||||
|
||||
# CAS Logout
|
||||
#logout: true # Enable CAS logout on app logout
|
||||
#logout_url: "https://my.example.fr/logout/" # Specify custom CAS logout URL
|
||||
|
||||
# CAS Fake authenticated user
|
||||
#fake_authenticated_user: 'myusername'
|
||||
|
||||
#
|
||||
# LDAP user backend
|
||||
#
|
||||
ldap:
|
||||
# LDAP host (required, multiple hosts could be specified with comma separator)
|
||||
host: 'ldap://localhost'
|
||||
|
||||
# LDAP port (optional)
|
||||
#port: 389
|
||||
|
||||
# Enable STARTTLS (optional, default: false)
|
||||
#starttls: false
|
||||
|
||||
# LDAP directory base DN (required)
|
||||
basedn: 'o=example'
|
||||
|
||||
# LDAP bind DN (optional)
|
||||
#bind_dn: 'uid=eesyphp,ou=sysaccounts,${auth.ldap.basedn}'
|
||||
|
||||
# LDAP bind password (optional)
|
||||
#bind_password: 'secret'
|
||||
|
||||
# User search filter by username. The keyword "[username]" will be replace before search by
|
||||
# the looked username (default: "uid=[username]")
|
||||
#user_filter_by_uid: 'uid=[username]'
|
||||
|
||||
# User base DN
|
||||
user_basedn: 'ou=people,${auth.ldap.basedn}'
|
||||
|
||||
# Bind with username instead of user DN (optional, default: false)
|
||||
#bind_with_username: true
|
||||
|
||||
# LDAP user attributes to retreive with their properties:
|
||||
# [LDAP attr name]:
|
||||
# name: [map name] # optional, default: LDAP attr name
|
||||
# type: [type of value] # optional, default: 'string', possible values: string, bool, int, float
|
||||
# multivalued: true # optional, default: false
|
||||
# default: null # optional, default: null
|
||||
user_attributes:
|
||||
uid:
|
||||
name: 'login'
|
||||
multivalued: false
|
||||
default: null
|
||||
cn:
|
||||
name: 'name'
|
||||
multivalued: false
|
||||
default: null
|
||||
mail:
|
||||
type: 'string'
|
||||
|
||||
# PEAR Net_LDAP2 library path (optional, default: Net/LDAP2.php)
|
||||
#netldap2_path: 'Net/LDAP2.php'
|
||||
|
||||
#
|
||||
# Email configuration
|
||||
#
|
||||
|
|
Binary file not shown.
|
@ -1,7 +1,7 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"POT-Creation-Date: 2023-02-14 01:17+0100\n"
|
||||
"POT-Creation-Date: 2023-02-25 04:54+0100\n"
|
||||
"PO-Revision-Date: \n"
|
||||
"Last-Translator: Benjamin Renard <brenard@zionetrix.net>\n"
|
||||
"Language-Team: \n"
|
||||
|
@ -70,6 +70,22 @@ msgstr "Une exception est survenue en exécutant la commande %s"
|
|||
msgid "Unable to connect to the database."
|
||||
msgstr "Impossible de se connecter à la base de données."
|
||||
|
||||
#: Auth/Form.php:32
|
||||
msgid "Invalid username or password."
|
||||
msgstr "Nom d'utilisateur ou mot de passe invalide."
|
||||
|
||||
#: Auth/Http.php:34 Url.php:176
|
||||
msgid "Authentication required"
|
||||
msgstr "Authentification requise"
|
||||
|
||||
#: Auth/Http.php:115 Auth/Http.php:118 Url.php:180
|
||||
msgid "Access denied"
|
||||
msgstr "Accès interdit"
|
||||
|
||||
#: Auth/Http.php:119 Auth/Http.php:123
|
||||
msgid "You must login to access this page."
|
||||
msgstr "Vous devez vous connecter pour accéder à cette page."
|
||||
|
||||
#: Email.php:141
|
||||
#, php-format
|
||||
msgid "</hr><p><small>Mail initialy intended for %s.</small></p>"
|
||||
|
@ -102,35 +118,27 @@ msgstr ""
|
|||
"\n"
|
||||
"%s: %s"
|
||||
|
||||
#: Tpl.php:355
|
||||
#: Tpl.php:394
|
||||
msgid "No template specified."
|
||||
msgstr "Aucun template spécifié."
|
||||
|
||||
#: Tpl.php:386
|
||||
#: Tpl.php:425
|
||||
msgid "An error occurred while displaying this page."
|
||||
msgstr "Une erreur est survenue en affichant cette page."
|
||||
|
||||
#: Url.php:141
|
||||
#: Url.php:172
|
||||
msgid "Bad request"
|
||||
msgstr "Mauvaise requête"
|
||||
|
||||
#: Url.php:142
|
||||
#: Url.php:173
|
||||
msgid "Invalid request."
|
||||
msgstr "Requête invalide."
|
||||
|
||||
#: Url.php:145
|
||||
msgid "Authentication required"
|
||||
msgstr "Authentification requise"
|
||||
|
||||
#: Url.php:146
|
||||
#: Url.php:177
|
||||
msgid "You have to be authenticated to access to this page."
|
||||
msgstr "Vous devez être authentifié pour accéder à cette page."
|
||||
|
||||
#: Url.php:149
|
||||
msgid "Access denied"
|
||||
msgstr "Accès interdit"
|
||||
|
||||
#: Url.php:150
|
||||
#: Url.php:181
|
||||
msgid ""
|
||||
"You do not have access to this application. If you think this is an error, "
|
||||
"please contact support."
|
||||
|
@ -138,25 +146,25 @@ msgstr ""
|
|||
"Vous n'avez pas accès à cette application. Si vous pensez qu'il s'agit d'une "
|
||||
"erreur, merci de prendre contact avec le support."
|
||||
|
||||
#: Url.php:153
|
||||
#: Url.php:184
|
||||
msgid "Whoops ! Page not found"
|
||||
msgstr "Oups ! Page introuvable"
|
||||
|
||||
#: Url.php:154
|
||||
#: Url.php:185
|
||||
msgid "The requested page can not be found."
|
||||
msgstr "La page demandée est introuvable."
|
||||
|
||||
#: Url.php:162
|
||||
#: Url.php:193
|
||||
msgid "Error"
|
||||
msgstr "Erreur"
|
||||
|
||||
#: Url.php:163
|
||||
#: Url.php:194
|
||||
msgid "An unknown error occurred. If problem persist, please contact support."
|
||||
msgstr ""
|
||||
"Une erreur inconnue est survenue. Si le problème persiste, merci de prendre "
|
||||
"contact avec le support."
|
||||
|
||||
#: Url.php:226
|
||||
#: Url.php:257
|
||||
msgid ""
|
||||
"Unable to determine the requested page. If the problem persists, please "
|
||||
"contact support."
|
||||
|
@ -164,7 +172,7 @@ msgstr ""
|
|||
"Impossible de déterminer la page demandée. Si le problème persiste, merci de "
|
||||
"prendre contact avec le support."
|
||||
|
||||
#: Url.php:376
|
||||
#: Url.php:411
|
||||
msgid ""
|
||||
"Unable to determine the requested page (loop detected). If the problem "
|
||||
"persists, please contact support."
|
||||
|
@ -172,22 +180,19 @@ msgstr ""
|
|||
"Impossible de déterminer la page demandée (boucle détectée). Si le problème "
|
||||
"persiste, merci de prendre contact avec le support."
|
||||
|
||||
#: Url.php:407
|
||||
#: Url.php:441
|
||||
msgid "This request cannot be processed."
|
||||
msgstr "Cette requête ne peut être traitée."
|
||||
|
||||
#: Url.php:420
|
||||
msgid ""
|
||||
"Authentication required but force_authentication function is not defined."
|
||||
msgstr ""
|
||||
"Authentification requise mais la fonction force_authentication n'est pas "
|
||||
"définie."
|
||||
#: Url.php:451
|
||||
msgid "Authentication required but fail to authenticate you."
|
||||
msgstr "Authentification requise mais impossible pour vous authentifier."
|
||||
|
||||
#: Url.php:429
|
||||
#: Url.php:460
|
||||
msgid "This request could not be processed correctly."
|
||||
msgstr "Cette requête n'a put être traitée correctement."
|
||||
|
||||
#: I18n.php:122 App.php:120
|
||||
#: I18n.php:122 App.php:124
|
||||
msgid "Hello world !"
|
||||
msgstr "Bonjour tout le monde !"
|
||||
|
||||
|
@ -379,10 +384,18 @@ msgstr "Impossible d'écrire le fichier du catalogue JS %s (%s)."
|
|||
msgid "%s JS catalog writed (%s)."
|
||||
msgstr "Catalogue JS %s créé (%s)."
|
||||
|
||||
#: App.php:122
|
||||
#: App.php:126
|
||||
msgid "Hello world!"
|
||||
msgstr "Salut tout le monde !"
|
||||
|
||||
#: App.php:137
|
||||
msgid "Disconnected"
|
||||
msgstr "Déconnecté"
|
||||
|
||||
#: App.php:139
|
||||
msgid "You are now disconnected."
|
||||
msgstr "Vous êtes maintenant déconnecté."
|
||||
|
||||
#: static/js/myconfirm.js:4 static/js/myconfirm.js:171
|
||||
#: static/js/myconfirm.js:200
|
||||
msgid "Confirmation"
|
||||
|
@ -460,3 +473,29 @@ msgstr ""
|
|||
"framework EesyPHP. Configurez votre propre dossier de templates et créer le "
|
||||
"fichier <em>homepage.tpl</em> pour l'écraser. Vous pouvez également écraser "
|
||||
"le gestionnaire de l'URL racine de l'application web."
|
||||
|
||||
#: templates/empty.tpl:60
|
||||
msgid "Logout"
|
||||
msgstr "Déconnexion"
|
||||
|
||||
#: templates/login.tpl:2
|
||||
msgid "Connection"
|
||||
msgstr "Connexion"
|
||||
|
||||
#: templates/login.tpl:7
|
||||
msgid "Username"
|
||||
msgstr "Nom d'utilisateur"
|
||||
|
||||
#: templates/login.tpl:11
|
||||
msgid "Password"
|
||||
msgstr "Mot de passe"
|
||||
|
||||
#: templates/login.tpl:14
|
||||
msgid "Submit"
|
||||
msgstr "Envoyer"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Authentication required but force_authentication function is not defined."
|
||||
#~ msgstr ""
|
||||
#~ "Authentification requise mais la fonction force_authentication n'est pas "
|
||||
#~ "définie."
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2023-02-14 01:17+0100\n"
|
||||
"PO-Revision-Date: 2023-02-14 01:17+0100\n"
|
||||
"POT-Creation-Date: 2023-02-25 04:54+0100\n"
|
||||
"PO-Revision-Date: 2023-02-25 04:54+0100\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
|
@ -1,7 +1,7 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"POT-Creation-Date: 2023-02-14 01:17+0100\n"
|
||||
"PO-Revision-Date: 2023-02-14 01:17+0100\n"
|
||||
"POT-Creation-Date: 2023-02-25 04:54+0100\n"
|
||||
"PO-Revision-Date: 2023-02-25 04:54+0100\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
@ -61,6 +61,22 @@ msgstr ""
|
|||
msgid "Unable to connect to the database."
|
||||
msgstr ""
|
||||
|
||||
#: Auth/Form.php:32
|
||||
msgid "Invalid username or password."
|
||||
msgstr ""
|
||||
|
||||
#: Auth/Http.php:34 Url.php:176
|
||||
msgid "Authentication required"
|
||||
msgstr ""
|
||||
|
||||
#: Auth/Http.php:115 Auth/Http.php:118 Url.php:180
|
||||
msgid "Access denied"
|
||||
msgstr ""
|
||||
|
||||
#: Auth/Http.php:119 Auth/Http.php:123
|
||||
msgid "You must login to access this page."
|
||||
msgstr ""
|
||||
|
||||
#: Email.php:141
|
||||
#, php-format
|
||||
msgid "</hr><p><small>Mail initialy intended for %s.</small></p>"
|
||||
|
@ -87,82 +103,73 @@ msgid ""
|
|||
"%s: %s"
|
||||
msgstr ""
|
||||
|
||||
#: Tpl.php:355
|
||||
#: Tpl.php:394
|
||||
msgid "No template specified."
|
||||
msgstr ""
|
||||
|
||||
#: Tpl.php:386
|
||||
#: Tpl.php:425
|
||||
msgid "An error occurred while displaying this page."
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:141
|
||||
#: Url.php:172
|
||||
msgid "Bad request"
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:142
|
||||
#: Url.php:173
|
||||
msgid "Invalid request."
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:145
|
||||
msgid "Authentication required"
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:146
|
||||
#: Url.php:177
|
||||
msgid "You have to be authenticated to access to this page."
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:149
|
||||
msgid "Access denied"
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:150
|
||||
#: Url.php:181
|
||||
msgid ""
|
||||
"You do not have access to this application. If you think this is an error, "
|
||||
"please contact support."
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:153
|
||||
#: Url.php:184
|
||||
msgid "Whoops ! Page not found"
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:154
|
||||
#: Url.php:185
|
||||
msgid "The requested page can not be found."
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:162
|
||||
#: Url.php:193
|
||||
msgid "Error"
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:163
|
||||
#: Url.php:194
|
||||
msgid "An unknown error occurred. If problem persist, please contact support."
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:226
|
||||
#: Url.php:257
|
||||
msgid ""
|
||||
"Unable to determine the requested page. If the problem persists, please "
|
||||
"contact support."
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:376
|
||||
#: Url.php:411
|
||||
msgid ""
|
||||
"Unable to determine the requested page (loop detected). If the problem "
|
||||
"persists, please contact support."
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:407
|
||||
#: Url.php:441
|
||||
msgid "This request cannot be processed."
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:420
|
||||
msgid ""
|
||||
"Authentication required but force_authentication function is not defined."
|
||||
#: Url.php:451
|
||||
msgid "Authentication required but fail to authenticate you."
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:429
|
||||
#: Url.php:460
|
||||
msgid "This request could not be processed correctly."
|
||||
msgstr ""
|
||||
|
||||
#: I18n.php:122 App.php:120
|
||||
#: I18n.php:122 App.php:124
|
||||
msgid "Hello world !"
|
||||
msgstr ""
|
||||
|
||||
|
@ -321,10 +328,18 @@ msgstr ""
|
|||
msgid "%s JS catalog writed (%s)."
|
||||
msgstr ""
|
||||
|
||||
#: App.php:122
|
||||
#: App.php:126
|
||||
msgid "Hello world!"
|
||||
msgstr ""
|
||||
|
||||
#: App.php:137
|
||||
msgid "Disconnected"
|
||||
msgstr ""
|
||||
|
||||
#: App.php:139
|
||||
msgid "You are now disconnected."
|
||||
msgstr ""
|
||||
|
||||
#: static/js/myconfirm.js:4 static/js/myconfirm.js:171
|
||||
#: static/js/myconfirm.js:200
|
||||
msgid "Confirmation"
|
||||
|
@ -395,3 +410,23 @@ msgid ""
|
|||
"it. You could also overwrite the URL handler for the root of the web "
|
||||
"application."
|
||||
msgstr ""
|
||||
|
||||
#: templates/empty.tpl:60
|
||||
msgid "Logout"
|
||||
msgstr ""
|
||||
|
||||
#: templates/login.tpl:2
|
||||
msgid "Connection"
|
||||
msgstr ""
|
||||
|
||||
#: templates/login.tpl:7
|
||||
msgid "Username"
|
||||
msgstr ""
|
||||
|
||||
#: templates/login.tpl:11
|
||||
msgid "Password"
|
||||
msgstr ""
|
||||
|
||||
#: templates/login.tpl:14
|
||||
msgid "Submit"
|
||||
msgstr ""
|
||||
|
|
|
@ -53,6 +53,22 @@ msgstr ""
|
|||
msgid "Unable to connect to the database."
|
||||
msgstr ""
|
||||
|
||||
#: Auth/Form.php:32
|
||||
msgid "Invalid username or password."
|
||||
msgstr ""
|
||||
|
||||
#: Auth/Http.php:34 Url.php:176
|
||||
msgid "Authentication required"
|
||||
msgstr ""
|
||||
|
||||
#: Auth/Http.php:115 Auth/Http.php:118 Url.php:180
|
||||
msgid "Access denied"
|
||||
msgstr ""
|
||||
|
||||
#: Auth/Http.php:119 Auth/Http.php:123
|
||||
msgid "You must login to access this page."
|
||||
msgstr ""
|
||||
|
||||
#: Email.php:141
|
||||
#, php-format
|
||||
msgid "</hr><p><small>Mail initialy intended for %s.</small></p>"
|
||||
|
@ -79,82 +95,73 @@ msgid ""
|
|||
"%s: %s"
|
||||
msgstr ""
|
||||
|
||||
#: Tpl.php:355
|
||||
#: Tpl.php:394
|
||||
msgid "No template specified."
|
||||
msgstr ""
|
||||
|
||||
#: Tpl.php:386
|
||||
#: Tpl.php:425
|
||||
msgid "An error occurred while displaying this page."
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:141
|
||||
#: Url.php:172
|
||||
msgid "Bad request"
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:142
|
||||
#: Url.php:173
|
||||
msgid "Invalid request."
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:145
|
||||
msgid "Authentication required"
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:146
|
||||
#: Url.php:177
|
||||
msgid "You have to be authenticated to access to this page."
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:149
|
||||
msgid "Access denied"
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:150
|
||||
#: Url.php:181
|
||||
msgid ""
|
||||
"You do not have access to this application. If you think this is an error, "
|
||||
"please contact support."
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:153
|
||||
#: Url.php:184
|
||||
msgid "Whoops ! Page not found"
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:154
|
||||
#: Url.php:185
|
||||
msgid "The requested page can not be found."
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:162
|
||||
#: Url.php:193
|
||||
msgid "Error"
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:163
|
||||
#: Url.php:194
|
||||
msgid "An unknown error occurred. If problem persist, please contact support."
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:226
|
||||
#: Url.php:257
|
||||
msgid ""
|
||||
"Unable to determine the requested page. If the problem persists, please "
|
||||
"contact support."
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:376
|
||||
#: Url.php:411
|
||||
msgid ""
|
||||
"Unable to determine the requested page (loop detected). If the problem "
|
||||
"persists, please contact support."
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:407
|
||||
#: Url.php:441
|
||||
msgid "This request cannot be processed."
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:420
|
||||
msgid ""
|
||||
"Authentication required but force_authentication function is not defined."
|
||||
#: Url.php:451
|
||||
msgid "Authentication required but fail to authenticate you."
|
||||
msgstr ""
|
||||
|
||||
#: Url.php:429
|
||||
#: Url.php:460
|
||||
msgid "This request could not be processed correctly."
|
||||
msgstr ""
|
||||
|
||||
#: I18n.php:122 App.php:120
|
||||
#: I18n.php:122 App.php:124
|
||||
msgid "Hello world !"
|
||||
msgstr ""
|
||||
|
||||
|
@ -313,6 +320,14 @@ msgstr ""
|
|||
msgid "%s JS catalog writed (%s)."
|
||||
msgstr ""
|
||||
|
||||
#: App.php:122
|
||||
#: App.php:126
|
||||
msgid "Hello world!"
|
||||
msgstr ""
|
||||
|
||||
#: App.php:137
|
||||
msgid "Disconnected"
|
||||
msgstr ""
|
||||
|
||||
#: App.php:139
|
||||
msgid "You are now disconnected."
|
||||
msgstr ""
|
||||
|
|
|
@ -19,6 +19,14 @@ msgstr ""
|
|||
msgid "Back"
|
||||
msgstr ""
|
||||
|
||||
#: templates/logout.tpl:5
|
||||
msgid "Disconnected"
|
||||
msgstr ""
|
||||
|
||||
#: templates/logout.tpl:6
|
||||
msgid "You are now disconnected."
|
||||
msgstr ""
|
||||
|
||||
#: templates/homepage.tpl:5
|
||||
msgid "Hello, world!"
|
||||
msgstr ""
|
||||
|
@ -30,3 +38,31 @@ msgid ""
|
|||
"it. You could also overwrite the URL handler for the root of the web "
|
||||
"application."
|
||||
msgstr ""
|
||||
|
||||
#: templates/empty.tpl:60
|
||||
msgid "Logout"
|
||||
msgstr ""
|
||||
|
||||
#: templates/login.tpl:2
|
||||
msgid "Connection"
|
||||
msgstr ""
|
||||
|
||||
#: templates/login.tpl:7
|
||||
msgid "Username"
|
||||
msgstr ""
|
||||
|
||||
#: templates/login.tpl:11
|
||||
msgid "Password"
|
||||
msgstr ""
|
||||
|
||||
#: templates/login.tpl:14
|
||||
msgid "Submit"
|
||||
msgstr ""
|
||||
|
||||
#: templates/must_login.tpl:5
|
||||
msgid "Access denied"
|
||||
msgstr ""
|
||||
|
||||
#: templates/must_login.tpl:6
|
||||
msgid "You must login to access this page."
|
||||
msgstr ""
|
||||
|
|
14
phpstan.neon
14
phpstan.neon
|
@ -8,8 +8,22 @@ parameters:
|
|||
- example/includes/config.local.php
|
||||
- example/data/tmp/templates_c
|
||||
universalObjectCratesClasses:
|
||||
- EesyPHP\HookEvent
|
||||
- EesyPHP\UrlRequest
|
||||
- EesyPHP\Auth\User
|
||||
ignoreErrors:
|
||||
-
|
||||
message: "#Property EesyPHP\\\\Auth\\\\Ldap::\\$connection has unknown class Net_LDAP2 as its type\\.#"
|
||||
path: src/Auth/Ldap.php
|
||||
-
|
||||
message: "#Call to method search\\(\\) on an unknown class Net_LDAP2\\.#"
|
||||
path: src/Auth/Ldap.php
|
||||
-
|
||||
message: "#Call to static method connect\\(\\) on an unknown class Net_LDAP2\\.#"
|
||||
path: src/Auth/Ldap.php
|
||||
-
|
||||
message: "#Call to static method escape\\(\\) on an unknown class Net_LDAP2_Filter\\.#"
|
||||
path: src/Auth/Ldap.php
|
||||
-
|
||||
message: "#Instantiated class Mail_mime not found\\.#"
|
||||
path: src/Email.php
|
||||
|
|
17
src/App.php
17
src/App.php
|
@ -64,6 +64,10 @@ class App {
|
|||
Url::init();
|
||||
Url :: add_url_handler('#^$#', array('EesyPHP\\App', 'handle_homepage'));
|
||||
}
|
||||
if (Auth :: enabled()) {
|
||||
Auth :: init();
|
||||
Url :: add_url_handler('#^logout$#', array('EesyPHP\\App', 'handle_logout'), null, false);
|
||||
}
|
||||
if (self :: get('mail.enabled', true, 'bool'))
|
||||
Email :: init();
|
||||
if (self :: get('i18n.enabled', true, 'bool'))
|
||||
|
@ -122,4 +126,17 @@ class App {
|
|||
echo "<h1>".I18n::_("Hello world!")."</h1>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Default logout handler
|
||||
* @param UrlRequest $request
|
||||
* @return void
|
||||
*/
|
||||
public static function handle_logout($request) {
|
||||
Auth::logout();
|
||||
if (Tpl::initialized())
|
||||
Tpl :: display("logout.tpl", I18n::_("Disconnected"));
|
||||
else
|
||||
echo "<h1>".I18n::_("You are now disconnected.")."</h1>";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
306
src/Auth.php
Normal file
306
src/Auth.php
Normal file
|
@ -0,0 +1,306 @@
|
|||
<?php
|
||||
|
||||
namespace EesyPHP;
|
||||
|
||||
|
||||
class Auth {
|
||||
|
||||
/**
|
||||
* Initialized methods
|
||||
* @var array<string,string>
|
||||
*/
|
||||
private static $methods = array();
|
||||
|
||||
/**
|
||||
* Method name used to authenticate current user
|
||||
* @var string|null
|
||||
*/
|
||||
private static $logged_method = null;
|
||||
|
||||
/**
|
||||
* Initialized backends
|
||||
* @var array<string,string>
|
||||
*/
|
||||
private static $backends = array();
|
||||
|
||||
/**
|
||||
* Current authenticated user
|
||||
* @var \EesyPHP\Auth\User|null
|
||||
*/
|
||||
private static $user = null;
|
||||
|
||||
/**
|
||||
* Initialize
|
||||
* @return void
|
||||
*/
|
||||
public static function init() {
|
||||
if (!self :: enabled()) return;
|
||||
self :: $methods = array();
|
||||
foreach(App::get('auth.methods', array(), 'array') as $method) {
|
||||
if (!$method || !is_string($method)) {
|
||||
Log::warning(
|
||||
'Auth Init: Invalid auth method retreive from configuration, ignore it: %s',
|
||||
vardump($method));
|
||||
continue;
|
||||
}
|
||||
$class = (
|
||||
$method[0] == '\\'?
|
||||
$method:
|
||||
"\\EesyPHP\\Auth\\".ucfirst($method)
|
||||
);
|
||||
if (!class_exists($class)) {
|
||||
Log::warning(
|
||||
"Auth Init: Unknown auth method '%s' retreived from configuration, ignore it",
|
||||
$method
|
||||
);
|
||||
continue;
|
||||
}
|
||||
$parents = class_parents($class);
|
||||
if (!is_array($parents) || !in_array('EesyPHP\\Auth\\Method', $parents)) {
|
||||
Log::warning(
|
||||
'Auth Init: Auth method %s class (%s) do not derivate from \\EesyPHP\\Auth\\Method '.
|
||||
'class, ignore it.',
|
||||
$method, $class);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!call_user_func(array($class, 'init'))) {
|
||||
Log::warning(
|
||||
'Auth Init: fail to initialize auth method %s, ignore it',
|
||||
$method, $class);
|
||||
continue;
|
||||
}
|
||||
Log::trace('Auth method %s initialized (class %s)', $method, $class);
|
||||
self :: $methods[strtolower($method)] = $class;
|
||||
}
|
||||
|
||||
self :: $backends = array();
|
||||
foreach(App::get('auth.backends', array(), 'array') as $backend) {
|
||||
if (!$backend || !is_string($backend)) {
|
||||
Log::warning(
|
||||
'Auth Init: Invalid auth backend retreive from configuration, ignore it: %s',
|
||||
vardump($backend));
|
||||
continue;
|
||||
}
|
||||
$class = (
|
||||
$backend[0] == '\\'?
|
||||
$backend:
|
||||
"\\EesyPHP\\Auth\\".ucfirst($backend)
|
||||
);
|
||||
if (!class_exists($class)) {
|
||||
Log::warning(
|
||||
"Auth Init: Unknown auth backend '%s' retreived from configuration, ignore it",
|
||||
$backend
|
||||
);
|
||||
continue;
|
||||
}
|
||||
$parents = class_parents($class);
|
||||
if (!is_array($parents) || !in_array('EesyPHP\\Auth\\Backend', $parents)) {
|
||||
Log::warning(
|
||||
'Auth Init: Auth backend %s class (%s) do not derivate from \\EesyPHP\\Auth\\Backend '.
|
||||
'class, ignore it.',
|
||||
$backend, $class);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!call_user_func(array($class, 'init'))) {
|
||||
Log::warning(
|
||||
'Auth Init: fail to initialize auth backend %s, ignore it',
|
||||
$backend, $class);
|
||||
continue;
|
||||
}
|
||||
Log::trace('Auth backend %s initialized (class %s)', $backend, $class);
|
||||
self :: $backends[strtolower($backend)] = $class;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if authentication is enabled
|
||||
* @return bool
|
||||
*/
|
||||
public static function enabled() {
|
||||
if (!is_null(App::get('auth.enabled', null, 'bool')))
|
||||
return App::get('auth.enabled', false, 'bool');
|
||||
if (App::get('auth.methods', array(), 'array') && App::get('auth.backends', array(), 'array'))
|
||||
return true;
|
||||
Log :: trace('Authentication is disabled');
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a authentification method is enabled
|
||||
* @param string $method
|
||||
* @return bool
|
||||
*/
|
||||
public static function method_is_enabled($method) {
|
||||
return array_key_exists(strtolower($method), self :: $methods);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user by username
|
||||
* @param string $username
|
||||
* @param boolean $first Return only the first matched user (if authorized, optional, default: true)
|
||||
* @return \EesyPHP\Auth\User|array<\EesyPHP\Auth\User>|null|false The user object if found, null it not, false in case of error
|
||||
*/
|
||||
public static function get_user($username, $first=true) {
|
||||
if (!self :: $backends) {
|
||||
Log :: warning("No auth backend registered, can't retreive user");
|
||||
return false;
|
||||
}
|
||||
$users = array();
|
||||
foreach (self :: $backends as $backend) {
|
||||
$user = call_user_func(array($backend, 'get_user'), $username);
|
||||
if ($user) $users[] = $user;
|
||||
}
|
||||
if (!$users) return null;
|
||||
if (count($users) > 1 && !App::get('auth.allow_multiple_match', false, 'bool')) {
|
||||
Log :: error('Multiple user found for username "%s":\n%s', $username, vardump($users));
|
||||
return false;
|
||||
}
|
||||
return $first?$users[0]:$users;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search user by username and check its password
|
||||
* @param string $username The username
|
||||
* @param string $password The password to check
|
||||
* @return \EesyPHP\Auth\User|null|false
|
||||
*/
|
||||
public static function authenticate($username, $password) {
|
||||
$users = self :: get_user($username, false);
|
||||
if (!$users) return $users === false?false:null;
|
||||
|
||||
$auth_users = array();
|
||||
foreach ($users as $user) {
|
||||
if ($user->check_password($password))
|
||||
$auth_users[] = $user;
|
||||
}
|
||||
if (!$auth_users) return null;
|
||||
if (
|
||||
count($auth_users) > 1
|
||||
&& !App::get(
|
||||
'auth.allow_multiple_match_with_valid_password',
|
||||
App::get('auth.allow_multiple_match', false, 'bool'),
|
||||
'bool'
|
||||
)
|
||||
) {
|
||||
Log :: error(
|
||||
'Multiple user match for username "%s" and provided password:\n%s',
|
||||
$username, vardump($auth_users));
|
||||
return false;
|
||||
}
|
||||
return $auth_users[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Log user
|
||||
* @param bool|string $force Force user authentication: could specified desired method or true
|
||||
* to use the first one (optional, default: false)
|
||||
* @param null|string $with_method Specify with which method(s) login user (optional, default: all methods)
|
||||
* @return \EesyPHP\Auth\User|null|false
|
||||
*/
|
||||
public static function login($force=false, $with_method=null) {
|
||||
// Check if already logged in
|
||||
if (self :: $user)
|
||||
return self :: $user;
|
||||
|
||||
// Check if logged in session
|
||||
if (isset($_SESSION['user']) && isset($_SESSION['auth_method'])) {
|
||||
$user = unserialize($_SESSION['user']);
|
||||
if (is_a($user, '\\EesyPHP\\Auth\\User')) {
|
||||
self :: $user = $user;
|
||||
self :: $logged_method = (
|
||||
array_key_exists($_SESSION['auth_method'], self :: $methods)?
|
||||
$_SESSION['auth_method']:null
|
||||
);
|
||||
Log :: debug(
|
||||
'User %s authenticated from session (method %s and backend %s)',
|
||||
$user->username,
|
||||
self :: $logged_method?self :: $logged_method:'unknown',
|
||||
$user->backend);
|
||||
return $user;
|
||||
}
|
||||
Log::warning('Invalid user data in session, drop it');
|
||||
// Otherwise, drop user in session
|
||||
unset($_SESSION['user']);
|
||||
unset($_SESSION['auth_method']);
|
||||
}
|
||||
|
||||
if (!self :: $methods) {
|
||||
Log :: warning("No auth method registered, can't authenticate users");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise, log without enforcing by using registered methods
|
||||
foreach (self :: $methods as $method => $class) {
|
||||
if ($with_method && !in_array($method, array_map('strtolower', ensure_is_array($with_method))))
|
||||
continue;
|
||||
$user = call_user_func(array($class, 'login'));
|
||||
if ($user) {
|
||||
self :: set_user($user, $method);
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
|
||||
// If still not logged and force mode enable, force login using specified method (or the first one)
|
||||
if ($force) {
|
||||
$method = (
|
||||
is_string($force) && array_key_exists($force, self :: $methods)?
|
||||
$force:key(self :: $methods)
|
||||
);
|
||||
Log::debug('Force authentication using method %s', $method);
|
||||
$user = call_user_func(array(self :: $methods[$method], 'login'), true);
|
||||
if ($user) {
|
||||
self :: set_user($user, $method);
|
||||
return $user;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to set current authenticated user
|
||||
* @param \EesyPHP\Auth\User $user The current authenticated user object
|
||||
* @param string $method Method used to authenticate the user
|
||||
* @return void
|
||||
*/
|
||||
private static function set_user($user, $method) {
|
||||
Log :: debug(
|
||||
'User %s authenticated using method %s and backend %s',
|
||||
$user->username, $method, $user->backend);
|
||||
self :: $user = $user;
|
||||
self :: $logged_method = $method;
|
||||
$_SESSION['user'] = serialize($user);
|
||||
$_SESSION['auth_method'] = $method;
|
||||
Hook :: trigger('logged_in', array('method' => $method, 'user' => $user));
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout
|
||||
* @return void
|
||||
*/
|
||||
public static function logout() {
|
||||
$method = (
|
||||
self :: $logged_method?
|
||||
self :: $logged_method:
|
||||
(isset($_SESSION['auth_method'])?$_SESSION['auth_method']:null)
|
||||
);
|
||||
self :: $user = null;
|
||||
self :: $logged_method = null;
|
||||
if (isset($_SESSION['user']))
|
||||
unset($_SESSION['user']);
|
||||
if (isset($_SESSION['auth_method']))
|
||||
unset($_SESSION['auth_method']);
|
||||
if ($method)
|
||||
call_user_func(array(self :: $methods[$method], 'logout'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current authenticated user
|
||||
* @return \EesyPHP\Auth\User|null
|
||||
*/
|
||||
public static function user() {
|
||||
return self :: $user;
|
||||
}
|
||||
}
|
33
src/Auth/Backend.php
Normal file
33
src/Auth/Backend.php
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace EesyPHP\Auth;
|
||||
|
||||
class Backend {
|
||||
|
||||
/**
|
||||
* Initialize
|
||||
* @return boolean
|
||||
*/
|
||||
public static function init() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retreive a user by its username
|
||||
* @param string $username
|
||||
* @return \EesyPHP\Auth\User|null|false The user object if found, null it not, false in case of error
|
||||
*/
|
||||
public static function get_user($username) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a user password
|
||||
* @param \EesyPHP\Auth\User $user The user object
|
||||
* @param string $password The password to check
|
||||
* @return boolean
|
||||
*/
|
||||
public static function check_password($user, $password) {
|
||||
return false;
|
||||
}
|
||||
}
|
132
src/Auth/Cas.php
Normal file
132
src/Auth/Cas.php
Normal file
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
|
||||
namespace EesyPHP\Auth;
|
||||
|
||||
use EesyPHP\App;
|
||||
use EesyPHP\Auth;
|
||||
use EesyPHP\Log;
|
||||
use EesyPHP\Url;
|
||||
|
||||
use phpCAS;
|
||||
|
||||
class Cas extends Method {
|
||||
|
||||
/**
|
||||
* Fake authenticated user login
|
||||
* @var string|null
|
||||
*/
|
||||
private static $fake_authenticated_user = null;
|
||||
|
||||
/**
|
||||
* Initialize
|
||||
* @return boolean
|
||||
*/
|
||||
public static function init() {
|
||||
self :: $fake_authenticated_user = App :: get(
|
||||
'auth.cas.fake_authenticated_user', null, 'string');
|
||||
if (self :: $fake_authenticated_user) return true;
|
||||
|
||||
if (App::get('auth.cas.debug_log_file'))
|
||||
phpCAS::setDebug(App::get('auth.cas.debug_log_file'));
|
||||
|
||||
if (!App::get('auth.cas.host')) {
|
||||
Log :: error('CAS host not configured. Check your configuration!');
|
||||
return false;
|
||||
}
|
||||
|
||||
$cas_version = App :: get('auth.cas.version', '2.0', 'string');
|
||||
$supported_cas_versions = phpCAS::getSupportedProtocols();
|
||||
if (!array_key_exists($cas_version, $supported_cas_versions)) {
|
||||
Log :: error(
|
||||
'Unsupported CAS version (%s). Check your configuration!',
|
||||
$cas_version
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Init phpCAS client
|
||||
phpCAS::client(
|
||||
$cas_version,
|
||||
App :: get('auth.cas.host'),
|
||||
App :: get('auth.cas.port', 443, 'int'),
|
||||
App :: get('auth.cas.context', '/idp/cas', 'string'),
|
||||
Url :: get_absolute_url("/")
|
||||
);
|
||||
if (App :: get('auth.cas.ca_cert_certificate_path'))
|
||||
phpCAS::setCasServerCACert(App :: get('auth.cas.ca_cert_certificate_path'));
|
||||
else
|
||||
phpCAS::setNoCasServerValidation();
|
||||
Url :: add_url_handler(
|
||||
'#^login/cas_callback$#', array('EesyPHP\\Auth\\Cas', 'handle_cas_callback'), null, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute CAS callback URL
|
||||
* @return string
|
||||
*/
|
||||
private static function get_cas_callback_url() {
|
||||
return Url :: get_absolute_url(
|
||||
'login/cas_callback?next='.(
|
||||
isset($_REQUEST['next'])?
|
||||
$_REQUEST['next']:
|
||||
urlencode(Url :: get_current_url())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log user
|
||||
* @param bool $force Force user authentication
|
||||
* @return \EesyPHP\Auth\User|null
|
||||
*/
|
||||
public static function login($force=false) {
|
||||
if (!phpCAS :: isAuthenticated() && $force) {
|
||||
$_SESSION['cas_callback_url'] = self :: get_cas_callback_url();
|
||||
phpCAS :: setFixedServiceURL($_SESSION['cas_callback_url']);
|
||||
phpCAS :: forceAuthentication();
|
||||
}
|
||||
$user = (
|
||||
phpCAS :: isAuthenticated()?
|
||||
Auth :: get_user(phpCAS :: getUser()):
|
||||
null
|
||||
);
|
||||
if ($force && !$user)
|
||||
Log :: fatal('Fail to authenticate you');
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout
|
||||
* @return void
|
||||
*/
|
||||
public static function logout() {
|
||||
if (App :: get('auth.cas.logout', true, 'bool') && !self :: $fake_authenticated_user) {
|
||||
if (App :: get('auth.cas.logout_url')) {
|
||||
Url :: redirect(App :: get('auth.cas.logout_url'));
|
||||
exit();
|
||||
}
|
||||
phpCAS::logout();
|
||||
}
|
||||
else {
|
||||
session_unset();
|
||||
session_destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The CAS callback view
|
||||
* @param \EesyPHP\UrlRequest $request
|
||||
* @return void
|
||||
*/
|
||||
public static function handle_cas_callback($request) {
|
||||
if (isset($_SESSION['cas_callback_url'])) {
|
||||
phpCAS :: setFixedServiceURL($_SESSION['cas_callback_url']);
|
||||
unset($_SESSION['cas_callback_url']);
|
||||
}
|
||||
$user = Auth :: login(false, 'Cas');
|
||||
if ($user)
|
||||
Url :: redirect(isset($_REQUEST['next'])?urldecode($_REQUEST['next']):null);
|
||||
Log :: fatal('No CAS ticket or fail to authenticate you');
|
||||
}
|
||||
}
|
76
src/Auth/Form.php
Normal file
76
src/Auth/Form.php
Normal file
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
namespace EesyPHP\Auth;
|
||||
|
||||
use EesyPHP\App;
|
||||
use EesyPHP\Auth;
|
||||
use EesyPHP\Hook;
|
||||
use EesyPHP\Url;
|
||||
use EesyPHP\Tpl;
|
||||
|
||||
class Form extends Method {
|
||||
|
||||
/**
|
||||
* Initialize
|
||||
* @return boolean
|
||||
*/
|
||||
public static function init() {
|
||||
Url :: add_url_handler('#^login$#', array('EesyPHP\\Auth\\Form', 'handle_login'), null, false);
|
||||
Hook :: register('logged_in', array('\\EesyPHP\\Auth\\Form', 'logged_in_hook'));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log user
|
||||
* @param bool $force Force user authentication
|
||||
* @return \EesyPHP\Auth\User|null
|
||||
*/
|
||||
public static function login($force=false) {
|
||||
$user = null;
|
||||
if (isset($_REQUEST['username']) && isset($_REQUEST['password'])) {
|
||||
$user = Auth :: authenticate($_REQUEST['username'], $_REQUEST['password']);
|
||||
if (!$user) Tpl::add_error(_('Invalid username or password.'));
|
||||
}
|
||||
if ($force && !$user) {
|
||||
if (Url :: get_current_url() != 'login')
|
||||
Url :: redirect('login?next='.urlencode(Url :: get_current_url()));
|
||||
return null;
|
||||
}
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* The login form view
|
||||
* @param \EesyPHP\UrlRequest $request
|
||||
* @return void
|
||||
*/
|
||||
public static function handle_login($request) {
|
||||
$user = Auth :: login(false, 'Form');
|
||||
$display_other_methods = array();
|
||||
foreach (App::get('auth.login_form.display_other_methods', array(), 'array') as $method => $label)
|
||||
if (Auth::method_is_enabled($method))
|
||||
$display_other_methods[$method] = $label;
|
||||
if (
|
||||
!$user && isset($_REQUEST['method']) &&
|
||||
array_key_exists($_REQUEST['method'], $display_other_methods)
|
||||
) {
|
||||
$user = Auth :: login($_REQUEST['method'], $_REQUEST['method']);
|
||||
}
|
||||
if ($user)
|
||||
Url :: redirect(isset($_REQUEST['next'])?urldecode($_REQUEST['next']):null);
|
||||
else
|
||||
Tpl :: assign('next', (isset($_REQUEST['next'])?urldecode($_REQUEST['next']):''));
|
||||
Tpl :: assign('display_other_methods', $display_other_methods);
|
||||
Tpl :: display('login.tpl', 'Connection');
|
||||
}
|
||||
|
||||
/**
|
||||
* Logged in hook
|
||||
* @param \EesyPHP\HookEvent $event
|
||||
* @return void
|
||||
*/
|
||||
public static function logged_in_hook($event) {
|
||||
if ($event->method == 'Form' && isset($_REQUEST['next']))
|
||||
Url :: redirect(urldecode($_REQUEST['next']));
|
||||
}
|
||||
}
|
137
src/Auth/Http.php
Normal file
137
src/Auth/Http.php
Normal file
|
@ -0,0 +1,137 @@
|
|||
<?php
|
||||
|
||||
namespace EesyPHP\Auth;
|
||||
|
||||
use EesyPHP\App;
|
||||
use EesyPHP\Auth;
|
||||
use EesyPHP\I18n;
|
||||
use EesyPHP\Log;
|
||||
use EesyPHP\Tpl;
|
||||
use EesyPHP\Url;
|
||||
use function EesyPHP\vardump;
|
||||
|
||||
class Http extends Method {
|
||||
|
||||
/**
|
||||
* Method to retreive HTTP credentials
|
||||
* @var string
|
||||
*/
|
||||
private static $method;
|
||||
|
||||
/**
|
||||
* HTTP realm string (use to compute WWW-Authenticate HTTP header)
|
||||
* @var string
|
||||
*/
|
||||
private static $realm;
|
||||
|
||||
/**
|
||||
* Initialize
|
||||
* @return boolean
|
||||
*/
|
||||
public static function init() {
|
||||
self :: $method = App::get('auth.http.method', 'PHP_AUTH', 'string');
|
||||
self :: $realm = App::get(
|
||||
'auth.http.realm', _('Authentication required'), 'string');
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retreive HTTP authentication data
|
||||
* @return array|false array('username' => '[login]', 'password' => '[password]') or false
|
||||
*/
|
||||
private static function get_auth_data() {
|
||||
switch(self :: $method) {
|
||||
case 'AUTHORIZATION':
|
||||
Log :: debug("Auth HTTP: use AUTHORIZATION method");
|
||||
if (isset($_SERVER['HTTP_AUTHORIZATION']) && !empty($_SERVER['HTTP_AUTHORIZATION'])) {
|
||||
$auth_data = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
|
||||
if (is_array($auth_data) && count($auth_data) == 2) {
|
||||
return array(
|
||||
'username' => $auth_data[0],
|
||||
'password' => $auth_data[1],
|
||||
);
|
||||
}
|
||||
else
|
||||
Log :: error("Fail to parse HTTP_AUTHORIZATION environnement variable.");
|
||||
}
|
||||
break;
|
||||
case 'REMOTE_USER':
|
||||
Log :: debug("Auth HTTP : use REMOTE_USER method");
|
||||
if (isset($_SERVER['REMOTE_USER']) && !empty($_SERVER['REMOTE_USER'])) {
|
||||
return array(
|
||||
'username' => $_SERVER['REMOTE_USER'],
|
||||
'password' => false,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'PHP_AUTH':
|
||||
default:
|
||||
Log :: debug("Auth HTTP : use PHP_AUTH method");
|
||||
if (isset($_SERVER['PHP_AUTH_USER']) && !empty($_SERVER['PHP_AUTH_USER'])) {
|
||||
return array(
|
||||
'username' => $_SERVER['PHP_AUTH_USER'],
|
||||
'password' => $_SERVER['PHP_AUTH_PW'],
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
Log :: trace("HTTP::get_auth_data(): no auth data found\n".vardump($_SERVER));
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log user
|
||||
* @param bool $force Force user authentication
|
||||
* @return \EesyPHP\Auth\User|null
|
||||
*/
|
||||
public static function login($force=false) {
|
||||
$auth_data = self :: get_auth_data();
|
||||
if (!$auth_data) {
|
||||
if ($force) self :: force_login();
|
||||
return null;
|
||||
}
|
||||
|
||||
if (App :: get('auth.http.trust_without_password_challenge', false, 'bool'))
|
||||
$user = Auth :: get_user($auth_data['username']);
|
||||
else
|
||||
$user = Auth :: authenticate($auth_data['username'], $auth_data['password']);
|
||||
|
||||
if (!$user && $force)
|
||||
self :: force_login();
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force HTTP user authentification
|
||||
* @return void
|
||||
*/
|
||||
public static function force_login() {
|
||||
header('HTTP/1.1 401 Authorization Required');
|
||||
header(
|
||||
sprintf('WWW-Authenticate: Basic realm="%s"', addslashes(self :: $realm))
|
||||
);
|
||||
if (Tpl::initialized()) {
|
||||
Tpl :: display("must_login.tpl", I18n::_("Access denied"));
|
||||
}
|
||||
else {
|
||||
printf("<h1>%s</h1>", I18n::_("Access denied"));
|
||||
printf("<p>%s</p>", I18n::_("You must login to access this page."));
|
||||
printf(
|
||||
"<p><a href='%s'>%s</a></p>",
|
||||
Url :: public_root_url(),
|
||||
I18n::_("You must login to access this page.")
|
||||
);
|
||||
}
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout
|
||||
* @return void
|
||||
*/
|
||||
public static function logout() {
|
||||
self :: force_login();
|
||||
}
|
||||
|
||||
}
|
260
src/Auth/Ldap.php
Normal file
260
src/Auth/Ldap.php
Normal file
|
@ -0,0 +1,260 @@
|
|||
<?php
|
||||
|
||||
namespace EesyPHP\Auth;
|
||||
|
||||
use EesyPHP\App;
|
||||
use EesyPHP\Auth\User;
|
||||
use EesyPHP\Config;
|
||||
use EesyPHP\Log;
|
||||
use function EesyPHP\ensure_is_array;
|
||||
use function EesyPHP\cast;
|
||||
use function EesyPHP\vardump;
|
||||
|
||||
use PEAR;
|
||||
use Net_LDAP2;
|
||||
use Net_LDAP2_Filter;
|
||||
|
||||
class Ldap extends Backend {
|
||||
|
||||
/**
|
||||
* LDAP configuration as expected by Net_LDAP2
|
||||
* @var array
|
||||
*/
|
||||
private static $ldap_config;
|
||||
|
||||
/**
|
||||
* Net_LDAP2 connection (if connected)
|
||||
* @var Net_LDAP2|null
|
||||
*/
|
||||
private static $connection = null;
|
||||
|
||||
/**
|
||||
* Default LDAP user attributes configuration
|
||||
* @var array<string,array>
|
||||
*/
|
||||
private static $default_user_attributes = array(
|
||||
'uid' => array(
|
||||
'name' => 'login',
|
||||
'type' => 'string',
|
||||
'multivalued' => false,
|
||||
'default' => null,
|
||||
),
|
||||
'mail' => array(
|
||||
'type' => 'string',
|
||||
'multivalued' => false,
|
||||
'default' => null,
|
||||
),
|
||||
'cn' => array(
|
||||
'name' => 'name',
|
||||
'type' => 'string',
|
||||
'multivalued' => false,
|
||||
'default' => null,
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* Initialize
|
||||
* @return bool
|
||||
*/
|
||||
public static function init() {
|
||||
if (!class_exists('Net_LDAP2')) {
|
||||
$path = App::get('auth.ldap.netldap2_path', 'Net/LDAP2.php', 'string');
|
||||
if (!@include($path)) {
|
||||
Log::error('Fail to load Net_LDAP2 (%s)', $path);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
foreach(array('host', 'basedn') as $param) {
|
||||
if (!App::get("auth.ldap.$param")) {
|
||||
Log :: error('LDAP %s not configured. Check your configuration!', $param);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
self :: $ldap_config = array (
|
||||
'host' => implode(' ', App :: get('auth.ldap.host', array(), 'array')),
|
||||
'basedn' => App :: get('auth.ldap.basedn', null, 'string'),
|
||||
'binddn' => App :: get('auth.ldap.bind_dn', null, 'string'),
|
||||
'bindpw' => App :: get('auth.ldap.bind_password', null, 'string'),
|
||||
'starttls' => App :: get('starttls', false, 'bool'),
|
||||
);
|
||||
if ($port = App :: get('auth.ldap.port', null, 'int'))
|
||||
self :: $ldap_config['port'] = $port;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect on the LDAP directory
|
||||
* @return bool
|
||||
*/
|
||||
private static function connect() {
|
||||
if (is_a(self :: $connection, 'Net_LDAP2')) return true;
|
||||
Log :: debug(
|
||||
'Connect on LDAP host "%s" as %s (base DN="%s")',
|
||||
self :: $ldap_config['host'],
|
||||
isset(self :: $ldap_config['binddn'])?self :: $ldap_config['binddn']:"anonymous",
|
||||
self :: $ldap_config['basedn']
|
||||
);
|
||||
|
||||
// @phpstan-ignore-next-line
|
||||
self :: $connection = Net_LDAP2::connect(self :: $ldap_config);
|
||||
// @phpstan-ignore-next-line
|
||||
if (PEAR::isError(self :: $connection)) {
|
||||
Log :: error(
|
||||
'Could not connect to LDAP server (%s): %s',
|
||||
self :: $ldap_config['host'], self :: $connection->getMessage());
|
||||
self :: $connection = null;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a search in the LDAP directory
|
||||
* @param string $filter The LDAP filter string
|
||||
* @param array|null $attrs Expected attributes (optional, default: all existing attributes)
|
||||
* @param string|null $basedn The base DN of the search (optional, default: configured root base
|
||||
* DN of the LDAP connection)
|
||||
* @param string|array<string>|null $sorted If defined, sort return objects by specified attribute(s)
|
||||
* @param array|null $options Search options as expected by NetLDAP::search() (optional, default: null)
|
||||
*/
|
||||
public static function search($filter, $attrs=null, $basedn=null, $sorted=null, $options=null) {
|
||||
if (!self :: connect()) return false;
|
||||
$options = is_array($options)?$options:array();
|
||||
if (!is_null($attrs))
|
||||
$options['attributes'] = $attrs;
|
||||
|
||||
Log :: debug(
|
||||
'Run search in LDAP directory with filter "%s" on base DN "%s"',
|
||||
$filter, $basedn?$basedn:"unset");
|
||||
$search = self :: $connection -> search($basedn, $filter, $options);
|
||||
|
||||
// @phpstan-ignore-next-line
|
||||
if (PEAR::isError($search)) {
|
||||
Log :: error(
|
||||
'Error occured searching in LDAP with filter "%s" on base DN "%s": %s',
|
||||
$filter, $basedn?$basedn:"unset", $search->getMessage()
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
$entries = (
|
||||
$sorted?
|
||||
$search -> sorted(ensure_is_array($sorted)):
|
||||
$search -> entries()
|
||||
);
|
||||
|
||||
$result = array();
|
||||
foreach ($entries as $entry)
|
||||
$result[$entry->dn()] = $entry -> getValues();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast an LDAP value
|
||||
* @param mixed $value The raw LDAP value
|
||||
* @param string $type The expected type: see cast() for supported types, but boolean value will
|
||||
* be casted as LDAP boolean string.
|
||||
* @return mixed The casted value
|
||||
*/
|
||||
public static function cast($value, $type) {
|
||||
switch($type) {
|
||||
case 'bool':
|
||||
case 'boolean':
|
||||
return $value == 'TRUE';
|
||||
case 'array_of_bool':
|
||||
case 'array_of_boolean':
|
||||
$values = array();
|
||||
foreach(ensure_is_array($value) as $value)
|
||||
$values[] = $value == 'TRUE';
|
||||
return $values;
|
||||
default:
|
||||
return cast($value, $type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retreive LDAP attribute value(s) from LDAP entry
|
||||
* @param array<string,mixed> $entry The LDAP entry
|
||||
* @param string $attr The LDAP attribute name
|
||||
* @param bool $all_values Return all values or just the first one (optional, default: false)
|
||||
* @param mixed $default The default value to return if the LDAP attribute is undefined
|
||||
* (optional, default: an empty array if $all_values, null otherwise)
|
||||
* @param string|null $cast The expected type of value (optional, default: string)
|
||||
*/
|
||||
public static function get_attr($entry, $attr, $all_values=False, $default=null, $cast=null) {
|
||||
$values = self :: cast(
|
||||
isset($entry[$attr])?ensure_is_array($entry[$attr]):array(),
|
||||
"array_of_".($cast?$cast:'string')
|
||||
);
|
||||
if ($values)
|
||||
return $all_values?$values:$values[0];
|
||||
if ($all_values)
|
||||
return !is_null($default)?$default:array();
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retreive a user by its username
|
||||
* @param string $username
|
||||
* @return \EesyPHP\Auth\User|null|false The user object if found, null it not, false in case of error
|
||||
*/
|
||||
public static function get_user($username) {
|
||||
$attrs = App::get('auth.ldap.user_attributes', self :: $default_user_attributes, 'array');
|
||||
$users = self :: search(
|
||||
str_replace(
|
||||
'[username]', Net_LDAP2_Filter::escape($username),
|
||||
App::get('auth.ldap.user_filter_by_uid', 'uid=[username]', 'string')
|
||||
),
|
||||
array_keys($attrs),
|
||||
App::get('auth.ldap.user_basedn', null, 'string')
|
||||
);
|
||||
if (!is_array($users)) {
|
||||
Log::warning('An error occured looking for user "%s" in LDAP directory', $username);
|
||||
return false;
|
||||
}
|
||||
if (!$users) {
|
||||
Log::debug('User "%s" not found in LDAP directory', $username);
|
||||
return null;
|
||||
}
|
||||
if (count($users) > 1) {
|
||||
Log::warning(
|
||||
'More than on users found with username "%s": %s',
|
||||
$username, implode(' / ', array_keys($users))
|
||||
);
|
||||
}
|
||||
$dn = key($users);
|
||||
$info = array('dn' => $dn);
|
||||
foreach($attrs as $attr => $attr_config) {
|
||||
$info[Config::get("name", $attr, 'string', false, $attr_config)] = self :: get_attr(
|
||||
$users[$dn],
|
||||
$attr,
|
||||
Config::get("multivalued", false, 'bool', false, $attr_config),
|
||||
Config::get("default", null, null, false, $attr_config)
|
||||
);
|
||||
}
|
||||
Log::debug('User "%s" found in LDAP directory (%s):\n%s', $username, $dn, vardump($info));
|
||||
return new User($username, '\\EesyPHP\\Auth\\LDAP', $info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a user password
|
||||
* @param \EesyPHP\Auth\User $user The user object
|
||||
* @param string $password The password to check
|
||||
* @return boolean
|
||||
*/
|
||||
public static function check_password($user, $password) {
|
||||
$config = self :: $ldap_config;
|
||||
$config['binddn'] = (
|
||||
App::get('auth.ldap.bind_with_username', false, 'bool')?
|
||||
$user->username:
|
||||
$user->dn
|
||||
);
|
||||
$config['bindpw'] = $password;
|
||||
$result = Net_LDAP2::connect($config);
|
||||
// @phpstan-ignore-next-line
|
||||
return !PEAR::isError($result);
|
||||
}
|
||||
|
||||
}
|
34
src/Auth/Method.php
Normal file
34
src/Auth/Method.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace EesyPHP\Auth;
|
||||
|
||||
use EesyPHP\Log;
|
||||
|
||||
class Method {
|
||||
|
||||
/**
|
||||
* Initialize
|
||||
* @return boolean
|
||||
*/
|
||||
public static function init() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log user
|
||||
* @param bool $force Force user authentication
|
||||
* @return \EesyPHP\Auth\User|null
|
||||
*/
|
||||
public static function login($force=false) {
|
||||
Log :: fatal('login() is not implement for this authentication method.');
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout
|
||||
* @return void
|
||||
*/
|
||||
public static function logout() {
|
||||
return;
|
||||
}
|
||||
}
|
86
src/Auth/User.php
Normal file
86
src/Auth/User.php
Normal file
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
namespace EesyPHP\Auth;
|
||||
|
||||
use EesyPHP\Log;
|
||||
|
||||
class User {
|
||||
|
||||
/**
|
||||
* Username
|
||||
* @var string
|
||||
*/
|
||||
private $username;
|
||||
|
||||
/**
|
||||
* User backend class name
|
||||
* @var string
|
||||
*/
|
||||
private $backend;
|
||||
|
||||
/**
|
||||
* User info
|
||||
* @var array<string,mixed>
|
||||
*/
|
||||
private $info;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param string $username The username
|
||||
* @param string $backend The backend class name
|
||||
* @param array<string,mixed>|null $info User info (optional)
|
||||
*/
|
||||
public function __construct($username, $backend, $info=null) {
|
||||
$this -> username = $username;
|
||||
$this -> backend = $backend;
|
||||
$this -> info = is_array($info)?$info:array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method to get a dynamic property
|
||||
* @param string $key The property
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($key) {
|
||||
switch ($key) {
|
||||
case 'username':
|
||||
return $this -> username;
|
||||
case 'backend':
|
||||
return $this -> backend;
|
||||
default:
|
||||
if (array_key_exists($key, $this -> info))
|
||||
return $this -> info[$key];
|
||||
}
|
||||
Log::warning(
|
||||
'Ask for unknown user property %s:\n%s', $key, Log::get_debug_backtrace_context());
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method to check if a dynamic property is set
|
||||
* @param string $key The property
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($key) {
|
||||
switch ($key) {
|
||||
case 'username':
|
||||
case 'backend':
|
||||
return true;
|
||||
default:
|
||||
return array_key_exists($key, $this -> info);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check user password
|
||||
* @param string $password
|
||||
* @return bool
|
||||
*/
|
||||
public function check_password($password) {
|
||||
return call_user_func(
|
||||
array($this -> backend, 'check_password'),
|
||||
$this, $password
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -437,7 +437,7 @@ class I18n {
|
|||
// Extract messages from templates files using tsmarty2c.php
|
||||
$result = run_external_command(
|
||||
array(
|
||||
App :: root_directory_path()."/vendor/smarty-gettext/smarty-gettext/tsmarty2c.php",
|
||||
PHP_BINARY.' '.App :: root_directory_path()."/vendor/smarty-gettext/smarty-gettext/tsmarty2c.php",
|
||||
basename($templates_directory),
|
||||
),
|
||||
null, // Pass nothing on STDIN
|
||||
|
|
|
@ -132,7 +132,7 @@ class Log {
|
|||
* @return true
|
||||
*/
|
||||
public static function log($level, $message, ...$extra_args) {
|
||||
global $auth_user, $argv;
|
||||
global $argv;
|
||||
|
||||
if (!array_key_exists($level, self :: $levels)) $level = self :: $default_level;
|
||||
if (self :: $levels[$level] < self :: $levels[self :: $level]) return true;
|
||||
|
@ -162,8 +162,8 @@ class Log {
|
|||
$_SERVER['REQUEST_URI'],
|
||||
$_SERVER['REMOTE_ADDR'],
|
||||
);
|
||||
if (isset($auth_user))
|
||||
$msg[] = ($auth_user['username']?$auth_user['username']:'anonymous');
|
||||
if (Auth::enabled())
|
||||
$msg[] = (Auth::user()?Auth::user()->username:'anonymous');
|
||||
$msg[] = $level;
|
||||
$msg[] = $message;
|
||||
$msg = implode(' - ', $msg)."\n";
|
||||
|
|
|
@ -47,11 +47,8 @@ class SentryIntegration {
|
|||
]);
|
||||
|
||||
\Sentry\configureScope(function (\Sentry\State\Scope $scope): void {
|
||||
global $auth_user;
|
||||
$scope->setUser([
|
||||
'id' => isset($auth_user) && $auth_user?$auth_user['uid']:null,
|
||||
'email' => isset($auth_user) && $auth_user?$auth_user['mail']:null,
|
||||
'segment' => isset($auth_user) && $auth_user?$auth_user['type']:null,
|
||||
'username' => Auth::user()?Auth::user()->username:null,
|
||||
'ip_address' => php_sapi_name()=='cli'?null:$_SERVER['REMOTE_ADDR'],
|
||||
]);
|
||||
});
|
||||
|
|
|
@ -356,7 +356,6 @@ class Tpl {
|
|||
* @return void
|
||||
*/
|
||||
protected static function define_common_variables($pagetitle=null) {
|
||||
global $auth_user;
|
||||
self :: assign('public_root_url', Url :: public_root_url());
|
||||
self :: assign('pagetitle', $pagetitle);
|
||||
self :: assign('main_pagetitle', App::get('main_pagetitle', null, 'string'));
|
||||
|
@ -379,8 +378,8 @@ class Tpl {
|
|||
self :: assign('TEXT_DOMAIN', I18n :: TEXT_DOMAIN);
|
||||
|
||||
// Authenticated user info
|
||||
if (isset($auth_user))
|
||||
self :: assign('auth_user', $auth_user);
|
||||
if (Auth::user())
|
||||
self :: assign('auth_user', Auth::user());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
42
src/Url.php
42
src/Url.php
|
@ -6,6 +6,12 @@ use Exception;
|
|||
|
||||
class Url {
|
||||
|
||||
/**
|
||||
* Current request
|
||||
* @var UrlRequest|null
|
||||
*/
|
||||
public static $request = null;
|
||||
|
||||
/**
|
||||
* Configured URL patterns :
|
||||
*
|
||||
|
@ -77,8 +83,8 @@ class Url {
|
|||
* @param array|null $additional_info Array of information to pass to the URL handler
|
||||
* @param boolean $authenticated Permit to define if this URL is accessible only for
|
||||
* authenticated users (optional, default: true if the
|
||||
* special force_authentication function is defined,
|
||||
* false otherwise)
|
||||
* EesyPHP Authentication feature is enabled, false
|
||||
* otherwise)
|
||||
* @param boolean $overwrite Allow overwrite if a command already exists with the
|
||||
* same name (optional, default: false)
|
||||
* @param boolean $api_mode Enable API mode (optional, default: false)
|
||||
|
@ -88,12 +94,6 @@ class Url {
|
|||
public static function add_url_handler($pattern, $handler=null, $additional_info=null,
|
||||
$authenticated=null, $overwrite=true, $api_mode=false,
|
||||
$http_methods=null) {
|
||||
$authenticated = (
|
||||
is_null($authenticated)?
|
||||
function_exists('force_authentication'):
|
||||
(bool)$authenticated
|
||||
);
|
||||
|
||||
// Check HTTP methods parameter
|
||||
if (is_null($http_methods))
|
||||
$http_methods = array('GET', 'POST');
|
||||
|
@ -422,8 +422,7 @@ class Url {
|
|||
* Handle the current requested URL
|
||||
*
|
||||
* Note: if the route required that user is authenticated, this method will
|
||||
* invoke the force_authentication() special function (or trigger a fatal error
|
||||
* if it's not defined).
|
||||
* invoke Auth::login() in force mode (or trigger a fatal error if fail).
|
||||
*
|
||||
* @param string|null $default_url The default URL if current one does not
|
||||
* match with any configured pattern.
|
||||
|
@ -433,34 +432,31 @@ class Url {
|
|||
public static function handle_request($default_url=null) {
|
||||
$sentry_span = new SentrySpan('http.handle_request', 'Handle the HTTP request');
|
||||
|
||||
$request = self :: get_request($default_url);
|
||||
self :: $request = self :: get_request($default_url);
|
||||
|
||||
if (!is_callable($request -> handler)) {
|
||||
if (!is_callable(self :: $request -> handler)) {
|
||||
Log :: error(
|
||||
"URL handler function %s does not exists !",
|
||||
format_callable($request -> handler));
|
||||
format_callable(self :: $request -> handler));
|
||||
Log :: fatal(I18n::_("This request cannot be processed."));
|
||||
}
|
||||
|
||||
if ($request -> api_mode)
|
||||
if (self :: $request -> api_mode)
|
||||
self :: $_api_mode = true;
|
||||
if (Tpl :: initialized())
|
||||
Tpl :: assign('request', $request);
|
||||
Tpl :: assign('request', self :: $request );
|
||||
|
||||
// Check authentication (if need)
|
||||
if($request -> authenticated)
|
||||
if (function_exists('force_authentication'))
|
||||
force_authentication();
|
||||
else
|
||||
Log :: fatal(I18n::_("Authentication required but force_authentication function is not defined."));
|
||||
if(self :: $request -> authenticated && !Auth::login(true))
|
||||
Log :: fatal(I18n::_("Authentication required but fail to authenticate you."));
|
||||
|
||||
try {
|
||||
call_user_func($request -> handler, $request);
|
||||
call_user_func(self :: $request -> handler, self :: $request );
|
||||
}
|
||||
catch (Exception $e) {
|
||||
Log :: exception(
|
||||
$e, "An exception occured running URL handler function %s()",
|
||||
format_callable($request -> handler));
|
||||
$e, "An exception occured running URL handler %s",
|
||||
format_callable(self :: $request -> handler));
|
||||
Log :: fatal(I18n::_("This request could not be processed correctly."));
|
||||
}
|
||||
$sentry_span->finish();
|
||||
|
|
|
@ -54,7 +54,7 @@ class UrlRequest {
|
|||
$this -> handler = $handler_info['handler'];
|
||||
$this -> authenticated = (
|
||||
isset($handler_info['authenticated'])?
|
||||
boolval($handler_info['authenticated']):true);
|
||||
$handler_info['authenticated']:null);
|
||||
$this -> api_mode = (
|
||||
isset($handler_info['api_mode'])?
|
||||
boolval($handler_info['api_mode']):false);
|
||||
|
@ -78,7 +78,11 @@ class UrlRequest {
|
|||
if ($key == 'handler')
|
||||
return $this -> handler;
|
||||
if ($key == 'authenticated')
|
||||
return $this -> authenticated;
|
||||
return (
|
||||
is_null($this -> authenticated)?
|
||||
Auth::enabled():
|
||||
(bool)$this -> authenticated
|
||||
);
|
||||
if ($key == 'api_mode')
|
||||
return $this -> api_mode;
|
||||
if ($key == 'referer')
|
||||
|
|
|
@ -99,6 +99,13 @@ function ensure_is_array($value) {
|
|||
* @return mixed The cast value
|
||||
**/
|
||||
function cast($value, $type, $split=false) {
|
||||
if (strpos($type, 'array_of_') === 0) {
|
||||
$type = substr($type, 9);
|
||||
$values = array();
|
||||
foreach(ensure_is_array($value) as $key => $value)
|
||||
$values[$key] = cast($value, $type);
|
||||
return $values;
|
||||
}
|
||||
switch($type) {
|
||||
case 'bool':
|
||||
case 'boolean':
|
||||
|
|
|
@ -53,11 +53,11 @@
|
|||
<ul class="navbar-nav ml-md-auto">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-item nav-link dropdown-toggle mr-md-2" href="#" id="bd-versions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="fa fa-user" aria-hidden="true"></i> {$auth_user.name|escape:"htmlall"} <span class="caret"></span>
|
||||
<i class="fa fa-user" aria-hidden="true"></i> {$auth_user->name|escape:"htmlall"} <span class="caret"></span>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-right">
|
||||
{block name="navbar-user-menu"}{/block}
|
||||
<a class="dropdown-item" href="?logout=1"><i class="fas fa-sign-out-alt"></i> Déconnexion</a>
|
||||
<a class="dropdown-item" href="logout"><i class="fas fa-sign-out-alt"></i> {t domain=$CORE_TEXT_DOMAIN}Logout{/t}</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
22
templates/login.tpl
Normal file
22
templates/login.tpl
Normal file
|
@ -0,0 +1,22 @@
|
|||
{extends file='Tpl:empty.tpl'}
|
||||
{block name="pagetitle"}<h2 class="center"><i class="fas fa-sign-in-alt"></i> {t domain=$CORE_TEXT_DOMAIN}Connection{/t}</h2>{/block}
|
||||
{block name="content"}
|
||||
<form action="login" method="POST">
|
||||
<input type="hidden" name="next" value="{$next|escape:"quotes"}"/>
|
||||
<div class="form-group">
|
||||
<label for="username">{t domain=$CORE_TEXT_DOMAIN}Username{/t}</label>
|
||||
<input type="text" class="form-control" name="username" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password">{t domain=$CORE_TEXT_DOMAIN}Password{/t}</label>
|
||||
<input type="password" class="form-control" name="password">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">{t domain=$CORE_TEXT_DOMAIN}Submit{/t}</button>
|
||||
{foreach $display_other_methods as $method => $name}
|
||||
<a class='btn btn-secondary' href='login?method={$method}&next={$next|escape:"url"}'>{$name}</a>
|
||||
{/foreach}
|
||||
</form>
|
||||
{/block}
|
||||
{*
|
||||
# vim: autoindent expandtab tabstop=2 shiftwidth=2 softtabstop=2
|
||||
*}
|
11
templates/logout.tpl
Normal file
11
templates/logout.tpl
Normal file
|
@ -0,0 +1,11 @@
|
|||
{extends file='Tpl:empty.tpl'}
|
||||
{block name="pagetitle"}{/block}
|
||||
{block name="content"}
|
||||
<div class="jumbotron">
|
||||
<h1 class="display-4">{t domain=$CORE_TEXT_DOMAIN}Disconnected{/t}</h1>
|
||||
<p class="lead">{t escape=off domain=$CORE_TEXT_DOMAIN}You are now disconnected.{/t}</p>
|
||||
</div>
|
||||
{/block}
|
||||
{*
|
||||
# vim: autoindent expandtab tabstop=2 shiftwidth=2 softtabstop=2
|
||||
*}
|
11
templates/must_login.tpl
Normal file
11
templates/must_login.tpl
Normal file
|
@ -0,0 +1,11 @@
|
|||
{extends file='Tpl:empty.tpl'}
|
||||
{block name="pagetitle"}{/block}
|
||||
{block name="content"}
|
||||
<div class="jumbotron">
|
||||
<h1 class="display-4">{t domain=$CORE_TEXT_DOMAIN}Access denied{/t}</h1>
|
||||
<p class="lead">{t escape=off domain=$CORE_TEXT_DOMAIN}You must login to access this page.{/t}</p>
|
||||
</div>
|
||||
{/block}
|
||||
{*
|
||||
# vim: autoindent expandtab tabstop=2 shiftwidth=2 softtabstop=2
|
||||
*}
|
Loading…
Reference in a new issue