Skip to content
This repository was archived by the owner on Oct 23, 2023. It is now read-only.

Commit fa04762

Browse files
authored
Merge pull request #134 from CSCfi/feature/ga4gh-jwt-fixes
GA4GH JWT Standard 1.0 processing with Passports
2 parents 564aace + 7853803 commit fa04762

14 files changed

Lines changed: 575 additions & 282 deletions

File tree

beacon_api/api/exceptions.py

Lines changed: 39 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -10,37 +10,35 @@
1010
from ..conf import CONFIG_INFO
1111

1212

13-
class BeaconError(Exception):
14-
"""BeaconError Exception specific class.
13+
def process_exception_data(request, host, error_code, error):
14+
"""Return request data as dictionary.
1515
1616
Generates custom exception messages based on request parameters.
1717
"""
18-
19-
def __init__(self, request, host, error_code, error):
20-
"""Return request data as dictionary."""
21-
self.data = {'beaconId': '.'.join(reversed(host.split('.'))),
22-
"apiVersion": __apiVersion__,
23-
'exists': None,
24-
'error': {'errorCode': error_code,
25-
'errorMessage': error},
26-
'alleleRequest': {'referenceName': request.get("referenceName", None),
27-
'referenceBases': request.get("referenceBases", None),
28-
'includeDatasetResponses': request.get("includeDatasetResponses", "NONE"),
29-
'assemblyId': request.get("assemblyId", None)},
30-
# showing empty datasetsAlleRsponse as no datasets found
31-
# A null/None would represent no data while empty array represents
32-
# none found or error and corresponds with exists null/None
33-
'datasetAlleleResponses': []}
34-
# include datasetIds only if they are specified
35-
# as per specification if they don't exist all datatsets will be queried
36-
# Only one of `alternateBases` or `variantType` is required, validated by schema
37-
oneof_fields = ["alternateBases", "variantType", "start", "end", "startMin", "startMax",
38-
"endMin", "endMax", "datasetIds"]
39-
self.data['alleleRequest'].update({k: request.get(k) for k in oneof_fields if k in request})
40-
return self.data
41-
42-
43-
class BeaconBadRequest(BeaconError):
18+
data = {'beaconId': '.'.join(reversed(host.split('.'))),
19+
"apiVersion": __apiVersion__,
20+
'exists': None,
21+
'error': {'errorCode': error_code,
22+
'errorMessage': error},
23+
'alleleRequest': {'referenceName': request.get("referenceName", None),
24+
'referenceBases': request.get("referenceBases", None),
25+
'includeDatasetResponses': request.get("includeDatasetResponses", "NONE"),
26+
'assemblyId': request.get("assemblyId", None)},
27+
# showing empty datasetsAlleRsponse as no datasets found
28+
# A null/None would represent no data while empty array represents
29+
# none found or error and corresponds with exists null/None
30+
'datasetAlleleResponses': []}
31+
# include datasetIds only if they are specified
32+
# as per specification if they don't exist all datatsets will be queried
33+
# Only one of `alternateBases` or `variantType` is required, validated by schema
34+
oneof_fields = ["alternateBases", "variantType", "start", "end", "startMin", "startMax",
35+
"endMin", "endMax", "datasetIds"]
36+
data['alleleRequest'].update({k: request.get(k) for k in oneof_fields if k in request})
37+
38+
return data
39+
40+
41+
class BeaconBadRequest(web.HTTPBadRequest):
4442
"""Exception returns with 400 code and a custom error message.
4543
4644
The method is called if one of the required parameters are missing or invalid.
@@ -49,13 +47,12 @@ class BeaconBadRequest(BeaconError):
4947

5048
def __init__(self, request, host, error):
5149
"""Return custom bad request exception."""
52-
data = super().__init__(request, host, 400, error)
53-
54-
LOG.error(f'400 ERROR MESSAGE: {error}')
55-
raise web.HTTPBadRequest(content_type="application/json", text=json.dumps(data))
50+
data = process_exception_data(request, host, 400, error)
51+
super().__init__(text=json.dumps(data), content_type="application/json")
52+
LOG.error(f'401 ERROR MESSAGE: {error}')
5653

5754

58-
class BeaconUnauthorised(BeaconError):
55+
class BeaconUnauthorised(web.HTTPUnauthorized):
5956
"""HTTP Exception returns with 401 code with a custom error message.
6057
6158
The method is called if the user is not registered or if the token from the authentication has expired.
@@ -64,17 +61,17 @@ class BeaconUnauthorised(BeaconError):
6461

6562
def __init__(self, request, host, error, error_message):
6663
"""Return custom unauthorized exception."""
67-
data = super().__init__(request, host, 401, error)
64+
data = process_exception_data(request, host, 401, error)
6865
headers_401 = {"WWW-Authenticate": f"Bearer realm=\"{CONFIG_INFO.url}\"\n\
6966
error=\"{error}\"\n\
7067
error_description=\"{error_message}\""}
68+
super().__init__(content_type="application/json", text=json.dumps(data),
69+
# we use auth scheme Bearer by default
70+
headers=headers_401)
7171
LOG.error(f'401 ERROR MESSAGE: {error}')
72-
raise web.HTTPUnauthorized(content_type="application/json", text=json.dumps(data),
73-
# we use auth scheme Bearer by default
74-
headers=headers_401)
7572

7673

77-
class BeaconForbidden(BeaconError):
74+
class BeaconForbidden(web.HTTPForbidden):
7875
"""HTTP Exception returns with 403 code with the error message.
7976
8077
`'Resource not granted for authenticated user or resource protected for all users.'`.
@@ -84,13 +81,12 @@ class BeaconForbidden(BeaconError):
8481

8582
def __init__(self, request, host, error):
8683
"""Return custom forbidden exception."""
87-
data = super().__init__(request, host, 403, error)
88-
84+
data = process_exception_data(request, host, 403, error)
85+
super().__init__(content_type="application/json", text=json.dumps(data))
8986
LOG.error(f'403 ERROR MESSAGE: {error}')
90-
raise web.HTTPForbidden(content_type="application/json", text=json.dumps(data))
9187

9288

93-
class BeaconServerError(BeaconError):
89+
class BeaconServerError(web.HTTPInternalServerError):
9490
"""HTTP Exception returns with 500 code with the error message.
9591
9692
The 500 error is not specified by the Beacon API, thus as simple error would do.
@@ -100,6 +96,5 @@ def __init__(self, error):
10096
"""Return custom forbidden exception."""
10197
data = {'errorCode': 500,
10298
'errorMessage': error}
103-
99+
super().__init__(content_type="application/json", text=json.dumps(data))
104100
LOG.error(f'500 ERROR MESSAGE: {error}')
105-
raise web.HTTPInternalServerError(content_type="application/json", text=json.dumps(data))

beacon_api/conf/config.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
title=GA4GHBeacon at CSC
88

99
# Version of the Beacon implementation
10-
version=1.4.1
10+
version=1.5.0
1111

1212
# Author of this software
1313
author=CSC developers

0 commit comments

Comments
 (0)