Skip to content

Commit e1c80b4

Browse files
ELI-578 consumer_id error validation
1 parent bcd1d8d commit e1c80b4

File tree

5 files changed

+34
-6
lines changed

5 files changed

+34
-6
lines changed

src/eligibility_signposting_api/common/api_error_response.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,11 @@ def log_and_generate_response(
135135
fhir_error_code=FHIRSpineErrorCode.ACCESS_DENIED,
136136
fhir_display_message="Access has been denied to process this request.",
137137
)
138+
139+
CONSUMER_ID_NOT_PROVIDED_ERROR = APIErrorResponse(
140+
status_code=HTTPStatus.FORBIDDEN,
141+
fhir_issue_code=FHIRIssueCode.FORBIDDEN,
142+
fhir_issue_severity=FHIRIssueSeverity.ERROR,
143+
fhir_error_code=FHIRSpineErrorCode.ACCESS_DENIED,
144+
fhir_display_message="Access has been denied to process this request.",
145+
)

src/eligibility_signposting_api/common/request_validator.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@
77
from flask.typing import ResponseReturnValue
88

99
from eligibility_signposting_api.common.api_error_response import (
10+
CONSUMER_ID_NOT_PROVIDED_ERROR,
1011
INVALID_CATEGORY_ERROR,
1112
INVALID_CONDITION_FORMAT_ERROR,
1213
INVALID_INCLUDE_ACTIONS_ERROR,
1314
NHS_NUMBER_MISMATCH_ERROR,
1415
)
15-
from eligibility_signposting_api.config.constants import NHS_NUMBER_HEADER
16+
from eligibility_signposting_api.config.constants import CONSUMER_ID, NHS_NUMBER_HEADER
1617

1718
logger = logging.getLogger(__name__)
1819

@@ -56,6 +57,14 @@ def validate_request_params() -> Callable:
5657
def decorator(func: Callable) -> Callable:
5758
@wraps(func)
5859
def wrapper(*args, **kwargs) -> ResponseReturnValue: # noqa:ANN002,ANN003
60+
consumer_id = str(request.headers.get(CONSUMER_ID))
61+
62+
if not consumer_id:
63+
message = "You are not authorised to request"
64+
return CONSUMER_ID_NOT_PROVIDED_ERROR.log_and_generate_response(
65+
log_message=message, diagnostics=message
66+
)
67+
5968
path_nhs_number = str(kwargs.get("nhs_number"))
6069
header_nhs_no = str(request.headers.get(NHS_NUMBER_HEADER))
6170

src/eligibility_signposting_api/config/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
URL_PREFIX = "patient-check"
44
RULE_STOP_DEFAULT = False
55
NHS_NUMBER_HEADER = "nhs-login-nhs-number"
6+
CONSUMER_ID = "consumer-id"
67
ALLOWED_CONDITIONS = Literal["COVID", "FLU", "MMR", "RSV"]

src/eligibility_signposting_api/views/eligibility.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
from eligibility_signposting_api.audit.audit_service import AuditService
1414
from eligibility_signposting_api.common.api_error_response import NHS_NUMBER_NOT_FOUND_ERROR
1515
from eligibility_signposting_api.common.request_validator import validate_request_params
16-
from eligibility_signposting_api.config.constants import URL_PREFIX
16+
from eligibility_signposting_api.config.constants import CONSUMER_ID, URL_PREFIX
17+
from eligibility_signposting_api.model.consumer_mapping import ConsumerId
1718
from eligibility_signposting_api.model.eligibility_status import Condition, EligibilityStatus, NHSNumber, Status
1819
from eligibility_signposting_api.services import EligibilityService, UnknownPersonError
1920
from eligibility_signposting_api.views.response_model import eligibility_response
@@ -48,13 +49,14 @@ def check_eligibility(
4849
) -> ResponseReturnValue:
4950
logger.info("checking nhs_number %r in %r", nhs_number, eligibility_service, extra={"nhs_number": nhs_number})
5051
try:
51-
query_params = get_or_default_query_params()
52+
query_params = _get_or_default_query_params()
53+
consumer_id = _get_consumer_id_from_headers()
5254
eligibility_status = eligibility_service.get_eligibility_status(
5355
nhs_number,
5456
query_params["includeActions"],
5557
query_params["conditions"],
5658
query_params["category"],
57-
request.headers.get("Consumer-ID"),
59+
consumer_id,
5860
)
5961
except UnknownPersonError:
6062
return handle_unknown_person_error(nhs_number)
@@ -64,7 +66,14 @@ def check_eligibility(
6466
return make_response(response.model_dump(by_alias=True, mode="json", exclude_none=True), HTTPStatus.OK)
6567

6668

67-
def get_or_default_query_params() -> dict[str, Any]:
69+
def _get_consumer_id_from_headers() -> ConsumerId:
70+
"""
71+
@validate_request_params() ensures the consumer ID is never null at this stage.
72+
"""
73+
return ConsumerId(request.headers.get(CONSUMER_ID, ""))
74+
75+
76+
def _get_or_default_query_params() -> dict[str, Any]:
6877
default_query_params = {"category": "ALL", "conditions": ["ALL"], "includeActions": "Y"}
6978

7079
if not request.args:

tests/integration/in_process/test_eligibility_endpoint.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
has_key,
1414
)
1515

16+
from eligibility_signposting_api.config.constants import CONSUMER_ID
1617
from eligibility_signposting_api.model.campaign_config import CampaignConfig
1718
from eligibility_signposting_api.model.consumer_mapping import ConsumerMapping
1819
from eligibility_signposting_api.model.eligibility_status import (
@@ -30,7 +31,7 @@ def test_nhs_number_given(
3031
secretsmanager_client: BaseClient, # noqa: ARG002
3132
):
3233
# Given
33-
headers = {"nhs-login-nhs-number": str(persisted_person), "Consumer-ID": "23-mic7heal-jor6don"}
34+
headers = {"nhs-login-nhs-number": str(persisted_person), CONSUMER_ID: "23-mic7heal-jor6don"}
3435

3536
# When
3637
response = client.get(f"/patient-check/{persisted_person}", headers=headers)

0 commit comments

Comments
 (0)