pytest-nhsd-apim 5.0.0__py3-none-any.whl → 5.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pytest-nhsd-apim might be problematic. Click here for more details.

@@ -5,6 +5,7 @@ This includes app setup/teardown, getting proxy info (proxy-under-test
5
5
  + identity-service of choice), getting products, registering them with
6
6
  the test app.
7
7
  """
8
+
8
9
  import functools
9
10
  import warnings
10
11
  from datetime import datetime
@@ -22,7 +23,7 @@ from .apigee_apis import (
22
23
  DebugSessionsAPI,
23
24
  AccessTokensAPI,
24
25
  ApiProductsAPI,
25
- DeveloperAppsAPI
26
+ DeveloperAppsAPI,
26
27
  )
27
28
 
28
29
  APIGEE_BASE_URL = "https://api.enterprise.apigee.com/v1/"
@@ -48,6 +49,7 @@ def _apigee_app_base_url(nhsd_apim_config):
48
49
  url = APIGEE_BASE_URL + f"organizations/{org}/developers/{dev}/apps"
49
50
  return url
50
51
 
52
+
51
53
  @pytest.fixture(scope="session")
52
54
  @log_method
53
55
  def _apigee_app_base_url_no_dev(nhsd_apim_config):
@@ -55,6 +57,7 @@ def _apigee_app_base_url_no_dev(nhsd_apim_config):
55
57
  url = APIGEE_BASE_URL + f"organizations/{org}/apps"
56
58
  return url
57
59
 
60
+
58
61
  @functools.lru_cache(maxsize=None)
59
62
  @log_method
60
63
  def _get_proxy_json(session, nhsd_apim_proxy_url):
@@ -62,8 +65,8 @@ def _get_proxy_json(session, nhsd_apim_proxy_url):
62
65
  Query the apigee edge API to get data about the desired proxy, in particular its current deployment.
63
66
  """
64
67
  deployment_err_msg = (
65
- "\n\tFailed to retrieve the proxy deployment data. " +
66
- "Please check the validity of the APIGEE credentials and token as well as any headers."
68
+ "\n\tFailed to retrieve the proxy deployment data. "
69
+ + "Please check the validity of the APIGEE credentials and token as well as any headers."
67
70
  )
68
71
  deployment_resp = session.get(f"{nhsd_apim_proxy_url}/deployments")
69
72
  assert deployment_resp.status_code == 200, deployment_err_msg.format(deployment_resp.content)
@@ -283,7 +286,9 @@ _TEST_APP = None
283
286
 
284
287
  @pytest.fixture(scope="session")
285
288
  @log_method
286
- def nhsd_apim_test_app(_create_test_app, _apigee_edge_session, _apigee_app_base_url, _apigee_app_base_url_no_dev, _test_app_id) -> Callable:
289
+ def nhsd_apim_test_app(
290
+ _create_test_app, _apigee_edge_session, _apigee_app_base_url, _apigee_app_base_url_no_dev, _test_app_id
291
+ ) -> Callable:
287
292
  """
288
293
  A Callable that gets you the current state of the test app.
289
294
  """
