Geoplateforme / sdk-entrepot

SDK Python pour utiliser l'API Entrepôt de la Géoplateforme.
GNU General Public License v3.0
1 stars 0 forks source link

Gestion des caractères spéciaux dans les valeurs du fichier config.ini (password) #152

Closed nrevelant closed 2 months ago

nrevelant commented 2 months ago

Dans le cas où certains caractères spéciaux comme '%' ou '$' sont présents dans des valeurs du fichier config.ini, ils semblent être interprétés et faire échouer le lancement du sdk. Le cas que je rencontre concerne la valeur du mot de passe.

Exemple de traces obtenues:


> $ python3 -m sdk_entrepot_gpf --ini ./config.ini me
> '%' must be followed by '%' or '{', found: '%_monmotdepRTht8yj9u\\\\%'
> ERREUR FATALE - Erreur non spécifiée :
> ERREUR - Traceback (most recent call last):
>   File "/home/station/code/github/sdk-entrepot/sdk-entrepot/sdk_entrepot_gpf/__main__.py", line 873, in <module>
>     Main()
>   File "/home/station/code/github/sdk-entrepot/sdk-entrepot/sdk_entrepot_gpf/__main__.py", line 67, in __init__
>     self.me_()
>   File "/home/station/code/github/sdk-entrepot/sdk-entrepot/sdk_entrepot_gpf/__main__.py", line 243, in me_
>     o_response = ApiRequester().route_request("me_get")
>   File "/home/station/code/github/sdk-entrepot/sdk-entrepot/sdk_entrepot_gpf/io/ApiRequester.py", line 111, in route_request
>     return self.url_request(s_url, method, params, data, files, d_header, timeout)
>   File "/home/station/code/github/sdk-entrepot/sdk-entrepot/sdk_entrepot_gpf/io/ApiRequester.py", line 149, in url_request
>     return self.__url_request(url, method, params=params, data=data, files=files, header=header, timeout=timeout)
>   File "/home/station/code/github/sdk-entrepot/sdk-entrepot/sdk_entrepot_gpf/io/ApiRequester.py", line 207, in __url_request
>     d_headers = Authentifier().get_http_header(json_content_type=files is None)
>   File "/home/station/code/github/sdk-entrepot/sdk-entrepot/sdk_entrepot_gpf/pattern/Singleton.py", line 23, in __call__
>     cls._instance = super().__call__(*args, **kwargs)
>   File "/home/station/code/github/sdk-entrepot/sdk-entrepot/sdk_entrepot_gpf/auth/Authentifier.py", line 33, in __init__
>     self.__request_params = self.__get_request_params()
>   File "/home/station/code/github/sdk-entrepot/sdk-entrepot/sdk_entrepot_gpf/auth/Authentifier.py", line 62, in __get_request_params
>     d_params["password"] = Config().get_str("store_authentification", "password")
>   File "/home/station/code/github/sdk-entrepot/sdk-entrepot/sdk_entrepot_gpf/io/Config.py", line 98, in get_str
>     return self.__config_parser.get(section, option, fallback=fallback)  # type: ignore
>   File "/usr/lib/python3.8/configparser.py", line 799, in get
>     return self._interpolation.before_get(self, section, option, value,
>   File "/usr/lib/python3.8/configparser.py", line 456, in before_get
>     self._interpolate_some(parser, option, L, value, section, defaults, 1)
>   File "/usr/lib/python3.8/configparser.py", line 516, in _interpolate_some
>     raise InterpolationSyntaxError(
> configparser.InterpolationSyntaxError: '%' must be followed by '%' or '{', found: '%_monmotdepRTht8yj9u%'

D'après un article comme ici https://stackoverflow.com/questions/47640354/reading-special-characters-text-from-ini-file-in-python , la solution passerait par l'utilisation d'un parser du type RawConfigParser ou ConfigParser(interpolation=None) sans interpolation à la place de ConfigParser.

J'ai tenté d'utiliser le contournement proposé dans cet article, qui consiste à doubler chaque caractère spécial. L'opération semble aller plus loin, mais avec une erreur 400 côté serveur (Keycloak ? API Entrepôt ?). Je n'arrive pas à avoir plus de trace, aucune en DEBUG notamment:

$ python3 -m sdk_entrepot_gpf --ini ./config.ini me
ALERTE - Code retour authentification KeyCloak = 400 (Account is not fully set up)
ALERTE - Code retour authentification KeyCloak = 400 (Account is not fully set up)
ALERTE - Code retour authentification KeyCloak = 400 (Account is not fully set up)
ALERTE - Code retour authentification KeyCloak = 400 (Account is not fully set up)
ALERTE - Code retour authentification KeyCloak = 400 (Account is not fully set up)
ALERTE - Code retour authentification KeyCloak = 400 (Account is not fully set up)
ERREUR - La récupération du jeton d'authentification a échoué après 5 tentatives
ERREUR - La récupération du jeton d'authentification a échoué après 5 tentatives
ERREUR FATALE - La récupération du jeton d'authentification a échoué après 5 tentatives

Je vais essayer de creuser si ce contournement peut tout même fonctionner.

Dans le code du dépôt je vois qu'actuellement la classe Config utilise l'interpolation étendue:

sdk_entrepot_gpf/io/Config.py
13:        __config_parser (configparser): ConfigParser
34:        self.__config_parser: configparser.ConfigParser = configparser.ConfigParser(interpolation=configparser.ExtendedInterpolation())
63:    def get_parser(self) -> configparser.ConfigParser:
vsasyan-ignf commented 2 months ago

L'interpolation étendue est nécessaire pour permettre de faire référence d'une clef à l'autre dans la config.

Il faut effectivement de doubler les caractères spéciaux pour que ça passe. Il est ensuite possible de vérifier que la config est correctement interprétée avec :

python3 -m sdk_entrepot_gpf --ini config.ini config -s store_authentification -o password

Je pense que le problème ne vient pas du password étant donné l'erreur : "Account is not fully set up"

Est-ce que tu peux tenter de te connecter via l'interface web pour voir s'il te demande pas de mettre à jour ton mdp ?

LudivineSchlegel commented 2 months ago

Bonjour, Le problème est connu. Pour l'instant, la solution la plus rapide est de changer de mot de passe ...

Il est prévu de permettre l'utilisation des fichiers de configuration .toml (cf #148). Le format toml étant plus permissif sur les caractères spéciaux, le changement de format de fichier évitera le problème des mots de passe

nrevelant commented 2 months ago

Je vois dans l'article cité qu'une solution pourrait être aussi de modifier la fonction get de la classe config :

def get(self, section: str, option: str, fallback: Optional[str] = None) -> Optional[str]:

pour permettre l'utilisation de l'argument raw=True de ConfigParser.get() pour le cas du mot de passe ? A condition que ceci soit ok du point de vue sécurité?

Je tente le contournement fourni, merci!

vsasyan-ignf commented 2 months ago

Je ne pense pas que le problème vienne de la config. As-tu tenté d'afficher le mdp pour voir si c'était le bon qui été récupéré ?

vsasyan-ignf commented 2 months ago

En mettant un autre mdp, j'ai une erreur différente :

ALERTE - Code retour authentification KeyCloak = 401 (Invalid user credentials)

vsasyan-ignf commented 2 months ago

Suite à entrevue avec l'utilisateur : les exigences de sécurité GPF exigeaient le renouvellement du mot de passe.

Suite à cela, deux améliorations à effectuer :