Coverage for src\baobab_web_api_caller\auth\basic_authentication_strategy.py: 93%

21 statements  

« prev     ^ index     » next       coverage.py v7.10.3, created at 2026-03-21 12:10 +0100

1"""Stratégie Basic auth (Authorization: Basic <base64(user:pass)>).""" 

2 

3from __future__ import annotations 

4 

5import base64 

6from dataclasses import dataclass 

7 

8from baobab_web_api_caller.auth.authentication_strategy import AuthenticationStrategy 

9from baobab_web_api_caller.core.baobab_request import BaobabRequest 

10from baobab_web_api_caller.exceptions.configuration_exception import ConfigurationException 

11 

12 

13@dataclass(frozen=True, slots=True) 

14class BasicAuthenticationStrategy(AuthenticationStrategy): 

15 """Applique l'authentification HTTP Basic. 

16 

17 Notes de sécurité: 

18 - Cette stratégie ne réalise pas de chiffrement. En production, l'usage doit se faire sur TLS. 

19 - Les identifiants ne doivent pas être loggés. 

20 

21 :param username: Nom d'utilisateur. 

22 :type username: str 

23 :param password: Mot de passe. 

24 :type password: str 

25 :raises ConfigurationException: Si les paramètres sont invalides. 

26 """ 

27 

28 username: str 

29 password: str 

30 

31 def __post_init__(self) -> None: 

32 if not isinstance(self.username, str) or self.username.strip() == "": 

33 raise ConfigurationException("username must be a non-empty string") 

34 if not isinstance(self.password, str): 34 ↛ 35line 34 didn't jump to line 35 because the condition on line 34 was never true

35 raise ConfigurationException("password must be a string") 

36 if ":" in self.username: 

37 raise ConfigurationException("username must not contain ':'") 

38 

39 def apply(self, request: BaobabRequest) -> BaobabRequest: 

40 """Ajoute/écrase ``Authorization`` avec l'en-tête Basic.""" 

41 

42 raw = f"{self.username}:{self.password}".encode("utf-8") 

43 token = base64.b64encode(raw).decode("ascii") 

44 return request.with_header("Authorization", f"Basic {token}")