pytest-nhsd-apim 4.0.1__tar.gz → 5.0.2__tar.gz
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.
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/PKG-INFO +2 -2
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/pyproject.toml +2 -2
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/src/pytest_nhsd_apim/apigee_edge.py +18 -9
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/src/pytest_nhsd_apim/identity_service.py +17 -30
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/src/pytest_nhsd_apim.egg-info/PKG-INFO +2 -2
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/src/pytest_nhsd_apim.egg-info/requires.txt +1 -1
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/tests/test_examples.py +21 -46
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/README.md +0 -0
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/setup.cfg +0 -0
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/setup.py +0 -0
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/src/pytest_nhsd_apim/__init__.py +0 -0
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/src/pytest_nhsd_apim/apigee_apis.py +0 -0
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/src/pytest_nhsd_apim/auth_journey.py +0 -0
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/src/pytest_nhsd_apim/config.py +0 -0
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/src/pytest_nhsd_apim/log.py +0 -0
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/src/pytest_nhsd_apim/nhsd_apim_authorization.py +0 -0
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/src/pytest_nhsd_apim/pytest_nhsd_apim.py +0 -0
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/src/pytest_nhsd_apim/secrets.py +0 -0
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/src/pytest_nhsd_apim/token_cache.py +0 -0
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/src/pytest_nhsd_apim.egg-info/SOURCES.txt +0 -0
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/src/pytest_nhsd_apim.egg-info/dependency_links.txt +0 -0
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/src/pytest_nhsd_apim.egg-info/entry_points.txt +0 -0
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/src/pytest_nhsd_apim.egg-info/top_level.txt +0 -0
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/tests/test_apigee_apis.py +0 -0
- {pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/tests/test_nhsd_apim.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pytest-nhsd-apim
|
|
3
|
-
Version:
|
|
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
|
|
@@ -13,7 +13,7 @@ Requires-Python: >=3.8
|
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
Requires-Dist: Authlib==1.3.1
|
|
15
15
|
Requires-Dist: cryptography==42.0.0
|
|
16
|
-
Requires-Dist: lxml==
|
|
16
|
+
Requires-Dist: lxml==5.3.1
|
|
17
17
|
Requires-Dist: pycryptodome==3.20.0
|
|
18
18
|
Requires-Dist: PyJWT==2.8.0
|
|
19
19
|
Requires-Dist: pyotp==2.9.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "pytest-nhsd-apim"
|
|
3
|
-
version = "
|
|
3
|
+
version = "5.0.2"
|
|
4
4
|
description = "Pytest plugin accessing NHSDigital's APIM proxies"
|
|
5
5
|
authors = ["Adrian Ciobanita <adrian.ciobanita1@nhs.net>", "Alex Carrie <alexander.carrie1@nhs.net>", "Lucas Fantini <lucas.fantini@nhs.net>"]
|
|
6
6
|
maintainers = ["Alex Carrie <alexander.carrie1@nhs.net>", "Alex Hawdon <alex.hawdon1@nhs.net"]
|
|
@@ -12,7 +12,7 @@ license = "MIT"
|
|
|
12
12
|
[tool.poetry.dependencies]
|
|
13
13
|
Authlib = "^1.3.1"
|
|
14
14
|
cryptography = ">42.0.0"
|
|
15
|
-
lxml = "^
|
|
15
|
+
lxml = "^5.3.1"
|
|
16
16
|
python = "^3.8"
|
|
17
17
|
pycryptodome = "^3.20.0"
|
|
18
18
|
PyJWT = "^2.8.0"
|
|
@@ -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(
|
|
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://
|
|
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://
|
|
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 =
|
|
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://
|
|
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[
|
|
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:
|
|
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
|
|
@@ -13,7 +13,7 @@ Requires-Python: >=3.8
|
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
Requires-Dist: Authlib==1.3.1
|
|
15
15
|
Requires-Dist: cryptography==42.0.0
|
|
16
|
-
Requires-Dist: lxml==
|
|
16
|
+
Requires-Dist: lxml==5.3.1
|
|
17
17
|
Requires-Dist: pycryptodome==3.20.0
|
|
18
18
|
Requires-Dist: PyJWT==2.8.0
|
|
19
19
|
Requires-Dist: pyotp==2.9.0
|
|
@@ -3,6 +3,7 @@ Example tests that show all the features of pytest_nhsd_apim.
|
|
|
3
3
|
|
|
4
4
|
These tests actually work!
|
|
5
5
|
"""
|
|
6
|
+
|
|
6
7
|
import json
|
|
7
8
|
import pytest
|
|
8
9
|
import requests
|
|
@@ -43,9 +44,7 @@ def test_status_endpoint(nhsd_apim_proxy_url, status_endpoint_auth_headers):
|
|
|
43
44
|
# {"apikey": "thesecretvalue"} Use it to access your proxy's
|
|
44
45
|
# _status endpoint.
|
|
45
46
|
|
|
46
|
-
resp = requests.get(
|
|
47
|
-
nhsd_apim_proxy_url + "/_status", headers=status_endpoint_auth_headers
|
|
48
|
-
)
|
|
47
|
+
resp = requests.get(nhsd_apim_proxy_url + "/_status", headers=status_endpoint_auth_headers)
|
|
49
48
|
status_json = resp.json()
|
|
50
49
|
assert resp.status_code == 200
|
|
51
50
|
assert status_json["status"] == "pass"
|
|
@@ -63,9 +62,7 @@ def test_app_level0_access(nhsd_apim_proxy_url, nhsd_apim_auth_headers):
|
|
|
63
62
|
resp = requests.get(nhsd_apim_proxy_url + "/test-auth/app/level0")
|
|
64
63
|
assert resp.status_code == 401 # unauthorized
|
|
65
64
|
|
|
66
|
-
resp = requests.get(
|
|
67
|
-
nhsd_apim_proxy_url + "/test-auth/app/level0", headers=nhsd_apim_auth_headers
|
|
68
|
-
)
|
|
65
|
+
resp = requests.get(nhsd_apim_proxy_url + "/test-auth/app/level0", headers=nhsd_apim_auth_headers)
|
|
69
66
|
assert resp.status_code == 200 # authorized
|
|
70
67
|
|
|
71
68
|
|
|
@@ -81,9 +78,7 @@ def test_app_level3_access(nhsd_apim_proxy_url, nhsd_apim_auth_headers):
|
|
|
81
78
|
resp = requests.get(nhsd_apim_proxy_url + "/test-auth/app/level3")
|
|
82
79
|
assert resp.status_code == 401 # unauthorized
|
|
83
80
|
|
|
84
|
-
resp = requests.get(
|
|
85
|
-
nhsd_apim_proxy_url + "/test-auth/app/level3", headers=nhsd_apim_auth_headers
|
|
86
|
-
)
|
|
81
|
+
resp = requests.get(nhsd_apim_proxy_url + "/test-auth/app/level3", headers=nhsd_apim_auth_headers)
|
|
87
82
|
assert resp.status_code == 200 # authorized
|
|
88
83
|
|
|
89
84
|
|
|
@@ -103,17 +98,13 @@ def test_app_level3_access_repeatedly(count, nhsd_apim_auth_headers):
|
|
|
103
98
|
return "rd"
|
|
104
99
|
return "th"
|
|
105
100
|
|
|
106
|
-
print(
|
|
107
|
-
f"This is the {count}{th(count)} test using the same credentials - {nhsd_apim_auth_headers}"
|
|
108
|
-
)
|
|
101
|
+
print(f"This is the {count}{th(count)} test using the same credentials - {nhsd_apim_auth_headers}")
|
|
109
102
|
|
|
110
103
|
|
|
111
104
|
# If for any reason you want to override the caching
|
|
112
105
|
# the force_new_token flag can be added
|
|
113
106
|
@pytest.mark.parametrize(("count"), [1, 2, 3])
|
|
114
|
-
@pytest.mark.nhsd_apim_authorization(
|
|
115
|
-
{"access": "application", "level": "level3", "force_new_token": True}
|
|
116
|
-
)
|
|
107
|
+
@pytest.mark.nhsd_apim_authorization({"access": "application", "level": "level3", "force_new_token": True})
|
|
117
108
|
def test_app_level3_with_force_new_token(count, nhsd_apim_auth_headers):
|
|
118
109
|
def th(i):
|
|
119
110
|
if i == 1:
|
|
@@ -124,9 +115,7 @@ def test_app_level3_with_force_new_token(count, nhsd_apim_auth_headers):
|
|
|
124
115
|
return "rd"
|
|
125
116
|
return "th"
|
|
126
117
|
|
|
127
|
-
print(
|
|
128
|
-
f"This is the {count}{th(count)} test using different credentials - {nhsd_apim_auth_headers}"
|
|
129
|
-
)
|
|
118
|
+
print(f"This is the {count}{th(count)} test using different credentials - {nhsd_apim_auth_headers}")
|
|
130
119
|
|
|
131
120
|
|
|
132
121
|
# You can include marks in a pytest parametrization to reduce
|
|
@@ -218,7 +207,8 @@ MOCK_CIS2_USERNAMES = {
|
|
|
218
207
|
# Create a list of pytest.param for each combination of username and level for combined auth
|
|
219
208
|
combined_auth_params = [
|
|
220
209
|
pytest.param(
|
|
221
|
-
username,
|
|
210
|
+
username,
|
|
211
|
+
level,
|
|
222
212
|
marks=pytest.mark.nhsd_apim_authorization(
|
|
223
213
|
access="healthcare_worker",
|
|
224
214
|
level=level,
|
|
@@ -231,9 +221,7 @@ combined_auth_params = [
|
|
|
231
221
|
|
|
232
222
|
|
|
233
223
|
@pytest.mark.parametrize("username, level", combined_auth_params)
|
|
234
|
-
def test_healthcare_worker_user_restricted_combined_auth(
|
|
235
|
-
nhsd_apim_proxy_url, nhsd_apim_auth_headers, username, level
|
|
236
|
-
):
|
|
224
|
+
def test_healthcare_worker_user_restricted_combined_auth(nhsd_apim_proxy_url, nhsd_apim_auth_headers, username, level):
|
|
237
225
|
url = f"{nhsd_apim_proxy_url}/test-auth/nhs-cis2/{level}"
|
|
238
226
|
resp0 = requests.get(url)
|
|
239
227
|
assert resp0.status_code == 401
|
|
@@ -252,7 +240,8 @@ def test_healthcare_worker_user_restricted_combined_auth(
|
|
|
252
240
|
# Create a combined list for separate authentication testing
|
|
253
241
|
separate_auth_params = [
|
|
254
242
|
pytest.param(
|
|
255
|
-
username,
|
|
243
|
+
username,
|
|
244
|
+
level,
|
|
256
245
|
marks=pytest.mark.nhsd_apim_authorization(
|
|
257
246
|
access="healthcare_worker",
|
|
258
247
|
level=level,
|
|
@@ -266,9 +255,7 @@ separate_auth_params = [
|
|
|
266
255
|
|
|
267
256
|
|
|
268
257
|
@pytest.mark.parametrize("username, level", separate_auth_params)
|
|
269
|
-
def test_healthcare_work_user_restricted_separate_auth(
|
|
270
|
-
nhsd_apim_proxy_url, nhsd_apim_auth_headers, username, level
|
|
271
|
-
):
|
|
258
|
+
def test_healthcare_work_user_restricted_separate_auth(nhsd_apim_proxy_url, nhsd_apim_auth_headers, username, level):
|
|
272
259
|
aal_url = f"{nhsd_apim_proxy_url}/test-auth/nhs-cis2/{level}"
|
|
273
260
|
resp0 = requests.get(aal_url)
|
|
274
261
|
assert resp0.status_code == 401
|
|
@@ -288,9 +275,7 @@ def test_healthcare_work_user_restricted_separate_auth(
|
|
|
288
275
|
"authentication": "separate",
|
|
289
276
|
}
|
|
290
277
|
)
|
|
291
|
-
def test_patient_user_restricted_separate_auth(
|
|
292
|
-
nhsd_apim_proxy_url, nhsd_apim_auth_headers
|
|
293
|
-
):
|
|
278
|
+
def test_patient_user_restricted_separate_auth(nhsd_apim_proxy_url, nhsd_apim_auth_headers):
|
|
294
279
|
P9_url = f"{nhsd_apim_proxy_url}/test-auth/nhs-login/P9"
|
|
295
280
|
resp0 = requests.get(P9_url)
|
|
296
281
|
assert resp0.status_code == 401
|
|
@@ -302,25 +287,19 @@ def test_patient_user_restricted_separate_auth(
|
|
|
302
287
|
# nhsd_apim_authorization marker. This allows you to parameterize
|
|
303
288
|
# unauthenicated access tests in the same way as authenticated API calls.
|
|
304
289
|
@pytest.mark.nhsd_apim_authorization()
|
|
305
|
-
def test_no_authorization_explicitly_marked(
|
|
306
|
-
nhsd_apim_proxy_url, nhsd_apim_auth_headers
|
|
307
|
-
):
|
|
290
|
+
def test_no_authorization_explicitly_marked(nhsd_apim_proxy_url, nhsd_apim_auth_headers):
|
|
308
291
|
assert nhsd_apim_auth_headers == {}
|
|
309
292
|
|
|
310
293
|
|
|
311
294
|
# You can also do it without marking, though this raises a warning.
|
|
312
|
-
def test_no_authorization_with_not_explicitly_marked(
|
|
313
|
-
nhsd_apim_proxy_url, nhsd_apim_auth_headers
|
|
314
|
-
):
|
|
295
|
+
def test_no_authorization_with_not_explicitly_marked(nhsd_apim_proxy_url, nhsd_apim_auth_headers):
|
|
315
296
|
assert nhsd_apim_auth_headers == {}
|
|
316
297
|
|
|
317
298
|
|
|
318
299
|
# You can also use the authenticators directly in case you want to run the tests
|
|
319
300
|
# using a specific app already available in Apigee, leaving all the marker magic
|
|
320
301
|
# behind this is how you can implement the diferent authenticators
|
|
321
|
-
def test_client_credentials_authenticator(
|
|
322
|
-
_test_app_credentials, _jwt_keys, apigee_environment
|
|
323
|
-
):
|
|
302
|
+
def test_client_credentials_authenticator(_test_app_credentials, _jwt_keys, apigee_environment):
|
|
324
303
|
# 1. Set your app config
|
|
325
304
|
config = ClientCredentialsConfig(
|
|
326
305
|
environment=apigee_environment,
|
|
@@ -352,7 +331,7 @@ def test_authorization_code_authenticator(_test_app_credentials, apigee_environm
|
|
|
352
331
|
config = AuthorizationCodeConfig(
|
|
353
332
|
environment=apigee_environment,
|
|
354
333
|
identity_service_base_url=f"https://{apigee_environment}.api.service.nhs.uk/oauth2-mock",
|
|
355
|
-
callback_url="https://
|
|
334
|
+
callback_url="https://google.com/callback",
|
|
356
335
|
client_id=_test_app_credentials["consumerKey"],
|
|
357
336
|
client_secret=_test_app_credentials["consumerSecret"],
|
|
358
337
|
scope="nhs-cis2",
|
|
@@ -439,13 +418,9 @@ def test_trace(nhsd_apim_proxy_url, nhsd_apim_auth_headers, trace):
|
|
|
439
418
|
|
|
440
419
|
trace_ids = trace.get_transaction_data(session_name=session_name)
|
|
441
420
|
|
|
442
|
-
trace_data = trace.get_transaction_data_by_id(
|
|
443
|
-
|
|
444
|
-
)
|
|
445
|
-
status_code_from_trace = trace.get_apigee_variable_from_trace(
|
|
446
|
-
name="message.status.code", data=trace_data
|
|
447
|
-
)
|
|
421
|
+
trace_data = trace.get_transaction_data_by_id(session_name=session_name, transaction_id=trace_ids[0])
|
|
422
|
+
status_code_from_trace = trace.get_apigee_variable_from_trace(name="message.status.code", data=trace_data)
|
|
448
423
|
|
|
449
424
|
trace.delete_debugsession_by_name(session_name)
|
|
450
425
|
|
|
451
|
-
assert status_code_from_trace == "200"
|
|
426
|
+
assert status_code_from_trace == "200"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/src/pytest_nhsd_apim/nhsd_apim_authorization.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/src/pytest_nhsd_apim.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/src/pytest_nhsd_apim.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{pytest_nhsd_apim-4.0.1 → pytest_nhsd_apim-5.0.2}/src/pytest_nhsd_apim.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|