From 4f01004bba2422ec992a06821e5337a4bfc959fe Mon Sep 17 00:00:00 2001 From: Michael Olund Date: Fri, 6 Nov 2020 14:21:24 -0800 Subject: [PATCH] DIV-1015 - Started to refactor eFiling HUB to super class for location API support --- .../core/tests/test_efiling_submission.py | 4 +- edivorce/apps/core/utils/efiling_hub_api.py | 114 +++++++++++++++++ .../apps/core/utils/efiling_submission.py | 116 ++---------------- 3 files changed, 126 insertions(+), 108 deletions(-) create mode 100644 edivorce/apps/core/utils/efiling_hub_api.py diff --git a/edivorce/apps/core/tests/test_efiling_submission.py b/edivorce/apps/core/tests/test_efiling_submission.py index 5910b38e..c86832f3 100644 --- a/edivorce/apps/core/tests/test_efiling_submission.py +++ b/edivorce/apps/core/tests/test_efiling_submission.py @@ -112,7 +112,7 @@ class EFilingSubmissionTests(TransactionTestCase): self.hub.access_token = 'aslkfjadskfjd' response = self.hub._get_api( - self.request, 'https://somewhere.com', 'alksdjfa', 'kasdkfd', {}) + self.request, 'https://somewhere.com', 'alksdjfa') self.assertTrue(response) self.assertEqual(response.status_code, 200) @@ -132,7 +132,7 @@ class EFilingSubmissionTests(TransactionTestCase): ] response = self.hub._get_api( - self.request, 'https://somewhere.com', 'alksdjfa', 'kasdkfd', {}) + self.request, 'https://somewhere.com', 'alksdjfa') self.assertTrue(response) self.assertEqual(response.status_code, 200) diff --git a/edivorce/apps/core/utils/efiling_hub_api.py b/edivorce/apps/core/utils/efiling_hub_api.py new file mode 100644 index 00000000..7cd2c312 --- /dev/null +++ b/edivorce/apps/core/utils/efiling_hub_api.py @@ -0,0 +1,114 @@ +import json +import logging +import requests +import uuid + +from django.conf import settings +from django.core.exceptions import PermissionDenied + +from .efiling_packaging import EFilingPackaging + +logger = logging.getLogger(__name__) + + +class EFilingHubApi: + + def __init__(self): + self.client_id = settings.EFILING_HUB_KEYCLOAK_CLIENT_ID + self.client_secret = settings.EFILING_HUB_KEYCLOAK_SECRET + self.token_base_url = settings.EFILING_HUB_KEYCLOAK_BASE_URL + self.token_realm = settings.EFILING_HUB_KEYCLOAK_REALM + self.api_base_url = settings.EFILING_HUB_API_BASE_URL + self.access_token = None + self.refresh_token = None + + def _get_token(self, request): + payload = f'client_id={self.client_id}&grant_type=client_credentials&client_secret={self.client_secret}' + headers = {'Content-Type': 'application/x-www-form-urlencoded'} + + url = f'{self.token_base_url}/auth/realms/{self.token_realm}/protocol/openid-connect/token' + + response = requests.post(url, headers=headers, data=payload) + logging.debug(f'EFH - Get Token {response.status_code}') + if response.status_code == 200: + response = json.loads(response.text) + + # save token as object property.. + if 'access_token' in response: + self.access_token = response['access_token'] + if 'refresh_token' in response: + self.refresh_token = response['refresh_token'] + + return True + return False + + def _refresh_token(self, request): + if not self.refresh_token: + return False + + payload = f'client_id={self.client_id}&grant_type=refresh_token&client_secret={self.client_secret}&refresh_token={self.refresh_token}' + headers = {'Content-Type': 'application/x-www-form-urlencoded'} + + url = f'{self.token_base_url}/auth/realms/{self.token_realm}/protocol/openid-connect/token' + + response = requests.post(url, headers=headers, data=payload) + logging.debug(f'EFH - Get Refresh Token {response.status_code}') + + response = json.loads(response.text) + + # save in session .. lets just assume that current user is authenticated + if 'access_token' in response: + self.access_token = response['access_token'] + if 'refresh_token' in response: + self.refresh_token = response['refresh_token'] + + return True + return False + + def _get_api(self, request, url, bceid_guid, headers={}, data=None, transaction_id=None, files=None): + # make sure we have an access token + if not self.access_token: + if not self._get_token(request): + raise Exception('EFH - Unable to get API Token') + + headers.update({ + 'X-Transaction-Id': transaction_id, + 'X-User-Id': bceid_guid, + 'Authorization': f'Bearer {self.access_token}' + }) + + if not data: + data = {} + + response = requests.post(url, headers=headers, data=data, files=files) + logging.debug(f'EFH - Get API {response.status_code} {response.text}') + + if response.status_code == 401: + # not authorized .. try refreshing token + if self._refresh_token(request): + headers.update({ + 'X-Transaction-Id': transaction_id, + 'X-User-Id': bceid_guid, + 'Authorization': f'Bearer {self.access_token}' + }) + + response = requests.post(url, headers=headers, data=data, files=files) + logging.debug(f'EFH - Get API Retry {response.status_code} {response.text}') + + return response + + def _get_bceid(self, request): + + def _get_raw_bceid(request): + if settings.DEPLOYMENT_TYPE == 'localdev': + # to integrate with the Test eFiling Hub, we need a valid BCEID which is + # unavailable for a local eDivorce environment. Use an env specified mapping + # to figure out what we should pass through to eFiling Hub. This BCEID username + # needs to match with what you will be logging in with to the Test BCEID environment. + return settings.EFILING_BCEID + return request.session.get('bcgov_userguid', None) + + guid = _get_raw_bceid(request) + if guid: + return str(uuid.UUID(guid)) + return guid diff --git a/edivorce/apps/core/utils/efiling_submission.py b/edivorce/apps/core/utils/efiling_submission.py index 5f94ae7d..23c59997 100644 --- a/edivorce/apps/core/utils/efiling_submission.py +++ b/edivorce/apps/core/utils/efiling_submission.py @@ -7,102 +7,20 @@ from django.conf import settings from django.core.exceptions import PermissionDenied from .efiling_packaging import EFilingPackaging +from .efiling_hub_api import EFilingHubApi logger = logging.getLogger(__name__) -class EFilingSubmission: +class EFilingSubmission(EFilingHubApi): def __init__(self, initial_filing): - self.client_id = settings.EFILING_HUB_KEYCLOAK_CLIENT_ID - self.client_secret = settings.EFILING_HUB_KEYCLOAK_SECRET - self.token_base_url = settings.EFILING_HUB_KEYCLOAK_BASE_URL - self.token_realm = settings.EFILING_HUB_KEYCLOAK_REALM - self.api_base_url = settings.EFILING_HUB_API_BASE_URL self.initial_filing = initial_filing self.packaging = EFilingPackaging(initial_filing) self.submission_id = None self.access_token = None self.refresh_token = None - - def _get_token(self, request): - payload = f'client_id={self.client_id}&grant_type=client_credentials&client_secret={self.client_secret}' - headers = {'Content-Type': 'application/x-www-form-urlencoded'} - - url = f'{self.token_base_url}/auth/realms/{self.token_realm}/protocol/openid-connect/token' - - try: - response = requests.post(url, headers=headers, data=payload) - except: - return False - - logging.debug(f'EFH - Get Token {response.status_code}') - if response.status_code == 200: - response = json.loads(response.text) - - # save token as object property.. - if 'access_token' in response: - self.access_token = response['access_token'] - if 'refresh_token' in response: - self.refresh_token = response['refresh_token'] - - return True - return False - - def _refresh_token(self, request): - if not self.refresh_token: - return False - - payload = f'client_id={self.client_id}&grant_type=refresh_token&client_secret={self.client_secret}&refresh_token={self.refresh_token}' - headers = {'Content-Type': 'application/x-www-form-urlencoded'} - - url = f'{self.token_base_url}/auth/realms/{self.token_realm}/protocol/openid-connect/token' - - response = requests.post(url, headers=headers, data=payload) - logging.debug(f'EFH - Get Refresh Token {response.status_code}') - - response = json.loads(response.text) - - # save in session .. lets just assume that current user is authenticated - if 'access_token' in response: - self.access_token = response['access_token'] - if 'refresh_token' in response: - self.refresh_token = response['refresh_token'] - - return True - return False - - def _get_api(self, request, url, transaction_id, bce_id, headers, data=None, files=None): - # make sure we have an access token - if not self.access_token: - if not self._get_token(request): - raise Exception('EFH - Unable to get API Token') - - headers.update({ - 'X-Transaction-Id': transaction_id, - 'X-User-Id': bce_id, - 'Authorization': f'Bearer {self.access_token}' - }) - - if not data: - data = {} - - response = requests.post(url, headers=headers, data=data, files=files) - logging.debug(f'EFH - Get API {response.status_code} {response.text}') - - if response.status_code == 401: - # not authorized .. try refreshing token - if self._refresh_token(request): - headers.update({ - 'X-Transaction-Id': transaction_id, - 'X-User-Id': bce_id, - 'Authorization': f'Bearer {self.access_token}' - }) - - response = requests.post(url, headers=headers, data=data, files=files) - logging.debug(f'EFH - Get API Retry {response.status_code} {response.text}') - - return response + EFilingHubApi.__init__(self) def _get_transaction(self, request): """ @@ -116,22 +34,6 @@ class EFilingSubmission: request.session['transaction_id'] = guid return guid - def _get_bceid(self, request): - - def _get_raw_bceid(request): - if settings.DEPLOYMENT_TYPE == 'localdev': - # to integrate with the Test eFiling Hub, we need a valid BCEID which is - # unavailable for a local eDivorce environment. Use an env specified mapping - # to figure out what we should pass through to eFiling Hub. This BCEID username - # needs to match with what you will be logging in with to the Test BCEID environment. - return settings.EFILING_BCEID - return request.session.get('bcgov_userguid', None) - - guid = _get_raw_bceid(request) - if guid: - return str(uuid.UUID(guid)) - return guid - def upload(self, request, responses, files, documents=None, parties=None): """ Does an initial upload of documents and gets the generated eFiling Hub url. @@ -144,16 +46,17 @@ class EFilingSubmission: # will tie it to the session. transaction_id = self._get_transaction(request) - bce_id = self._get_bceid(request) + bceid_guid = self._get_bceid(request) - # if bce_id is None .. we basically have an anonymous user so raise an error - if bce_id is None: + # if bceid_guid is None .. we basically have an anonymous user so raise an error + if bceid_guid is None: raise PermissionDenied() url = f'{self.api_base_url}/submission/documents' print('DEBUG: ' + url) try: - response = self._get_api(request, url, transaction_id, bce_id, headers={}, files=files) + response = self._get_api(request, url, transaction_id, + bceid_guid, headers={}, files=files) except: return settings.FORCE_SCRIPT_NAME + "dashboard/initial_filing?no_connection=1", None @@ -170,7 +73,8 @@ class EFilingSubmission: print('DEBUG: ' + url) data = json.dumps(package_data) print('DEBUG: ' + data) - response = self._get_api(request, url, transaction_id, bce_id, headers, data) + response = self._get_api(request, url, bceid_guid, headers=headers, + transaction_id=transaction_id, data=data) if response.status_code == 200: response = json.loads(response.text)