@@ -314,7 +319,7 @@ def nhsd_apim_test_app(_create_test_app, _apigee_edge_session, _apigee_app_base_
314
319
  return _TEST_APP
315
320
  if _test_app_id:
316
321
  resp = _apigee_edge_session.get(_apigee_app_base_url_no_dev + "/" + _test_app_id)
317
- else:
322
+ else:
318
323
  resp = _apigee_edge_session.get(_apigee_app_base_url + "/" + _create_test_app["name"])
319
324
  _TEST_APP = resp.json()
320
325
  return _TEST_APP
@@ -468,7 +473,7 @@ def _create_test_app(
468
473
  else:
469
474
  app = {
470
475
  "name": f"apim-auto-{uuid4()}",
471
- "callbackUrl": "https://example.org/callback",
476
+ "callbackUrl": "https://google.com/callback",
472
477
  "attributes": [{"name": "jwks-resource-url", "value": jwt_public_key_url}],
473
478
  }
474
479
  create_resp = _apigee_edge_session.post(_apigee_app_base_url, json=app)
@@ -512,7 +517,7 @@ def _create_function_scoped_test_app(
512
517
  else:
513
518
  app = {
514
519
  "name": f"apim-auto-{uuid4()}",
515
- "callbackUrl": "https://example.org/callback",
520
+ "callbackUrl": "https://google.com/callback",
516
521
  "attributes": [{"name": "jwks-resource-url", "value": jwt_public_key_url}],
517
522
  }
518
523
  create_resp = _apigee_edge_session.post(_apigee_app_base_url, json=app)
@@ -538,6 +543,7 @@ def _test_app_callback_url(_create_test_app):
538
543
  def _test_app_id(nhsd_apim_config):
539
544
  return nhsd_apim_config["APIGEE_APP_ID"]
540
545
 
546
+
541
547
  @pytest.fixture()
542
548
  @log_method
543
549
  def trace(_apigee_proxy):
@@ -545,15 +551,16 @@ def trace(_apigee_proxy):
545
551
  Authenticated wrapper around the DebugSessionsAPI class
546
552
  """
547
553
  config = ApigeeNonProdCredentials()
548
- client = ApigeeClient(config=config)
554
+ client = ApigeeClient(config=config)
549
555
  debug = DebugSessionsAPI(
550
556
  client=client,
551
557
  env_name=_apigee_proxy["environment"],
552
558
  api_name=_apigee_proxy["name"],
553
- revision_number=_apigee_proxy["revision"]
559
+ revision_number=_apigee_proxy["revision"],
554
560
  )
555
561
  return debug
556
562
 
563
+
557
564
  @pytest.fixture(scope="session")
558
565
  @log_method
559
566
  def access_token_api():
@@ -575,6 +582,7 @@ def products_api():
575
582
  client = ApigeeClient(config=config)
576
583
  return ApiProductsAPI(client=client)
577
584
 
585
+
578
586
  @pytest.fixture(scope="session")
579
587
  @log_method
580
588
  def developer_apps_api():
@@ -585,6 +593,7 @@ def developer_apps_api():
585
593
  client = ApigeeClient(config=config)
586
594
  return DeveloperAppsAPI(client=client)
587
595
 
596
+
588
597
  @pytest.fixture(scope="session")
589
598
  @log_method
590
599
  def developer_app_keys_api():
@@ -1,8 +1,8 @@
1
1
  """
2
2
  This is a self-contained wrapper for a bunch of authentication
3
- methods in APIM. NOT ONLY the identity service is taken into
4
- account in here, you will also find authenticators for keycloak
5
- and more... Feel free to keep adding authenticators here and
3
+ methods in APIM. NOT ONLY the identity service is taken into
4
+ account in here, you will also find authenticators for keycloak
5
+ and more... Feel free to keep adding authenticators here and
6
6
  maybe move this file to its own library.
7
7
  """
8
8
 
@@ -20,6 +20,7 @@ from typing_extensions import Annotated
20
20
 
21
21
  HttpUrlString = Annotated[HttpUrl, AfterValidator(lambda v: str(v))]
22
22
 
23
+
23
24
  #### Config models
24
25
  class KeycloakConfig(BaseModel):
25
26
  """Basic Keycloak config"""
@@ -55,7 +56,7 @@ class KeycloakConfig(BaseModel):
55
56
  class KeycloakUserConfig(KeycloakConfig):
56
57
  client_id: str
57
58
  client_secret: str
58
- redirect_uri: HttpUrlString = "https://example.org"
59
+ redirect_uri: HttpUrlString = "https://google.com"
59
60
  login_form: dict
60
61
 
61
62
 
@@ -92,9 +93,7 @@ class AuthorizationCodeConfig(BaseModel):
92
93
  @validator("environment")
93
94
  def validate_environment(cls, environment):
94
95
  if environment == "prod":
95
- raise ValueError(
96
- f"We dont support testing in the production environment"
97
- )
96
+ raise ValueError(f"We dont support testing in the production environment")
98
97
  return environment
99
98
 
100
99
 
@@ -136,9 +135,7 @@ class ClientCredentialsConfig(BaseModel):
136
135
  "exp": int(time()) + 300, # 5 minutes in the future
137
136
  }
138
137
  additional_headers = {"kid": self.jwt_kid}
139
- client_assertion = jwt.encode(
140
- claims, self.jwt_private_key, algorithm="RS512", headers=additional_headers
141
- )
138
+ client_assertion = jwt.encode(claims, self.jwt_private_key, algorithm="RS512", headers=additional_headers)
142
139
  return client_assertion
143
140
 
144
141
 
@@ -150,6 +147,7 @@ class TokenExchangeConfig(ClientCredentialsConfig):
150
147
  class KeycloakSignedJWTConfig:
151
148
  pass
152
149
 
150
+
153
151
  # currently only targets AOS environment
154
152
  class NHSLoginConfig(BaseModel):
155
153
  """Config needed to authenticate using NHS Login"""
@@ -159,7 +157,7 @@ class NHSLoginConfig(BaseModel):
159
157
  self.nhs_login_base_url = openid_config["issuer"]
160
158
 
161
159
  well_known_jwks: list = requests.get(openid_config["jwks_uri"]).json()
162
- well_known_key = well_known_jwks['keys'].pop()
160
+ well_known_key = well_known_jwks["keys"].pop()
163
161
  self.jwt_kid = well_known_key["kid"]
164
162
  self.alg = well_known_key["alg"]
165
163
 
@@ -184,16 +182,14 @@ class NHSLoginConfig(BaseModel):
184
182
  "exp": int(time()) + 300, # 5 minutes in the future
185
183
  }
186
184
  additional_headers = {"kid": self.jwt_kid}
187
- client_assertion = jwt.encode(
188
- claims, self.jwt_private_key, algorithm=self.alg, headers=additional_headers
189
- )
185
+ client_assertion = jwt.encode(claims, self.jwt_private_key, algorithm=self.alg, headers=additional_headers)
190
186
  return client_assertion
191
-
192
187
 
193
188
 
194
189
  class BananaAuthenticatorConfig: # Placeholder
195
190
  pass
196
191
 
192
+
197
193
  ### Authenticators
198
194
  class Authenticator(ABC):
199
195
  """Defines the interface"""
@@ -263,9 +259,7 @@ class AuthorizationCodeAuthenticator(Authenticator):
263
259
  },
264
260
  )
265
261
  if resp.status_code != 200:
266
- raise RuntimeError(
267
- f"{auth_url} request returned {resp.status_code}: {resp.text}"
268
- )
262
+ raise RuntimeError(f"{auth_url} request returned {resp.status_code}: {resp.text}")
269
263
  return resp
270
264
 
271
265
  @staticmethod
@@ -299,9 +293,7 @@ class AuthorizationCodeAuthenticator(Authenticator):
299
293
  form_submission_data,
300
294
  ):
301
295
  form_submit_url = authorize_form.action or authorize_response.request.url
302
- resp = session.request(
303
- authorize_form.method, form_submit_url, data=form_submission_data
304
- )
296
+ resp = session.request(authorize_form.method, form_submit_url, data=form_submission_data)
305
297
  # TODO: Investigate why when using the fixtures it returns 404 and when
306
298
  # using with external credentials returns 200
307
299
  # if resp.status_code != 200:
@@ -312,9 +304,7 @@ class AuthorizationCodeAuthenticator(Authenticator):
312
304
 
313
305
  @staticmethod
314
306
  def _get_auth_code_from_mock_auth(response_identity_service_login):
315
- qs = urlparse(
316
- response_identity_service_login.history[-1].headers["Location"]
317
- ).query
307
+ qs = urlparse(response_identity_service_login.history[-1].headers["Location"]).query
318
308
  auth_code = parse_qs(qs)["code"]
319
309
  if isinstance(auth_code, list):
320
310
  # in case there's multiple, this was a bug at one stage
@@ -336,16 +326,12 @@ class AuthorizationCodeAuthenticator(Authenticator):
336
326
  self.config.scope,
337
327
  )
338
328
 
339
- authorize_form = self._get_authorization_form(
340
- authorize_response.content.decode()
341
- )
329
+ authorize_form = self._get_authorization_form(authorize_response.content.decode())
342
330
  # 2. Parse the login page. For keycloak this presents an
343
331
  # HTML form, which must be filled in with valid data. The tester
344
332
  # can submits their login data with the `login_form` field.
345
333
 
346
- form_submission_data = self._get_authorize_form_submission_data(
347
- authorize_form, self.config.login_form
348
- )
334
+ form_submission_data = self._get_authorize_form_submission_data(authorize_form, self.config.login_form)
349
335
 
350
336
  # form_submission_data["username"] = 656005750104
351
337
  # # And here we inject a valid mock username for keycloak.
@@ -508,6 +494,7 @@ class NHSLoginSandpitAuthenticator(Authenticator):
508
494
 
509
495
  class NHSLoginAosAuthenticator(Authenticator):
510
496
  """Authenticates you against NHS-Login aos environment"""
497
+
511
498
  # This is only partially implemented. See below for usage:
512
499
  # https://nhsd-confluence.digital.nhs.uk/display/APM/KOP-085+Generating+NHS+login+ID+tokens
513
500
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pytest-nhsd-apim
3
- Version: 5.0.0
3
+ Version: 5.0.2
4
4
  Summary: Pytest plugin accessing NHSDigital's APIM proxies
5
5
  Home-page: https://github.com/NHSDigital/pytest-nhsd-apim
6
6
  Author: Adrian Ciobanita
@@ -1,16 +1,16 @@
1
1
  pytest_nhsd_apim/__init__.py,sha256=CRwQfUDrbXIqvJX6OfTR4jGdhlU9kjGmBAptJasRg7E,72
2
2
  pytest_nhsd_apim/apigee_apis.py,sha256=u_sHjISj4XKgidVje1Uzq4LblMGnX4lrrrMWZM-SEF4,67289
3
- pytest_nhsd_apim/apigee_edge.py,sha256=NQrW8PeA_-X4zt2torTmBOaFIzRKjh6pT1ksolNjpmA,19065
3
+ pytest_nhsd_apim/apigee_edge.py,sha256=STfwfXpdGLURCfZ3AoXwyAhfP2vIyVDY1U_W0350SE8,19076
4
4
  pytest_nhsd_apim/auth_journey.py,sha256=UovbLXhokUnikrMOaXIhjV8t5aRrcxinAbS96nfZWcY,5154
5
5
  pytest_nhsd_apim/config.py,sha256=ScKfV8iURqDXX2ajgGsRDcVn9RZy2DxLoEU2QQt9lmA,4246
6
- pytest_nhsd_apim/identity_service.py,sha256=0ymDSEsTuBYcMU15zFNuqEV6PMvC7Z0Vde0PkN8NQ2E,19899
6
+ pytest_nhsd_apim/identity_service.py,sha256=naVMtBJR7cRYLbP1mJyyGGrit9YqWF50CpELM2vgp4g,19702
7
7
  pytest_nhsd_apim/log.py,sha256=8gYHqzlQM546FB2XvFmLTk1YfZRNeNhIwLmOy0GScr8,2685
8
8
  pytest_nhsd_apim/nhsd_apim_authorization.py,sha256=GR8GfbIZyqBC4jsSZMYNifDH52E3VWoIa7lrpuvIbaM,3513
9
9
  pytest_nhsd_apim/pytest_nhsd_apim.py,sha256=ZCItUqcM23CCmcRyGU8bEwI3vJnNcGdoOlbSfvYILR8,5242
10
10
  pytest_nhsd_apim/secrets.py,sha256=yIYwOZwpliIomtqSJGIYRbAE2HYvLvQU4W2kOa9TnXo,2354
11
11
  pytest_nhsd_apim/token_cache.py,sha256=6L08taTlSyRsx2NCb0LSGsHdWx_wmqwlFtcF7pZMhUg,3540
12
- pytest_nhsd_apim-5.0.0.dist-info/METADATA,sha256=8t_2m8WWcrUJ30Y8Cv4y4Mr_jC6cWo9z-TVZA0crtZM,4704
13
- pytest_nhsd_apim-5.0.0.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
14
- pytest_nhsd_apim-5.0.0.dist-info/entry_points.txt,sha256=XWicT3meTpqLXnZcXNoAd2IfXspFPlNgMgLBMy4nqwQ,57
15
- pytest_nhsd_apim-5.0.0.dist-info/top_level.txt,sha256=ZK5GZP-g_K8gNfm4a58T9JCRb0i1X267ngvNelCGgfQ,17
16
- pytest_nhsd_apim-5.0.0.dist-info/RECORD,,
12
+ pytest_nhsd_apim-5.0.2.dist-info/METADATA,sha256=eovd0I30Nv0B0-RFskDi1FFdxuOQiK_VPfEpP93Y7eU,4704
13
+ pytest_nhsd_apim-5.0.2.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
14
+ pytest_nhsd_apim-5.0.2.dist-info/entry_points.txt,sha256=XWicT3meTpqLXnZcXNoAd2IfXspFPlNgMgLBMy4nqwQ,57
15
+ pytest_nhsd_apim-5.0.2.dist-info/top_level.txt,sha256=ZK5GZP-g_K8gNfm4a58T9JCRb0i1X267ngvNelCGgfQ,17
16
+ pytest_nhsd_apim-5.0.2.dist-info/RECORD,,