Coverage for gws-app / gws / plugin / auth_method / basic / __init__.py: 40%

48 statements  

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

1"""HTTP Basic authorisation method.""" 

2 

3from typing import Optional 

4 

5import base64 

6 

7import gws 

8import gws.base.auth 

9import gws.base.web 

10 

11gws.ext.new.authMethod('basic') 

12 

13 

14class Config(gws.base.auth.method.Config): 

15 """HTTP-basic authorization options""" 

16 

17 realm: Optional[str] 

18 """Authentication realm.""" 

19 

20 

21class Object(gws.base.auth.method.Object): 

22 realm: str 

23 

24 def configure(self): 

25 self.uid = 'gws.plugin.auth_method.basic' 

26 self.realm = self.cfg('realm', default='Restricted Area') 

27 self.root.app.middlewareMgr.register(self, self.uid, depends_on=['auth']) 

28 

29 ## 

30 

31 def exit_middleware(self, req, res): 

32 if res.status == 403 and req.isGet: 

33 res.set_status(401) 

34 res.add_header('WWW-Authenticate', f'Basic realm={self.realm}, charset="UTF-8"') 

35 gws.log.debug(f'auth basic: redirect {res.status=}') 

36 

37 

38 def open_session(self, req): 

39 am = self.root.app.authMgr 

40 credentials = self._parse_header(req) 

41 if not credentials: 

42 return 

43 user = am.authenticate(self, credentials) 

44 if user: 

45 return am.sessionMgr.create(self, user) 

46 

47 def close_session(self, req, res): 

48 pass 

49 

50 def _parse_header(self, req: gws.WebRequester): 

51 h = req.header('Authorization') 

52 if not h: 

53 return 

54 

55 a = h.strip().split() 

56 if len(a) != 2 or a[0].lower() != 'basic': 

57 return 

58 

59 try: 

60 b = gws.u.to_str(base64.decodebytes(gws.u.to_bytes(a[1]))) 

61 except ValueError: 

62 return 

63 

64 c = b.split(':') 

65 if len(c) != 2: 

66 return 

67 

68 username = c[0].strip() 

69 if not username: 

70 return 

71 

72 return gws.Data(username=username, password=c[1])