1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/aeneria_ynh.git synced 2024-09-03 18:06:15 +02:00

æneria v2 (#48)

* æneria v2 (#44)

Let's go to æneria V2 

---------

Co-authored-by: yunohost-bot <yunohost@yunohost.org>
Co-authored-by: Éric Gaspar <46165813+ericgaspar@users.noreply.github.com>

* Update upstream app to v2.1.0

* Auto-update README

---------

Co-authored-by: yunohost-bot <yunohost@yunohost.org>
Co-authored-by: Éric Gaspar <46165813+ericgaspar@users.noreply.github.com>
This commit is contained in:
Simon MELLERIN 2024-01-13 19:12:46 +01:00 committed by GitHub
parent 37dcc93af2
commit c3de6b6f1f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 281 additions and 347 deletions

View file

@ -22,11 +22,15 @@ The idea of [æneria](https://aeneria.com) is to display energy consumption and
* Analyse energy consumption throw weather data * Analyse energy consumption throw weather data
**Shipped version:** 1.1.6~ynh5 **Shipped version:** 2.1.0~ynh1
**Demo:** https://demo.aeneria.com
## Screenshots ## Screenshots
![Screenshot of æneria](./doc/screenshots/screenshot1.png) ![Screenshot of æneria](./doc/screenshots/preview-2.png)
![Screenshot of æneria](./doc/screenshots/preview-3.png)
![Screenshot of æneria](./doc/screenshots/preview-1.png)
## Documentation and resources ## Documentation and resources

View file

@ -21,11 +21,15 @@ L'idée de [æneria](https://aeneria.com) est d'afficher la consommation d'éner
* Mieux comprendre sa propre consommation d'énergie * Mieux comprendre sa propre consommation d'énergie
* Analyser la consommation d'énergie et les données météorologiques * Analyser la consommation d'énergie et les données météorologiques
**Version incluse :** 1.1.6~ynh5 **Version incluse :** 2.1.0~ynh1
**Démo :** https://demo.aeneria.com
## Captures décran ## Captures décran
![Capture décran de æneria](./doc/screenshots/screenshot1.png) ![Capture décran de æneria](./doc/screenshots/preview-2.png)
![Capture décran de æneria](./doc/screenshots/preview-3.png)
![Capture décran de æneria](./doc/screenshots/preview-1.png)
## Documentations et ressources ## Documentations et ressources

View file

@ -32,10 +32,23 @@ AENERIA_DEMO_MODE=0
# Welcome message # Welcome message
AENERIA_WELCOME_MESSAGE='<h1>Bienvenue sur æneria</h1>' AENERIA_WELCOME_MESSAGE='<h1>Bienvenue sur æneria</h1>'
### Enedis Data Hub ### # æneria proxy URL (no trailing slash !)
AENERIA_PROXY_URL=https://proxy.aeneria.com
# should the app use æneria proxy (1 for yes, 0 for no)
AENERIA_PROXY_FOR_ENEDIS=1
AENERIA_PROXY_FOR_GRDF=1
# Enedis Data Hub
ENEDIS_CLIENT_ID=noneed ENEDIS_CLIENT_ID=noneed
ENEDIS_CLIENT_SECRET=noneed ENEDIS_CLIENT_SECRET=noneed
ENEDIS_REDIRECT_URI=noneed ENEDIS_REDIRECT_URI=noneed
ENEDIS_ENDPOINT_AUTH=https://proxy.aeneria.com/enedis-data-connect ENEDIS_ENDPOINT_AUTH=noneed
ENEDIS_ENDPOINT_TOKEN=https://proxy.aeneria.com/enedis-data-connect ENEDIS_ENDPOINT_TOKEN=noneed
ENEDIS_ENDPOINT_DATA=https://gw.prd.api.enedis.fr ENEDIS_ENDPOINT_DATA=noneed
# Grdf adict
GRDF_CLIENT_ID=noneed
GRDF_CLIENT_SECRET=noneed
GRDF_REDIRECT_URI=noneed
GRDF_ENDPOINT_AUTH=noneed
GRDF_ENDPOINT_DATA=noneed

View file

@ -7,19 +7,17 @@ location __PATH__/ {
client_body_timeout 60m; client_body_timeout 60m;
proxy_read_timeout 60m; proxy_read_timeout 60m;
fastcgi_read_timeout 60m; fastcgi_read_timeout 60m;
client_max_body_size 50M;
# Common parameter to increase upload size limit in conjunction with dedicated php-fpm file
#client_max_body_size 50M;
try_files $uri @__NAME__; try_files $uri @__NAME__;
location ~ ^__PATH__/index\.php(/|$) {
fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_pass unix:/var/run/php/php__PHPVERSION__-fpm-__NAME__.sock;
location ~ ^__PATH__/index\.php(/|$) {
include fastcgi_params; include fastcgi_params;
fastcgi_param REMOTE_USER $remote_user; fastcgi_split_path_info ^(.+\.php)(/.*)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param SCRIPT_FILENAME $request_filename; fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param REMOTE_USER $remote_user;
fastcgi_pass unix:/var/run/php/php__PHPVERSION__-fpm-__NAME__.sock;
fastcgi_intercept_errors on; fastcgi_intercept_errors on;
} }
@ -36,8 +34,3 @@ location __PATH__/ {
location @__NAME__ { location @__NAME__ {
rewrite ^ __PATH__/index.php/$is_args$args; rewrite ^ __PATH__/index.php/$is_args$args;
} }
#for-subdir location __PATH__ {
#for-subdir return 301 __PATH__/;
#for-subdir }

View file

@ -0,0 +1,6 @@
Since version 2, æneria must be installed under its own domain.
If æneria is currently installed under a path, before upgrading, change æneria URL:
* delete the path
* switch to a new dedicated domain (if needed)

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

View file

@ -1,41 +0,0 @@
#!/bin/bash
app=$1
# Run only if we are altering aeneria's permissions
[[ "$app" != "__APP__" ]] && exit 0
# Source YunoHost helpers
source /usr/share/yunohost/helpers
source /etc/yunohost/apps/$app/scripts/_common.sh
# Retrieve arguments
usernames=$2
permission=$3
groups=$4
install_dir=$(ynh_app_setting_get "$app" install_dir)
phpversion=$(ynh_app_setting_get "$app" phpversion)
IFS=',' read -r -a user_list <<< "$usernames"
IFS=',' read -r -a group_list <<< "$groups"
for group in "${group_list[@]}"
do
group_array=$(yunohost user group list --output-as json --quiet | jq -r --arg group "$group" ".groups.$group.members | @csv" | tr -d \")
IFS=',' read -r -a group_array <<< "$group_array"
user_list+=("${group_array[@]}")
done
pushd $install_dir
for user in "${user_list[@]}"
do
mail=$(ynh_user_get_info --username="$user" --key=mail)
user_exists=$(ynh_exec_as $app php$phpversion bin/console aeneria:user:exist "$mail")
if [ $user_exists -eq 0 ]
then
user_pass=$(ynh_string_random)
ynh_exec_as $app php$phpversion bin/console aeneria:user:add "$mail" "$user_pass" -n
else
ynh_exec_as $app php$phpversion bin/console aeneria:user:activate "$mail"
fi
done
popd

View file

@ -1,32 +0,0 @@
#!/bin/bash
app=$1
# Run only if we are altering aeneria's permissions
[[ "$app" != "__APP__" ]] && exit 0
# Source YunoHost helpers
source /usr/share/yunohost/helpers
source /etc/yunohost/apps/$app/scripts/_common.sh
# Retrieve arguments
usernames=$2
permission=$3
groups=$4
install_dir=$(ynh_app_setting_get "$app" install_dir)
phpversion=$(ynh_app_setting_get "$app" phpversion)
IFS=',' read -r -a user_list <<< "$usernames"
IFS=',' read -r -a group_list <<< "$groups"
for group in "${group_list[@]}"
do
group_array=$(yunohost user group list --output-as json --quiet | jq -r --arg group "$group" ".groups.$group.members | @csv" | tr -d \")
IFS=',' read -r -a group_array <<< "$group_array"
user_list+=("${group_array[@]}")
done
for user in "${user_list[@]}"
do
mail=$(ynh_user_get_info --username="$user" --key=mail)
cd "$install_dir" && ynh_exec_as $app php$phpversion bin/console aeneria:user:deactivate "$mail" -n
done

View file

@ -2,10 +2,10 @@ packaging_format = 2
id = "aeneria" id = "aeneria"
name = "æneria" name = "æneria"
description.en = "Dashboard to analyse your energy consumption data from Linky & weather" description.en = "Analyse your energy consumption (from Linky & Gazpar) & weather data"
description.fr = "Tableau de bord pour analyser votre consomation d'énergie à partir des données d'un Linky et de la météo" description.fr = "Analyser sa consommation d'énergie (via Linky & Gazpar) avec des données météo"
version = "1.1.6~ynh5" version = "2.1.0~ynh1"
maintainers = ["Simon Mellerin"] maintainers = ["Simon Mellerin"]
@ -14,15 +14,16 @@ license = "AGPL-3.0-or-later"
website = "https://aeneria.com" website = "https://aeneria.com"
admindoc = "https://docs.aeneria.com" admindoc = "https://docs.aeneria.com"
code = "https://gitlab.com/aeneria/aeneria-app" code = "https://gitlab.com/aeneria/aeneria-app"
demo = "https://demo.aeneria.com"
[integration] [integration]
yunohost = ">= 11.2" yunohost = ">= 11.2"
architectures = "all" architectures = "all"
multi_instance = true multi_instance = true
ldap = false ldap = true
sso = false sso = true
disk = "50M" disk = "50M"
ram.build = "50M" ram.build = "50M"
@ -32,24 +33,19 @@ ram.runtime = "50M"
[install.domain] [install.domain]
type = "domain" type = "domain"
[install.path]
type = "path"
default = "/aeneria"
[install.admin] [install.admin]
type = "user" type = "user"
[install.init_main_permission] [install.init_main_permission]
help.en = "Choose whether the app should be accessible only for your yunohost users or for everyone." help.en = "Choose whether the app should be accessible only for your YunoHost users or for everyone."
help.fr = "Choisissez si l'application doit être accessible uniquement pour vos utilisateurs yunohost ou pour tout le monde." help.fr = "Choisissez si l'application doit être accessible uniquement pour vos utilisateurs YunoHost ou pour tout le monde."
type = "group" type = "group"
default = false default = "all_users"
[resources] [resources]
[resources.sources.main] [resources.sources.main]
url = "https://statics.aeneria.com/aeneria-app-1.1.6.tar.gz" url = "https://statics.aeneria.com/aeneria-app-2.1.0.tar.gz"
sha256 = "2923c3aee79a02154c2168537a18250abe6a3a84fd7b4a5f0309bd7ad604a98b" sha256 = "c2f4dc9825fd769a6dff2cdacfa64ddbf9b54de1bc2660a4a515fee5444d1e5a"
[resources.system_user] [resources.system_user]
@ -59,7 +55,7 @@ ram.runtime = "50M"
main.url = "/" main.url = "/"
[resources.apt] [resources.apt]
packages = "postgresql, apt-transport-https, postgresql-contrib, php7.4-zip, php7.4-pgsql, php7.4-xml, php7.4-intl, php7.4-mbstring, php7.4-gd, php7.4-curl, php7.4-bcmath, php7.4-opcache" packages = "postgresql, apt-transport-https, postgresql-contrib, php8.2-zip, php8.2-pgsql, php8.2-xml, php8.2-intl, php8.2-gd, php8.2-curl, php8.2-bcmath, php8.2-opcache, php8.2-ldap"
[resources.database] [resources.database]
type = "postgresql" type = "postgresql"

View file

@ -17,10 +17,10 @@
# hour: random value between 0 and 2 # hour: random value between 0 and 2
# These two variables are used in conf/aeneria.cron so that it runs every 3 hours starting at 00:MM, 01:MM, or 02:MM. # These two variables are used in conf/aeneria.cron so that it runs every 3 hours starting at 00:MM, 01:MM, or 02:MM.
generate_random_minutes_hour () { generate_random_minutes_hour () {
minutes="$(ynh_string_random --length=1 --filter=0-5)$(ynh_string_random --length=1 --filter=0-9)" minutes="$(ynh_string_random --length=1 --filter=0-5)$(ynh_string_random --length=1 --filter=0-9)"
hour="$(ynh_string_random --length=1 --filter=0-2)" hour="$(ynh_string_random --length=1 --filter=0-2)"
ynh_app_setting_set --app=$app --key=minutes --value=$minutes ynh_app_setting_set --app=$app --key=minutes --value=$minutes
ynh_app_setting_set --app=$app --key=hour --value=$hour ynh_app_setting_set --app=$app --key=hour --value=$hour
} }
#================================================= #=================================================

View file

@ -9,6 +9,20 @@
source _common.sh source _common.sh
source /usr/share/yunohost/helpers source /usr/share/yunohost/helpers
#=================================================
# ENSURE DOWNWARD COMPATIBILITY
#=================================================
# Before version 2.x æneria could be installed under a path,
# this functionnality has been deprecated since version 2.0.0 and æneria
# now need to be installed under its own domain.
# If the app is currently installed under a path, we warn the admin
# that he should move the app under its own domain
if [ "$path" != "/" ]; then
ynh_die --message="Since version 2.0.0, $app need to be installed under its own domain. \
Before upgrading, change $app URL: delete the path and switch to a new domain if needed."
fi
#================================================= #=================================================
# STANDARD MODIFICATIONS # STANDARD MODIFICATIONS
#================================================= #=================================================

View file

@ -24,8 +24,8 @@ ynh_script_progression --message="Setting up source files..." --weight=1
# Download, check integrity, uncompress and patch the source from app.src # Download, check integrity, uncompress and patch the source from app.src
ynh_setup_source --dest_dir="$install_dir" ynh_setup_source --dest_dir="$install_dir"
chmod -R o-rwx "$install_dir"
chown -R $app:www-data "$install_dir" chown -R $app:www-data "$install_dir"
chmod -R 750 "$install_dir"
#================================================= #=================================================
# SYSTEM CONFIGURATION # SYSTEM CONFIGURATION
@ -57,11 +57,11 @@ ynh_script_progression --message="Installing aeneria..." --weight=1
# Install aeneria # Install aeneria
pushd $install_dir pushd $install_dir
ynh_exec_as $app php$phpversion bin/console aeneria:install "$app" -n ynh_exec_as $app php$phpversion bin/console aeneria:install "$app" -n
# Create admin user # Create admin user
mail=$(ynh_user_get_info --username="$admin" --key='mail') mail=$(ynh_user_get_info --username="$admin" --key='mail')
ynh_exec_as $app php$phpversion bin/console aeneria:user:add "$mail" "$(ynh_string_random)" -n ynh_exec_as $app php$phpversion bin/console aeneria:user:add "$mail" "$(ynh_string_random)" -n
ynh_exec_as $app php$phpversion bin/console aeneria:user:grant "$mail" ynh_exec_as $app php$phpversion bin/console aeneria:user:grant "$mail"
popd popd
#================================================= #=================================================
@ -76,14 +76,6 @@ ynh_add_config --template="aeneria.cron" --destination="/etc/cron.d/$app"
chown root: "/etc/cron.d/$app" chown root: "/etc/cron.d/$app"
chmod 644 "/etc/cron.d/$app" chmod 644 "/etc/cron.d/$app"
#=================================================
# ADAPT HOOK FOR AENERIA INSTANCE
#=================================================
ynh_script_progression --message="Adapting hooks..." --weight=1
ynh_replace_string --match_string="__APP__" --replace_string="$app" --target_file="../hooks/post_app_addaccess"
ynh_replace_string --match_string="__APP__" --replace_string="$app" --target_file="../hooks/post_app_removeaccess"
#================================================= #=================================================
# END OF SCRIPT # END OF SCRIPT
#================================================= #=================================================

View file

@ -24,8 +24,18 @@ ynh_script_progression --message="Ensuring downward compatibility..."
# If minutes or hour do not exist, create them # If minutes or hour do not exist, create them
if [ -z "${minutes:-}" ] || [ -z "${hour:-}" ]; then if [ -z "${minutes:-}" ] || [ -z "${hour:-}" ]; then
# Generate random running schedule, and save $hour and $minutes as app parameters # Generate random running schedule, and save $hour and $minutes as app parameters
generate_random_minutes_hour generate_random_minutes_hour
fi
# Before version 2.x æneria could be installed under a path,
# this functionnality has been deprecated since version 2.0.0 and æneria
# now need to be installed under its own domain.
# If the app is currently installed under a path, we warn the admin
# that he should move the app under its own domain
if [ "$path" != "/" ]; then
ynh_die --message="Since version 2.0.0, $app need to be installed under its own domain. \
Before upgrading, change $app URL: delete the path and switch to a new domain if needed."
fi fi
#================================================= #=================================================
@ -34,28 +44,31 @@ fi
if [ "$upgrade_type" == "UPGRADE_APP" ] if [ "$upgrade_type" == "UPGRADE_APP" ]
then then
ynh_script_progression --message="Upgrading source files..." ynh_script_progression --message="Upgrading source files..."
# For aeneria source update, we use a temporary directory because # For aeneria source update, we use a temporary directory because
# without it, patches can't be apply correctly: # without it, patches can't be apply correctly:
# In 'app-00-ldap-auth.patch' we create a new file, if we try # In 'app-00-ldap-auth.patch' we create a new file, if we try
# to apply the patch a second time while the file already exists, it # to apply the patch a second time while the file already exists, it
# throws a warning leading to an upgrade fail. # throws a warning leading to an upgrade fail.
# Create tmpdir for new sources # Create tmpdir for new sources
tmpdir="$(ynh_smart_mktemp min_size=300)" tmpdir="$(ynh_smart_mktemp min_size=300)"
# Download, check integrity, uncompress and patch the source from app.src # Download, check integrity, uncompress and patch the source from app.src
ynh_setup_source --dest_dir="$tmpdir" ynh_setup_source --dest_dir="$tmpdir"
# Replace the old aeneria by the new one # Keep private dir
ynh_secure_remove --file="$install_dir" mv "$install_dir/private" "$tmpdir"
mv "$tmpdir" "$install_dir"
ynh_secure_remove --file="$tmpdir" # Replace the old aeneria by the new one
ynh_secure_remove --file="$install_dir"
mv "$tmpdir" "$install_dir"
ynh_secure_remove --file="$tmpdir"
fi fi
chmod -R o-rwx "$install_dir"
chown -R $app:www-data "$install_dir" chown -R $app:www-data "$install_dir"
chmod -R 750 "$install_dir"
#================================================= #=================================================
# REAPPLY SYSTEM CONFIGURATIONS # REAPPLY SYSTEM CONFIGURATIONS
@ -91,30 +104,22 @@ ynh_script_progression --message="Upgrading $app..." --weight=1
# Install dependencies and aeneria # Install dependencies and aeneria
pushd $install_dir pushd $install_dir
ynh_exec_as $app php$phpversion bin/console cache:clear -n ynh_exec_as $app php$phpversion bin/console cache:clear -n
ynh_exec_as $app php$phpversion bin/console doctrine:migrations:migrate -n ynh_exec_as $app php$phpversion bin/console doctrine:migrations:migrate -n
# Set admin user # Set admin user
mail=$(ynh_user_get_info --username="$admin" --key='mail') mail=$(ynh_user_get_info --username="$admin" --key='mail')
user_exists=$(ynh_exec_as $app php$phpversion bin/console aeneria:user:exist "$mail") user_exists=$(ynh_exec_as $app php$phpversion bin/console aeneria:user:exist "$mail")
if [ $user_exists -eq 0 ] if [ $user_exists -eq 0 ]
then then
user_pass=$(ynh_string_random) user_pass=$(ynh_string_random)
ynh_exec_as $app php$phpversion bin/console aeneria:user:add "$mail" "$user_pass" -n ynh_exec_as $app php$phpversion bin/console aeneria:user:add "$mail" "$user_pass" -n
fi fi
# Regenerate RSA keys # Regenerate RSA keys
ynh_exec_as $app php$phpversion bin/console aeneria:generate-key --force -n ynh_exec_as $app php$phpversion bin/console aeneria:generate-key -n
popd popd
#=================================================
# ADAPT HOOK FOR AENERIA INSTANCE
#=================================================
ynh_script_progression --message="Adapting hooks..." --weight=1
ynh_replace_string --match_string="__APP__" --replace_string="$app" --target_file="../hooks/post_app_addaccess"
ynh_replace_string --match_string="__APP__" --replace_string="$app" --target_file="../hooks/post_app_removeaccess"
#================================================= #=================================================
# END OF SCRIPT # END OF SCRIPT
#================================================= #=================================================

View file

@ -1,179 +0,0 @@
commit c7a763a0fae7e1933f280b29bd2a1911b01f7170
Author: Simon Mellerin <simon.mellerin@makina-corpus.com>
Date: Fri Nov 27 12:19:02 2020 +0100
diff --git a/config/packages/security.yaml b/config/packages/security.yaml
index 15ef608..8516775 100644
--- a/config/packages/security.yaml
+++ b/config/packages/security.yaml
@@ -10,6 +10,8 @@ security:
entity:
class: App\Entity\User
property: username
+ user_provider_yunohost:
+ id: yunohost.provider.ldap
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
@@ -20,6 +22,10 @@ security:
provider: app_user_provider
authenticators:
- App\Security\LoginFormAuthenticator
+ http_basic_ldap:
+ provider: user_provider_yunohost
+ service: yunohost.ldap
+ dn_string: "uid={username},ou=users,dc=yunohost,dc=org"
logout:
path: security.logout
target: security.login
diff --git a/config/services.yaml b/config/services.yaml
index 533c244..9362ef5 100644
--- a/config/services.yaml
+++ b/config/services.yaml
@@ -70,3 +70,16 @@ services:
Aeneria\EnedisDataConnectApi\Service\DataConnectServiceInterface:
alias: Aeneria\EnedisDataConnectApi\Service\DataConnectService
+
+ yunohost.provider.ldap:
+ class: App\Security\YunohostLdapUserProvider
+ arguments: ["@yunohost.ldap", "ou=users,dc=yunohost,dc=org"]
+
+ yunohost.ldap:
+ class: Symfony\Component\Ldap\Ldap
+ arguments: ['@yunohost.ldap.adapter']
+
+ yunohost.ldap.adapter:
+ class: Symfony\Component\Ldap\Adapter\ExtLdap\Adapter
+ arguments:
+ - host: "localhost"
diff --git a/src/Security/YunohostLdapUserProvider.php b/src/Security/YunohostLdapUserProvider.php
new file mode 100644
index 0000000..39ba1e8
--- /dev/null
+++ b/src/Security/YunohostLdapUserProvider.php
@@ -0,0 +1,123 @@
+<?php
+
+namespace App\Security;
+
+use App\Entity\User;
+use App\Repository\UserRepository;
+use Symfony\Component\Ldap\Entry;
+use Symfony\Component\Ldap\Exception\ConnectionException;
+use Symfony\Component\Ldap\LdapInterface;
+use Symfony\Component\Security\Core\Exception\InvalidArgumentException;
+use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
+use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
+use Symfony\Component\Security\Core\User\UserInterface;
+use Symfony\Component\Security\Core\User\UserProviderInterface;
+
+/**
+ * Adapted from LdapUserProvider.
+ *
+ * @author Grégoire Pineau <lyrixx@lyrixx.info>
+ * @author Charles Sarrazin <charles@sarraz.in>
+ * @author Robin Chalas <robin.chalas@gmail.com>
+ */
+class YunohostLdapUserProvider implements UserProviderInterface
+{
+ /** @var LdapInterface */
+ private $ldap;
+ /** @var string */
+ private $baseDn;
+ /** @var string */
+ private $searchDn;
+ /** @var string */
+ private $searchPassword;
+ /** @var string[] */
+ private $defaultRoles;
+ /** @var string */
+ private $uidKey;
+ /** @var string */
+ private $defaultSearch;
+ /** @var UserRepository */
+ private $userRepository;
+
+ public function __construct(
+ LdapInterface $ldap,
+ string $baseDn,
+ string $searchDn = null,
+ string $searchPassword = null,
+ array $defaultRoles = [],
+ UserRepository $userRepository
+ ) {
+ $this->ldap = $ldap;
+ $this->baseDn = $baseDn;
+ $this->searchDn = $searchDn;
+ $this->searchPassword = $searchPassword;
+ $this->defaultRoles = $defaultRoles;
+ $this->defaultSearch = '(uid={username})';
+
+ $this->userRepository = $userRepository;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function loadUserByUsername(string $username)
+ {
+ try {
+ $this->ldap->bind($this->searchDn, $this->searchPassword);
+ $username = $this->ldap->escape($username, '', LdapInterface::ESCAPE_FILTER);
+ $query = str_replace('{username}', $username, $this->defaultSearch);
+ $search = $this->ldap->query($this->baseDn, $query);
+ } catch (ConnectionException $e) {
+ throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username), 0, $e);
+ }
+
+ $entries = $search->execute();
+ $count = \count($entries);
+
+ if (!$count) {
+ die($username . 'ldap pas trouvé');
+ throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username));
+ }
+
+ if ($count > 1) {
+ throw new UsernameNotFoundException('More than one user found.');
+ }
+
+ $entry = $entries[0];
+
+ $username = $this->getAttributeValue($entry, 'mail');
+
+ return $this->userRepository->findOneBy(['username' => $username]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function refreshUser(UserInterface $user)
+ {
+ if (!$user instanceof User) {
+ throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', \get_class($user)));
+ }
+
+ return $this->userRepository->findOneBy(['username' => $user->getUsername()]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function supportsClass(string $class)
+ {
+ return User::class === $class;
+ }
+
+ private function getAttributeValue(Entry $entry, string $attribute)
+ {
+ if (!$entry->hasAttribute($attribute)) {
+ throw new InvalidArgumentException(sprintf('Missing attribute "%s" for user "%s".', $attribute, $entry->getDn()));
+ }
+
+ $values = $entry->getAttribute($attribute);
+
+ return $values[0];
+ }
+}
--

View file

@ -0,0 +1,157 @@
commit 7a3e622666fa16ab124158cffec73d9a3e6748bf
Author: Simon Mellerin <simon.mellerin@makina-corpus.com>
Date: Sun Jan 7 16:25:06 2024 +0100
YNH LDAP
diff --git a/config/packages/security.yaml b/config/packages/security.yaml
index 6c4457f1..e716ba39 100644
--- a/config/packages/security.yaml
+++ b/config/packages/security.yaml
@@ -11,6 +11,11 @@ security:
entity:
class: App\Entity\User
property: username
+ ldap_user_provider:
+ id: ynh.ldap.user.provider
+ all_users:
+ chain:
+ providers: ['ldap_user_provider', 'app_user_provider']
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
@@ -22,7 +27,12 @@ security:
form_login:
login_path: security.login
check_path: security.login
+ provider: app_user_provider
enable_csrf: true
+ http_basic_ldap:
+ provider: ldap_user_provider
+ service: ynh.ldap
+ dn_string: 'uid={username},ou=users,dc=yunohost,dc=org'
logout:
path: security.logout
target: security.login
diff --git a/config/services.yaml b/config/services.yaml
index 3e770913..83fbec0d 100644
--- a/config/services.yaml
+++ b/config/services.yaml
@@ -104,3 +104,21 @@ services:
Aeneria\GrdfAdictApi\Client\GrdfAdictClientInterface:
alias: Aeneria\GrdfAdictApi\Client\GrdfAdictClient
+
+ ynh.ldap.user.provider:
+ class: App\Security\YnhLdapUserProvider
+ arguments:
+ $ldap: '@ynh.ldap'
+ $baseDn: "dc=yunohost,dc=org"
+ # $searchDn: 'uid={username},ou=users,dc=yunohost,dc=org'
+ $uidKey: "uid"
+
+ ynh.ldap:
+ class: Symfony\Component\Ldap\Ldap
+ arguments: ['@ynh.ldap.adapter']
+ tags: ['ldap']
+
+ ynh.ldap.adapter:
+ class: Symfony\Component\Ldap\Adapter\ExtLdap\Adapter
+ arguments:
+ - host: "localhost"
diff --git a/src/Security/YnhLdapUserProvider.php b/src/Security/YnhLdapUserProvider.php
new file mode 100755
index 00000000..eb8b1149
--- /dev/null
+++ b/src/Security/YnhLdapUserProvider.php
@@ -0,0 +1,89 @@
+<?php
+
+namespace App\Security;
+
+use App\Entity\User;
+use App\Repository\UserRepository;
+use Doctrine\ORM\EntityManagerInterface;
+use Symfony\Component\Ldap\Entry;
+use Symfony\Component\Ldap\LdapInterface;
+use Symfony\Component\Ldap\Security\LdapUserProvider as SecurityLdapUserProvider;
+use Symfony\Component\Security\Core\User\UserInterface;
+
+class YnhLdapUserProvider extends SecurityLdapUserProvider
+{
+ public function __construct(
+ private EntityManagerInterface $entityManager,
+ private UserRepository $userRepository,
+ LdapInterface $ldap,
+ string $baseDn,
+ string $searchDn = null,
+ string $searchPassword = null,
+ array $defaultRoles = [],
+ string $uidKey = null,
+ string $filter = null,
+ string $passwordAttribute = null,
+ array $extraFields = [])
+ {
+ parent::__construct(
+ $ldap,
+ $baseDn,
+ $searchDn,
+ $searchPassword,
+ $defaultRoles,
+ $uidKey,
+ $filter,
+ $passwordAttribute,
+ $extraFields,
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function upgradePassword($user, string $newHashedPassword): void
+ {
+ return;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function supportsClass(string $class)
+ {
+ return User::class === $class;
+ }
+
+ /**
+ * Loads a user from an LDAP entry.
+ *
+ * @return UserInterface
+ */
+ protected function loadUser(string $identifier, Entry $entry)
+ {
+ $email = $entry->getAttribute('mail');
+
+ // Dans le cadre de la connexion LDAP Yunohost,
+ // on cherche l'utilisateur par son mail.
+ //
+ $user = $this->userRepository->findOneBy(['username' => $email]);
+
+ // Si l'utilisateur n'existe pas encore, on le crée.
+ if (!$user) {
+ $user = (new User())
+ ->setUsername(\reset($email))
+ ->setPassword(\bin2hex(\random_bytes(32)))
+ ->setActive(true)
+ ->setUpdatedAt(new \DateTimeImmutable())
+ ;
+
+ $this->entityManager->persist($user);
+ $this->entityManager->flush();
+ }
+
+ return $user
+ ->setUsername(\reset($email))
+ ->setUserIdentifier($identifier)
+ ;
+ }
+}
+

View file

@ -1,3 +1,5 @@
test_format = 1.0 test_format = 1.0
[default] [default]
# aeneria needs its own dedicated domain
exclude = ["install.subdir"]