Coverage for benefits/oauth/client.py: 100%

24 statements  

« prev     ^ index     » next       coverage.py v7.6.9, created at 2024-12-19 00:56 +0000

1""" 

2The oauth application: helpers for working with OAuth clients. 

3""" 

4 

5import logging 

6 

7from authlib.integrations.django_client import OAuth 

8 

9from benefits.core import models 

10 

11logger = logging.getLogger(__name__) 

12 

13oauth = OAuth() 

14 

15 

16def _client_kwargs(scope=None): 

17 """ 

18 Generate the OpenID Connect client_kwargs, with optional extra scope(s). 

19 

20 `scope` should be a space-separated list of scopes to add. 

21 """ 

22 scopes = ["openid", scope] if scope else ["openid"] 

23 return {"code_challenge_method": "S256", "scope": " ".join(scopes), "prompt": "login"} 

24 

25 

26def _server_metadata_url(authority): 

27 """ 

28 Generate the OpenID Connect server_metadata_url for an OAuth authority server. 

29 

30 `authority` should be a fully qualified HTTPS domain name, e.g. https://example.com. 

31 """ 

32 return f"{authority}/.well-known/openid-configuration" 

33 

34 

35def _authorize_params(scheme): 

36 if scheme is not None: 

37 params = {"scheme": scheme} 

38 else: 

39 params = None 

40 

41 return params 

42 

43 

44def _register_provider(oauth_registry: OAuth, flow: models.EnrollmentFlow): 

45 """ 

46 Register OAuth clients into the given registry, using configuration from ClaimsProvider and EnrollmentFlow models. 

47 

48 Adapted from https://stackoverflow.com/a/64174413. 

49 """ 

50 logger.debug(f"Registering OAuth client: {flow.claims_provider.client_name}") 

51 

52 client = oauth_registry.register( 

53 flow.claims_provider.client_name, 

54 client_id=flow.claims_provider.client_id, 

55 server_metadata_url=_server_metadata_url(flow.claims_provider.authority), 

56 client_kwargs=_client_kwargs(flow.claims_scope), 

57 authorize_params=_authorize_params(flow.claims_scheme), 

58 ) 

59 

60 return client 

61 

62 

63def create_client(oauth_registry: OAuth, flow: models.EnrollmentFlow): 

64 """ 

65 Returns an OAuth client, registering it if needed. 

66 """ 

67 client = oauth_registry.create_client(flow.claims_provider.client_name) 

68 

69 if client is None: 

70 client = _register_provider(oauth_registry, flow) 

71 

72 return client