Add authentication support
This commit is contained in:
parent
16659cdaf6
commit
610cdb0f7c
28 changed files with 1515 additions and 119 deletions
|
@ -27,7 +27,8 @@
|
||||||
"ext-pdo": "^7.3",
|
"ext-pdo": "^7.3",
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"ext-yaml": "^2.0",
|
"ext-yaml": "^2.0",
|
||||||
"league/mime-type-detection": "^1.11"
|
"league/mime-type-detection": "^1.11",
|
||||||
|
"apereo/phpcas": "^1.6"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpstan/phpstan": "^1.9"
|
"phpstan/phpstan": "^1.9"
|
||||||
|
|
|
@ -134,6 +134,140 @@ db:
|
||||||
#datetime_format: '%Y-%m-%d %H:%M:%S' # Exemple : 2018-10-12 18:06:59
|
#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
|
# Email configuration
|
||||||
#
|
#
|
||||||
|
|
Binary file not shown.
|
@ -1,7 +1,7 @@
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: \n"
|
"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"
|
"PO-Revision-Date: \n"
|
||||||
"Last-Translator: Benjamin Renard <brenard@zionetrix.net>\n"
|
"Last-Translator: Benjamin Renard <brenard@zionetrix.net>\n"
|
||||||
"Language-Team: \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."
|
msgid "Unable to connect to the database."
|
||||||
msgstr "Impossible de se connecter à la base de données."
|
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
|
#: Email.php:141
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "</hr><p><small>Mail initialy intended for %s.</small></p>"
|
msgid "</hr><p><small>Mail initialy intended for %s.</small></p>"
|
||||||
|
@ -102,35 +118,27 @@ msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
"%s: %s"
|
"%s: %s"
|
||||||
|
|
||||||
#: Tpl.php:355
|
#: Tpl.php:394
|
||||||
msgid "No template specified."
|
msgid "No template specified."
|
||||||
msgstr "Aucun template spécifié."
|
msgstr "Aucun template spécifié."
|
||||||
|
|
||||||
#: Tpl.php:386
|
#: Tpl.php:425
|
||||||
msgid "An error occurred while displaying this page."
|
msgid "An error occurred while displaying this page."
|
||||||
msgstr "Une erreur est survenue en affichant cette page."
|
msgstr "Une erreur est survenue en affichant cette page."
|
||||||
|
|
||||||
#: Url.php:141
|
#: Url.php:172
|
||||||
msgid "Bad request"
|
msgid "Bad request"
|
||||||
msgstr "Mauvaise requête"
|
msgstr "Mauvaise requête"
|
||||||
|
|
||||||
#: Url.php:142
|
#: Url.php:173
|
||||||
msgid "Invalid request."
|
msgid "Invalid request."
|
||||||
msgstr "Requête invalide."
|
msgstr "Requête invalide."
|
||||||
|
|
||||||
#: Url.php:145
|
#: Url.php:177
|
||||||
msgid "Authentication required"
|
|
||||||
msgstr "Authentification requise"
|
|
||||||
|
|
||||||
#: Url.php:146
|
|
||||||
msgid "You have to be authenticated to access to this page."
|
msgid "You have to be authenticated to access to this page."
|
||||||
msgstr "Vous devez être authentifié pour accéder à cette page."
|
msgstr "Vous devez être authentifié pour accéder à cette page."
|
||||||
|
|
||||||
#: Url.php:149
|
#: Url.php:181
|
||||||
msgid "Access denied"
|
|
||||||
msgstr "Accès interdit"
|
|
||||||
|
|
||||||
#: Url.php:150
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"You do not have access to this application. If you think this is an error, "
|
"You do not have access to this application. If you think this is an error, "
|
||||||
"please contact support."
|
"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 "
|
"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."
|
"erreur, merci de prendre contact avec le support."
|
||||||
|
|
||||||
#: Url.php:153
|
#: Url.php:184
|
||||||
msgid "Whoops ! Page not found"
|
msgid "Whoops ! Page not found"
|
||||||
msgstr "Oups ! Page introuvable"
|
msgstr "Oups ! Page introuvable"
|
||||||
|
|
||||||
#: Url.php:154
|
#: Url.php:185
|
||||||
msgid "The requested page can not be found."
|
msgid "The requested page can not be found."
|
||||||
msgstr "La page demandée est introuvable."
|
msgstr "La page demandée est introuvable."
|
||||||
|
|
||||||
#: Url.php:162
|
#: Url.php:193
|
||||||
msgid "Error"
|
msgid "Error"
|
||||||
msgstr "Erreur"
|
msgstr "Erreur"
|
||||||
|
|
||||||
#: Url.php:163
|
#: Url.php:194
|
||||||
msgid "An unknown error occurred. If problem persist, please contact support."
|
msgid "An unknown error occurred. If problem persist, please contact support."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Une erreur inconnue est survenue. Si le problème persiste, merci de prendre "
|
"Une erreur inconnue est survenue. Si le problème persiste, merci de prendre "
|
||||||
"contact avec le support."
|
"contact avec le support."
|
||||||
|
|
||||||
#: Url.php:226
|
#: Url.php:257
|
||||||
msgid ""
|
msgid ""
|
||||||
"Unable to determine the requested page. If the problem persists, please "
|
"Unable to determine the requested page. If the problem persists, please "
|
||||||
"contact support."
|
"contact support."
|
||||||
|
@ -164,7 +172,7 @@ msgstr ""
|
||||||
"Impossible de déterminer la page demandée. Si le problème persiste, merci de "
|
"Impossible de déterminer la page demandée. Si le problème persiste, merci de "
|
||||||
"prendre contact avec le support."
|
"prendre contact avec le support."
|
||||||
|
|
||||||
#: Url.php:376
|
#: Url.php:411
|
||||||
msgid ""
|
msgid ""
|
||||||
"Unable to determine the requested page (loop detected). If the problem "
|
"Unable to determine the requested page (loop detected). If the problem "
|
||||||
"persists, please contact support."
|
"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 "
|
"Impossible de déterminer la page demandée (boucle détectée). Si le problème "
|
||||||
"persiste, merci de prendre contact avec le support."
|
"persiste, merci de prendre contact avec le support."
|
||||||
|
|
||||||
#: Url.php:407
|
#: Url.php:441
|
||||||
msgid "This request cannot be processed."
|
msgid "This request cannot be processed."
|
||||||
msgstr "Cette requête ne peut être traitée."
|
msgstr "Cette requête ne peut être traitée."
|
||||||
|
|
||||||
#: Url.php:420
|
#: Url.php:451
|
||||||
msgid ""
|
msgid "Authentication required but fail to authenticate you."
|
||||||
"Authentication required but force_authentication function is not defined."
|
msgstr "Authentification requise mais impossible pour vous authentifier."
|
||||||
msgstr ""
|
|
||||||
"Authentification requise mais la fonction force_authentication n'est pas "
|
|
||||||
"définie."
|
|
||||||
|
|
||||||
#: Url.php:429
|
#: Url.php:460
|
||||||
msgid "This request could not be processed correctly."
|
msgid "This request could not be processed correctly."
|
||||||
msgstr "Cette requête n'a put être traitée correctement."
|
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 !"
|
msgid "Hello world !"
|
||||||
msgstr "Bonjour tout le monde !"
|
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)."
|
msgid "%s JS catalog writed (%s)."
|
||||||
msgstr "Catalogue JS %s créé (%s)."
|
msgstr "Catalogue JS %s créé (%s)."
|
||||||
|
|
||||||
#: App.php:122
|
#: App.php:126
|
||||||
msgid "Hello world!"
|
msgid "Hello world!"
|
||||||
msgstr "Salut tout le monde !"
|
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:4 static/js/myconfirm.js:171
|
||||||
#: static/js/myconfirm.js:200
|
#: static/js/myconfirm.js:200
|
||||||
msgid "Confirmation"
|
msgid "Confirmation"
|
||||||
|
@ -460,3 +473,29 @@ msgstr ""
|
||||||
"framework EesyPHP. Configurez votre propre dossier de templates et créer le "
|
"framework EesyPHP. Configurez votre propre dossier de templates et créer le "
|
||||||
"fichier <em>homepage.tpl</em> pour l'écraser. Vous pouvez également écraser "
|
"fichier <em>homepage.tpl</em> pour l'écraser. Vous pouvez également écraser "
|
||||||
"le gestionnaire de l'URL racine de l'application web."
|
"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 ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"POT-Creation-Date: 2023-02-14 01:17+0100\n"
|
"POT-Creation-Date: 2023-02-25 04:54+0100\n"
|
||||||
"PO-Revision-Date: 2023-02-14 01:17+0100\n"
|
"PO-Revision-Date: 2023-02-25 04:54+0100\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=utf-8\n"
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
|
@ -1,7 +1,7 @@
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"POT-Creation-Date: 2023-02-14 01:17+0100\n"
|
"POT-Creation-Date: 2023-02-25 04:54+0100\n"
|
||||||
"PO-Revision-Date: 2023-02-14 01:17+0100\n"
|
"PO-Revision-Date: 2023-02-25 04:54+0100\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
@ -61,6 +61,22 @@ msgstr ""
|
||||||
msgid "Unable to connect to the database."
|
msgid "Unable to connect to the database."
|
||||||
msgstr ""
|
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
|
#: Email.php:141
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "</hr><p><small>Mail initialy intended for %s.</small></p>"
|
msgid "</hr><p><small>Mail initialy intended for %s.</small></p>"
|
||||||
|
@ -87,82 +103,73 @@ msgid ""
|
||||||
"%s: %s"
|
"%s: %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Tpl.php:355
|
#: Tpl.php:394
|
||||||
msgid "No template specified."
|
msgid "No template specified."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Tpl.php:386
|
#: Tpl.php:425
|
||||||
msgid "An error occurred while displaying this page."
|
msgid "An error occurred while displaying this page."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:141
|
#: Url.php:172
|
||||||
msgid "Bad request"
|
msgid "Bad request"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:142
|
#: Url.php:173
|
||||||
msgid "Invalid request."
|
msgid "Invalid request."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:145
|
#: Url.php:177
|
||||||
msgid "Authentication required"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: Url.php:146
|
|
||||||
msgid "You have to be authenticated to access to this page."
|
msgid "You have to be authenticated to access to this page."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:149
|
#: Url.php:181
|
||||||
msgid "Access denied"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: Url.php:150
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"You do not have access to this application. If you think this is an error, "
|
"You do not have access to this application. If you think this is an error, "
|
||||||
"please contact support."
|
"please contact support."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:153
|
#: Url.php:184
|
||||||
msgid "Whoops ! Page not found"
|
msgid "Whoops ! Page not found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:154
|
#: Url.php:185
|
||||||
msgid "The requested page can not be found."
|
msgid "The requested page can not be found."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:162
|
#: Url.php:193
|
||||||
msgid "Error"
|
msgid "Error"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:163
|
#: Url.php:194
|
||||||
msgid "An unknown error occurred. If problem persist, please contact support."
|
msgid "An unknown error occurred. If problem persist, please contact support."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:226
|
#: Url.php:257
|
||||||
msgid ""
|
msgid ""
|
||||||
"Unable to determine the requested page. If the problem persists, please "
|
"Unable to determine the requested page. If the problem persists, please "
|
||||||
"contact support."
|
"contact support."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:376
|
#: Url.php:411
|
||||||
msgid ""
|
msgid ""
|
||||||
"Unable to determine the requested page (loop detected). If the problem "
|
"Unable to determine the requested page (loop detected). If the problem "
|
||||||
"persists, please contact support."
|
"persists, please contact support."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:407
|
#: Url.php:441
|
||||||
msgid "This request cannot be processed."
|
msgid "This request cannot be processed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:420
|
#: Url.php:451
|
||||||
msgid ""
|
msgid "Authentication required but fail to authenticate you."
|
||||||
"Authentication required but force_authentication function is not defined."
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:429
|
#: Url.php:460
|
||||||
msgid "This request could not be processed correctly."
|
msgid "This request could not be processed correctly."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: I18n.php:122 App.php:120
|
#: I18n.php:122 App.php:124
|
||||||
msgid "Hello world !"
|
msgid "Hello world !"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -321,10 +328,18 @@ msgstr ""
|
||||||
msgid "%s JS catalog writed (%s)."
|
msgid "%s JS catalog writed (%s)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: App.php:122
|
#: App.php:126
|
||||||
msgid "Hello world!"
|
msgid "Hello world!"
|
||||||
msgstr ""
|
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:4 static/js/myconfirm.js:171
|
||||||
#: static/js/myconfirm.js:200
|
#: static/js/myconfirm.js:200
|
||||||
msgid "Confirmation"
|
msgid "Confirmation"
|
||||||
|
@ -395,3 +410,23 @@ msgid ""
|
||||||
"it. You could also overwrite the URL handler for the root of the web "
|
"it. You could also overwrite the URL handler for the root of the web "
|
||||||
"application."
|
"application."
|
||||||
msgstr ""
|
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."
|
msgid "Unable to connect to the database."
|
||||||
msgstr ""
|
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
|
#: Email.php:141
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "</hr><p><small>Mail initialy intended for %s.</small></p>"
|
msgid "</hr><p><small>Mail initialy intended for %s.</small></p>"
|
||||||
|
@ -79,82 +95,73 @@ msgid ""
|
||||||
"%s: %s"
|
"%s: %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Tpl.php:355
|
#: Tpl.php:394
|
||||||
msgid "No template specified."
|
msgid "No template specified."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Tpl.php:386
|
#: Tpl.php:425
|
||||||
msgid "An error occurred while displaying this page."
|
msgid "An error occurred while displaying this page."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:141
|
#: Url.php:172
|
||||||
msgid "Bad request"
|
msgid "Bad request"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:142
|
#: Url.php:173
|
||||||
msgid "Invalid request."
|
msgid "Invalid request."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:145
|
#: Url.php:177
|
||||||
msgid "Authentication required"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: Url.php:146
|
|
||||||
msgid "You have to be authenticated to access to this page."
|
msgid "You have to be authenticated to access to this page."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:149
|
#: Url.php:181
|
||||||
msgid "Access denied"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: Url.php:150
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"You do not have access to this application. If you think this is an error, "
|
"You do not have access to this application. If you think this is an error, "
|
||||||
"please contact support."
|
"please contact support."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:153
|
#: Url.php:184
|
||||||
msgid "Whoops ! Page not found"
|
msgid "Whoops ! Page not found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:154
|
#: Url.php:185
|
||||||
msgid "The requested page can not be found."
|
msgid "The requested page can not be found."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:162
|
#: Url.php:193
|
||||||
msgid "Error"
|
msgid "Error"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:163
|
#: Url.php:194
|
||||||
msgid "An unknown error occurred. If problem persist, please contact support."
|
msgid "An unknown error occurred. If problem persist, please contact support."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:226
|
#: Url.php:257
|
||||||
msgid ""
|
msgid ""
|
||||||
"Unable to determine the requested page. If the problem persists, please "
|
"Unable to determine the requested page. If the problem persists, please "
|
||||||
"contact support."
|
"contact support."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:376
|
#: Url.php:411
|
||||||
msgid ""
|
msgid ""
|
||||||
"Unable to determine the requested page (loop detected). If the problem "
|
"Unable to determine the requested page (loop detected). If the problem "
|
||||||
"persists, please contact support."
|
"persists, please contact support."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:407
|
#: Url.php:441
|
||||||
msgid "This request cannot be processed."
|
msgid "This request cannot be processed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:420
|
#: Url.php:451
|
||||||
msgid ""
|
msgid "Authentication required but fail to authenticate you."
|
||||||
"Authentication required but force_authentication function is not defined."
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: Url.php:429
|
#: Url.php:460
|
||||||
msgid "This request could not be processed correctly."
|
msgid "This request could not be processed correctly."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: I18n.php:122 App.php:120
|
#: I18n.php:122 App.php:124
|
||||||
msgid "Hello world !"
|
msgid "Hello world !"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -313,6 +320,14 @@ msgstr ""
|
||||||
msgid "%s JS catalog writed (%s)."
|
msgid "%s JS catalog writed (%s)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: App.php:122
|
#: App.php:126
|
||||||
msgid "Hello world!"
|
msgid "Hello world!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: App.php:137
|
||||||
|
msgid "Disconnected"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: App.php:139
|
||||||
|
msgid "You are now disconnected."
|
||||||
|
msgstr ""
|
||||||
|
|
|
@ -19,6 +19,14 @@ msgstr ""
|
||||||
msgid "Back"
|
msgid "Back"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/logout.tpl:5
|
||||||
|
msgid "Disconnected"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/logout.tpl:6
|
||||||
|
msgid "You are now disconnected."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: templates/homepage.tpl:5
|
#: templates/homepage.tpl:5
|
||||||
msgid "Hello, world!"
|
msgid "Hello, world!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -30,3 +38,31 @@ msgid ""
|
||||||
"it. You could also overwrite the URL handler for the root of the web "
|
"it. You could also overwrite the URL handler for the root of the web "
|
||||||
"application."
|
"application."
|
||||||
msgstr ""
|
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/includes/config.local.php
|
||||||
- example/data/tmp/templates_c
|
- example/data/tmp/templates_c
|
||||||
universalObjectCratesClasses:
|
universalObjectCratesClasses:
|
||||||
|
- EesyPHP\HookEvent
|
||||||
- EesyPHP\UrlRequest
|
- EesyPHP\UrlRequest
|
||||||
|
- EesyPHP\Auth\User
|
||||||
ignoreErrors:
|
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\\.#"
|
message: "#Instantiated class Mail_mime not found\\.#"
|
||||||
path: src/Email.php
|
path: src/Email.php
|
||||||
|
|
17
src/App.php
17
src/App.php
|
@ -64,6 +64,10 @@ class App {
|
||||||
Url::init();
|
Url::init();
|
||||||
Url :: add_url_handler('#^$#', array('EesyPHP\\App', 'handle_homepage'));
|
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'))
|
if (self :: get('mail.enabled', true, 'bool'))
|
||||||
Email :: init();
|
Email :: init();
|
||||||
if (self :: get('i18n.enabled', true, 'bool'))
|
if (self :: get('i18n.enabled', true, 'bool'))
|
||||||
|
@ -122,4 +126,17 @@ class App {
|
||||||
echo "<h1>".I18n::_("Hello world!")."</h1>";
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -132,7 +132,7 @@ class Log {
|
||||||
* @return true
|
* @return true
|
||||||
*/
|
*/
|
||||||
public static function log($level, $message, ...$extra_args) {
|
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 (!array_key_exists($level, self :: $levels)) $level = self :: $default_level;
|
||||||
if (self :: $levels[$level] < self :: $levels[self :: $level]) return true;
|
if (self :: $levels[$level] < self :: $levels[self :: $level]) return true;
|
||||||
|
@ -162,8 +162,8 @@ class Log {
|
||||||
$_SERVER['REQUEST_URI'],
|
$_SERVER['REQUEST_URI'],
|
||||||
$_SERVER['REMOTE_ADDR'],
|
$_SERVER['REMOTE_ADDR'],
|
||||||
);
|
);
|
||||||
if (isset($auth_user))
|
if (Auth::enabled())
|
||||||
$msg[] = ($auth_user['username']?$auth_user['username']:'anonymous');
|
$msg[] = (Auth::user()?Auth::user()->username:'anonymous');
|
||||||
$msg[] = $level;
|
$msg[] = $level;
|
||||||
$msg[] = $message;
|
$msg[] = $message;
|
||||||
$msg = implode(' - ', $msg)."\n";
|
$msg = implode(' - ', $msg)."\n";
|
||||||
|
|
|
@ -47,11 +47,8 @@ class SentryIntegration {
|
||||||
]);
|
]);
|
||||||
|
|
||||||
\Sentry\configureScope(function (\Sentry\State\Scope $scope): void {
|
\Sentry\configureScope(function (\Sentry\State\Scope $scope): void {
|
||||||
global $auth_user;
|
|
||||||
$scope->setUser([
|
$scope->setUser([
|
||||||
'id' => isset($auth_user) && $auth_user?$auth_user['uid']:null,
|
'username' => Auth::user()?Auth::user()->username:null,
|
||||||
'email' => isset($auth_user) && $auth_user?$auth_user['mail']:null,
|
|
||||||
'segment' => isset($auth_user) && $auth_user?$auth_user['type']:null,
|
|
||||||
'ip_address' => php_sapi_name()=='cli'?null:$_SERVER['REMOTE_ADDR'],
|
'ip_address' => php_sapi_name()=='cli'?null:$_SERVER['REMOTE_ADDR'],
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
|
@ -356,7 +356,6 @@ class Tpl {
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
protected static function define_common_variables($pagetitle=null) {
|
protected static function define_common_variables($pagetitle=null) {
|
||||||
global $auth_user;
|
|
||||||
self :: assign('public_root_url', Url :: public_root_url());
|
self :: assign('public_root_url', Url :: public_root_url());
|
||||||
self :: assign('pagetitle', $pagetitle);
|
self :: assign('pagetitle', $pagetitle);
|
||||||
self :: assign('main_pagetitle', App::get('main_pagetitle', null, 'string'));
|
self :: assign('main_pagetitle', App::get('main_pagetitle', null, 'string'));
|
||||||
|
@ -379,8 +378,8 @@ class Tpl {
|
||||||
self :: assign('TEXT_DOMAIN', I18n :: TEXT_DOMAIN);
|
self :: assign('TEXT_DOMAIN', I18n :: TEXT_DOMAIN);
|
||||||
|
|
||||||
// Authenticated user info
|
// Authenticated user info
|
||||||
if (isset($auth_user))
|
if (Auth::user())
|
||||||
self :: assign('auth_user', $auth_user);
|
self :: assign('auth_user', Auth::user());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
20
src/Url.php
20
src/Url.php
|
@ -77,8 +77,8 @@ class Url {
|
||||||
* @param array|null $additional_info Array of information to pass to the URL handler
|
* @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
|
* @param boolean $authenticated Permit to define if this URL is accessible only for
|
||||||
* authenticated users (optional, default: true if the
|
* authenticated users (optional, default: true if the
|
||||||
* special force_authentication function is defined,
|
* EesyPHP Authentication feature is enabled, false
|
||||||
* false otherwise)
|
* otherwise)
|
||||||
* @param boolean $overwrite Allow overwrite if a command already exists with the
|
* @param boolean $overwrite Allow overwrite if a command already exists with the
|
||||||
* same name (optional, default: false)
|
* same name (optional, default: false)
|
||||||
* @param boolean $api_mode Enable API mode (optional, default: false)
|
* @param boolean $api_mode Enable API mode (optional, default: false)
|
||||||
|
@ -88,12 +88,6 @@ class Url {
|
||||||
public static function add_url_handler($pattern, $handler=null, $additional_info=null,
|
public static function add_url_handler($pattern, $handler=null, $additional_info=null,
|
||||||
$authenticated=null, $overwrite=true, $api_mode=false,
|
$authenticated=null, $overwrite=true, $api_mode=false,
|
||||||
$http_methods=null) {
|
$http_methods=null) {
|
||||||
$authenticated = (
|
|
||||||
is_null($authenticated)?
|
|
||||||
function_exists('force_authentication'):
|
|
||||||
(bool)$authenticated
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check HTTP methods parameter
|
// Check HTTP methods parameter
|
||||||
if (is_null($http_methods))
|
if (is_null($http_methods))
|
||||||
$http_methods = array('GET', 'POST');
|
$http_methods = array('GET', 'POST');
|
||||||
|
@ -422,8 +416,7 @@ class Url {
|
||||||
* Handle the current requested URL
|
* Handle the current requested URL
|
||||||
*
|
*
|
||||||
* Note: if the route required that user is authenticated, this method will
|
* Note: if the route required that user is authenticated, this method will
|
||||||
* invoke the force_authentication() special function (or trigger a fatal error
|
* invoke Auth::login() in force mode (or trigger a fatal error if fail).
|
||||||
* if it's not defined).
|
|
||||||
*
|
*
|
||||||
* @param string|null $default_url The default URL if current one does not
|
* @param string|null $default_url The default URL if current one does not
|
||||||
* match with any configured pattern.
|
* match with any configured pattern.
|
||||||
|
@ -448,11 +441,8 @@ class Url {
|
||||||
Tpl :: assign('request', $request);
|
Tpl :: assign('request', $request);
|
||||||
|
|
||||||
// Check authentication (if need)
|
// Check authentication (if need)
|
||||||
if($request -> authenticated)
|
if($request -> authenticated && !Auth::login(true))
|
||||||
if (function_exists('force_authentication'))
|
Log :: fatal(I18n::_("Authentication required but fail to authenticate you."));
|
||||||
force_authentication();
|
|
||||||
else
|
|
||||||
Log :: fatal(I18n::_("Authentication required but force_authentication function is not defined."));
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
call_user_func($request -> handler, $request);
|
call_user_func($request -> handler, $request);
|
||||||
|
|
|
@ -54,7 +54,7 @@ class UrlRequest {
|
||||||
$this -> handler = $handler_info['handler'];
|
$this -> handler = $handler_info['handler'];
|
||||||
$this -> authenticated = (
|
$this -> authenticated = (
|
||||||
isset($handler_info['authenticated'])?
|
isset($handler_info['authenticated'])?
|
||||||
boolval($handler_info['authenticated']):true);
|
$handler_info['authenticated']:null);
|
||||||
$this -> api_mode = (
|
$this -> api_mode = (
|
||||||
isset($handler_info['api_mode'])?
|
isset($handler_info['api_mode'])?
|
||||||
boolval($handler_info['api_mode']):false);
|
boolval($handler_info['api_mode']):false);
|
||||||
|
@ -78,7 +78,11 @@ class UrlRequest {
|
||||||
if ($key == 'handler')
|
if ($key == 'handler')
|
||||||
return $this -> handler;
|
return $this -> handler;
|
||||||
if ($key == 'authenticated')
|
if ($key == 'authenticated')
|
||||||
return $this -> authenticated;
|
return (
|
||||||
|
is_null($this -> authenticated)?
|
||||||
|
Auth::enabled():
|
||||||
|
(bool)$this -> authenticated
|
||||||
|
);
|
||||||
if ($key == 'api_mode')
|
if ($key == 'api_mode')
|
||||||
return $this -> api_mode;
|
return $this -> api_mode;
|
||||||
if ($key == 'referer')
|
if ($key == 'referer')
|
||||||
|
|
|
@ -99,6 +99,13 @@ function ensure_is_array($value) {
|
||||||
* @return mixed The cast value
|
* @return mixed The cast value
|
||||||
**/
|
**/
|
||||||
function cast($value, $type, $split=false) {
|
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) {
|
switch($type) {
|
||||||
case 'bool':
|
case 'bool':
|
||||||
case 'boolean':
|
case 'boolean':
|
||||||
|
|
|
@ -53,11 +53,11 @@
|
||||||
<ul class="navbar-nav ml-md-auto">
|
<ul class="navbar-nav ml-md-auto">
|
||||||
<li class="nav-item dropdown">
|
<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">
|
<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>
|
</a>
|
||||||
<div class="dropdown-menu dropdown-menu-right">
|
<div class="dropdown-menu dropdown-menu-right">
|
||||||
{block name="navbar-user-menu"}{/block}
|
{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>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</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