Skip to content

Commit

Permalink
Merge pull request #571 from jusabatier/patch_autorisation_organisations
Browse files Browse the repository at this point in the history
Gestion des zones de compétences des organisations
  • Loading branch information
pierrejego authored Sep 14, 2021
2 parents e655c26 + 585a096 commit 8dca1bd
Show file tree
Hide file tree
Showing 11 changed files with 320 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ public class PreRequestFilter implements ContainerRequestFilter {
public void filter(ContainerRequestContext requestContext) throws IOException {

String rolesList = requestContext.getHeaderString("sec-roles");
String org = requestContext.getHeaderString("sec-org");
String userName = requestContext.getHeaderString("sec-username");
MDC.put("user", userName);
MDC.put("org", org);
MDC.put("roles", rolesList);
MDC.put("uri", requestContext.getUriInfo().getPath());

Expand All @@ -34,4 +36,4 @@ public void filter(ContainerRequestContext requestContext) throws IOException {
}

}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.georchestra.cadastrapp.service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -146,39 +147,46 @@ protected String addAuthorizationFiltering(HttpHeaders headers) {
*/
protected String addAuthorizationFiltering(HttpHeaders headers, String tableAlias) {

logger.debug("Check user geographical limitation ");

List<Map<String, Object>> limitations;
List<String> communes = new ArrayList<String>();
List<String> deps = new ArrayList<String>();

StringBuilder queryFilter = new StringBuilder();

// get roles list in header
// Example 'ROLE_MOD_LDAPADMIN,ROLE_EL_CMS,ROLE_SV_ADMIN'
String usernameString = headers.getHeaderString("sec-username");
if (usernameString == null){
logger.debug("Not checking geographical limitation, anonymous user");
return queryFilter.toString();
}
// get org in header
String orgString = headers.getHeaderString("sec-org");
// get roles in heade
String roleListString = headers.getHeaderString("sec-roles");

logger.debug("user roleList : "+ roleListString);
// merge org+roles to get groups list
List<String> groupsList = new ArrayList<String>();
if(orgString!=null && !orgString.isEmpty()){
groupsList.add(orgString);
}
if(roleListString!=null && !roleListString.isEmpty()){

// set separator by default if not set
if(roleSeparator.isEmpty()){
roleSeparator = ";";
}
// Force to add the array of value in first place of a new Array
String[] roleList = roleListString.split(roleSeparator);
// get commune list in database corresponding to this header
groupsList.addAll(Arrays.asList(roleListString.split(roleSeparator)));
}

if(!groupsList.isEmpty()){
// get commune list in database corresponding to those groups
StringBuilder queryBuilder = new StringBuilder();
queryBuilder.append("select distinct cgocommune, ccodep from ");
queryBuilder.append(databaseSchema);
queryBuilder.append(".groupe_autorisation ");
queryBuilder.append(createWhereInQuery(roleList.length, "idgroup"));
queryBuilder.append(createWhereInQuery(groupsList.size(), "idgroup"));
queryBuilder.append(";");

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
limitations = jdbcTemplate.queryForList(queryBuilder.toString(), roleList);
limitations = jdbcTemplate.queryForList(queryBuilder.toString(), groupsList.toArray(new String[groupsList.size()]));

// filter request on commune
if (limitations != null && !limitations.isEmpty()) {
Expand All @@ -196,8 +204,12 @@ protected String addAuthorizationFiltering(HttpHeaders headers, String tableAlia
}

if(logger.isDebugEnabled()){
logger.debug("User have geographical limitation on zip code : " + communes.toString());
logger.debug("User have geographical limitation on dep : " + deps.toString());
if(!communes.isEmpty()){
logger.debug("User have geographical limitation on zip code : " + communes.toString());
}
if(!deps.isEmpty()){
logger.debug("User have geographical limitation on dep : " + deps.toString());
}
}


Expand Down Expand Up @@ -233,7 +245,8 @@ protected String addAuthorizationFiltering(HttpHeaders headers, String tableAlia
}
}
else{
logger.warn("No filter, no sec-roles was found");
logger.warn("User authenticated as '" + usernameString + "' but no sec-org header, maybe something is wrong.");
logger.warn("No filters applied because no sec-roles or sec-org corresponding rules were founds.");
}

return queryFilter.toString();
Expand Down
4 changes: 2 additions & 2 deletions cadastrapp/src/main/resources/logback.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>/tmp/cadastrapp.log</file>
<encoder>
<pattern>%d [%thread] %-5level /%X{uri} - %X{user:-nouser} - %X{roles:-norole} -%logger{36} - %msg%n</pattern>
<pattern>%d [%thread] %-5level /%X{uri} - %X{user:-nouser} - %X{org:-noorg} - %X{roles:-norole} -%logger{36} - %msg%n</pattern>
</encoder>
</appender>


<root level="DEBUG">
<appender-ref ref="FILE" />
</root>
</configuration>
</configuration>
142 changes: 135 additions & 7 deletions database/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

Ceci est la documentation des traitements qui mettent à jour la base de données applicative de cadastrapp.

=======
2 scripts existent :
- 1 script de purge + rechargement complet des données : `cadastrapp_load_data.sh`
- 1 script de rafraîchissement des vues matérialisées : `cadastrapp_update_data.sh`


**Pour une mise à jour incluant une mise à jour des données foncières (données MAJIC) il faut faire un rechargement complet de la base de données car, généralement il y a chaque année des mises à jour de valeurs des nomenclatures. En revanche, en cas de mise à jour des données du plan cadastral (EDIGEO) uniquement, on peut se contenter de rafraîchir les vues matérialisées.**


## Principe de fonctionnement

Avant de configurer et jouer les scripts, vous devez disposez d'une base de données PostgreSQL / PostGIS contenant des données cadastrales créées en utilisant le greffon **[QGIS cadastre](https://plugins.qgis.org/plugins/cadastre/)**.
Expand All @@ -22,7 +22,6 @@ Le script de purge + rechargement complet des données va créer les tables et *

L'utilisation des vues matérialisées permet de gagner du temps lors d'une mise à jour concernant uniquement le plan cadastral car un simple `REFRESH MATERIALIZED VIEW table_name` suffit à relire la base de données source.


## Prérequis

### Versions PostgreSQL et PostGIS
Expand All @@ -31,7 +30,6 @@ L'utilisation des vues matérialisées permet de gagner du temps lors d'une mise
* PostgreSQL > 9.6
* PostGIS > 2.1 mais < 3.0


### Si toutes les données sont dans la même base de données

C'est le cas le plus simple.
Expand All @@ -40,7 +38,6 @@ Dans ce cas il faut 2 schémas. Exemples :
* `cadastre_gis` : il contiendra les données cadastre produites par le plugin cadastre de QGIS
* `cadastrapp` : il contiendra les données applicatives pour cadastrapp et créées par notre script


### Si les données sont dans 2 bases de données distinctes

Dans ce cas on aura 2 bases de données différentes (sur la même machine ou pas) et donc 2 schémas différents. Exemples :
Expand All @@ -49,6 +46,42 @@ Dans ce cas on aura 2 bases de données différentes (sur la même machine ou pa

La base de données cible qui contiendra les données de cadastrapp devra comporter l'extension **[dblink](http://www.postgresql.org/docs/current//dblink.html)**.

### Si on souhaite remonter les autorisations geographiques depuis les groupes georchestra

Il faudra que le [fichier de correspondance fourni à la console](https://github.com/georchestra/georchestra/tree/master/console#custom-areas) comporte les codes INSEE des communes.

La base de données cible qui contiendra les données de cadastrapp devra :
* Comporter l'extension **[multicorn](https://multicorn.org/)**
* Avoir accès au serveur LDAP de l'instance geOrchestra

#### Installation de multicorn (Debian)

Dans Debian 10, multicorn est disponible via un paquet :

`$ sudo apt install postgresql-11-python3-multicorn`

Cette commande est à adapter en fonction de votre version de PostgreSQL.

#### Création du Foreign Data Wrapper pour LDAP

Afin de récupérer les emprises géographiques définies pour l'organisation des utilisateurs, il est necessaire de configurer une connexion de la base de données vers le LDAP de Georchestra.

Commencer par installer l'extension multicorn sur la BDD précedemment créée :

```
CREATE EXTENSION multicorn;
```

Puis, créer le lien vers le serveur LDAP :

```
CREATE SERVER ldap_srv foreign data wrapper multicorn options (
wrapper 'multicorn.ldapfdw.LdapFdw'
);
ALTER SERVER ldap_srv
OWNER TO #user_cadastrapp;
```
> **Note:** Remplacer `#user_cadastrapp` par l'utilisateur utilisé par cadastrapp
## Configuration

Expand All @@ -58,7 +91,7 @@ Sous linux ou git bash sous Windows :
* le renommer en `config.sh`
* l'ouvrir et compléter les informations de connection aux bases de données
* si les données cadastre QGIS et cadastrapp sont dans la même base de données, laisser `uniqueDB=True` sinon mettre `uniqueDB=False`

* si vous souhaitez remonter les autorisations cartographiques de puis les organisations geOrchestra (LDAP), mettre `orgsAutorisations=True` sinon laisser `orgsAutorisations=False`

## Purge + rechargement complet des données

Expand All @@ -68,7 +101,6 @@ Sous linux ou git bash sous Windows :

Note : il est possible de l'utiliser en mode silencieux avec l'option `-s` ou `--silent`. Si précisé, le script n'attendra pas de validation de la part de l'utilisateur.


## Mise à jour des données

Convient pour une mise à jour intermédiaire ne concernant pas une mise à jour des données foncières.
Expand All @@ -77,4 +109,100 @@ Sous linux ou git bash sous Windows :
* aller dans le répertoire `database`
* exécuter le script `cadastrapp_update_data.sh`

Note : il est possible de l'utiliser en mode silencieux avec l'option `-s` ou `--silent`. Si précisé, le script n'attendra pas de validation de la part de l'utilisateur.
Note : il est possible de l'utiliser en mode silencieux avec l'option `-s` ou `--silent`. Si précisé, le script n'attendra pas de validation de la part de l'utilisateur.

## Mise en place d'un CRON pour rafraichir les autorisations liées aux organisations

Si vous avez mis en place la gestion des autorisations geographiques depuis les groupes georchestra, le script a créé une vue materialisée contenant les codes INSEE pour chaque groupe qui ont été remontés depuis le LDAP.
Ceci permet de ne pas surcharger ce dernier avec des requêtes à chaque sollicitation de cadastrapp.

Néanmoins, pour que les changements sur les périmètres des organisations faits dans la console geOrchestra soient pris en compte, cette vue materialisée devra être rafraichie.

Pour ce faire, il est conseillé de mettre en place un CRON qui permettra de la rafraichir à interval régulier.

### Mise en place d'un 'cron job' dans debian

Créez un fichier de script `cadastrapp_refresh_ldap_view.sh` sur le serveur contenant la base de données cadastrapp avec le contenu suivant :

```
#!/bin/sh
PGPASSWORD=#cadastrapp_password psql -h #cadastrapp_db_host -p $cadastrapp_db_port -d $cadastrapp_db_name -U $cadastrapp_user -c 'refresh materialized view #cadastrapp_schema.org_autorisation'
```
> **Note:** Remplacez les variables précédées d'un `#` par la valeur appropriée
Déplacez le fichier dans le répertoire cron correspondant à la fréquence souhaitée :

* /etc/cron.hourly => toutes les heures
* /etc/cron.daily => tous les jours
* /etc/cron.weekly => toutes les semaines
* /etc/cron.monthly => tous les mois

Ou bien si vous souhaitez un parametrage plus poussé, référez vous à la [documentation de crontab](https://debian-facile.org/doc:systeme:crontab)

Enfin pensez-bien à rendre le fichier executable :

```
chmod +x cadastrapp_refresh_ldap_view.sh
```

### Mise en place d'un 'cron job' via pg_cron

Commencez par installer l'extension `cron` de postgresql :

```
sudo apt install postgresql-11-cron
```

Une fois installée, partie OS, il faudra modifier les paramètres base de données dans PostgreSQL afin de pouvoir utiliser cette extension.

Le fichier “postgresql.conf” devra indiquer les éléments suivants pour permettre la création de cette extension en base :

* share_preload_libraries
* cron.database_name

```
sudo nano /etc/postgesql/11/main/postgresql.conf
```

Ajoutez à la fin du fichier :

```
shared_preload_libraries = 'pg_cron'
cron.database_name = '#cadastrappDBName'
```

> **Note:** Remplacez `#cadastrappDBName` par le nom de la base de donnée hébergeant cadastrapp
Autorisez la connexion de l'utilisateur en local via trust pour permettre l'accès à la tache CRON,
pour cela dans le fichier `/etc/postgresql/11/main/pg_hba.conf` modifiez la ligne :

```
host #cadastrappDBName #user_cadastrapp 127.0.0.1/32 trust
host all all 127.0.0.1/32 md5
```
> **Note:** Remplacez les variables précédées d'un `#` par la valeur appropriée
Relancez postgresql :

```
sudo service postgresql restart
```

Activez l'extention dans la base de donnée hebergeant cadastrapp :

```
CREATE EXTENSION pg_cron;
```

Autorisez l'utilisation pour l'utilisateur cadastrapp :

```
GRANT USAGE ON SCHEMA cron TO #user_cadastrapp;
GRANT INSERT ON TABLE cron.job TO #user_cadastrapp;
GRANT USAGE ON SEQUENCE cron.jobid_seq TO #user_cadastrapp;
```
> **Note:** Remplacer `#user_cadastrapp` par l'utilisateur utilisé par cadastrapp
Enfin lancez le script de definition la tache CRON :

```
./create_ldap_cronjob.sh
```
> **Note:** Par défaut, le script défini le rafraichissement de la vue mateiralisée toutes les heures, si cela ne vous convient pas, vous pouvez modifier cette configuration dans le fichier `sql/ldap/cronjob.sql`.
32 changes: 30 additions & 2 deletions database/cadastrapp_load_data.sh
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,39 @@ else
exit 1
fi

echo ""
if [ "$orgsAutorisations" = True ] ; then
invalidLdapParam=False
if [ -z "$ldapUri" ] ; then
echo "Paramètre ldapUri manquant !"
invalidLdapParam=True
fi

if [ -z "$ldapPath" ] ; then
echo "Paramètre ldapPath manquant !"
invalidLdapParam=True
fi

if [ -z "$ldapBindDn" ] ; then
echo "Paramètre ldapBindDn manquant !"
invalidLdapParam=True
fi

if [ -z "$ldapBindPwd" ] ; then
echo "Paramètre ldapBindPwd manquant !"
invalidLdapParam=True
fi
if [ "$invalidLdapParam" = True ] ; then
echo " pb de configuration : stop"
exit 1
fi
fi

if [ "$silentMode" = False ] ; then
echo ""
read -p " Si ces infos sont exactes : appuyer sur la touche [Entrée] sinon faire ctrl + C pour arrêter."
echo ""
fi


#
# cette fonction permet de remplacer les infos de connection
# avant exécution
Expand All @@ -78,6 +102,10 @@ replaceAndLaunch (){
s/#DBSchema_qgis/$qgisDBSchema/g
s/#DBUser_qgis/$qgisDBUser/g
s/#DBpasswd_qgis/$qgisDBPassword/g
s|#ldap_uri|$ldapUri|g
s/#ldap_path/$ldapPath/g
s/#ldap_binddn/$ldapBindDn/g
s/#ldap_bindpwd/$ldapBindPwd/g
}" |\
PGPASSWORD=$cadastrappDBPassword psql -h $cadastrappDBHost -p $cadastrappDBPort -d $cadastrappDBName -U $cadastrappDBUser

Expand Down
9 changes: 9 additions & 0 deletions database/config_sample.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,12 @@ cadastrappDBPassword=cadastrapp_mdp
# True / False
uniqueDB=True

# Récupération des autorisations geographiques configurées pour les organisations dans la console geOrchestra
# True / False
orgsAutorisations=False

# Obligatoires si orgsAutorisations=True
#ldapUri=ldaps://ldap.georchestra.org
#ldapPath=ou=orgs,dc=georchestra,dc=org
#ldapBindDn=uid=cadastrapp,ou=users,dc=lepuyenvelay,dc=fr
#ldapBindPwd=secret
Loading

0 comments on commit 8dca1bd

Please sign in to comment.