diff --git a/eox_nelp/api_clients/authenticators.py b/eox_nelp/api_clients/authenticators.py index 2f2f9932..00ecad77 100644 --- a/eox_nelp/api_clients/authenticators.py +++ b/eox_nelp/api_clients/authenticators.py @@ -127,3 +127,37 @@ def authenticate(self, api_client): ) return session + + +class Oauth2BasicAuthenticator(BasicAuthAuthenticator): + """Authenticator for custom use using basic auth to get a Oauth2 Token (Bearer or JWT). + Token_type on depends of the response used after the oauth2 token request. + Then the token is used for the next requests. + """ + + def authenticate(self, api_client): + """Authenticate the session with basic auth in order to get token(Bearer or JWT). + Then the token is added to a new session Headers. + Is needed the user, password and token_path class atrributes to the get oauth2 token, + based on the client configuration. + """ + auth_session = super().authenticate(api_client) + key = f"oauth2-basic-{api_client.user}-{api_client.password}" + headers = cache.get(key) + + if not headers: + authenticate_url = f"{api_client.base_url}/{api_client.token_path}" + response = auth_session.post( + url=authenticate_url, + data={"grant_type": "client_credentials", "scope": "notification"} + ).json() + headers = { + "Authorization": f"{response.get('token_type')} {response.get('access_token')}" + } + + cache.set(key, headers, int(response.get("expires_in", 300))) + + session = requests.Session() + session.headers.update(headers) + + return session diff --git a/eox_nelp/api_clients/sms_vendor.py b/eox_nelp/api_clients/sms_vendor.py index 14494db1..9edf3e55 100644 --- a/eox_nelp/api_clients/sms_vendor.py +++ b/eox_nelp/api_clients/sms_vendor.py @@ -6,6 +6,7 @@ from django.conf import settings from eox_nelp.api_clients import AbstractAPIRestClient +from eox_nelp.api_clients.authenticators import Oauth2BasicAuthenticator try: from eox_audit_model.decorators import audit_method @@ -17,11 +18,19 @@ def audit_method(action): # pylint: disable=unused-argument class SMSVendorApiClient(AbstractAPIRestClient): """Allow to perform SMS send operations.""" + authentication_class = Oauth2BasicAuthenticator @property def base_url(self): return getattr(settings, "SMS_VENDOR_URL") + def __init__(self): + self.user = getattr(settings, "SMS_VENDOR_USERNAME") + self.password = getattr(settings, "SMS_VENDOR_PASSWORD") + self.token_path = getattr(settings, "SMS_VENDOR_TOKEN_PATH") + + super().__init__() + def send_sms(self, recipient, message): """This send SMS using an external Vendor via API. @@ -37,11 +46,8 @@ def send_sms_request(recipient, message): """This is a wrapper that allows to make audit-able the send_SMS method.""" path = getattr(settings, "SMS_VENDOR_SEND_SMS_PATH", "") payload = { - "message": message, - "number": recipient, - "username": getattr(settings, "SMS_VENDOR_USERNAME"), - "password": getattr(settings, "SMS_VENDOR_PASSWORD"), - "sender": getattr(settings, "SMS_VENDOR_MSG_SENDER", "NELC"), + "sms_message": message, + "recipient_number": recipient, } return self.make_post(path, payload) diff --git a/eox_nelp/api_clients/tests/test_sms_vendor.py b/eox_nelp/api_clients/tests/test_sms_vendor.py index 630e9736..ddd97c1f 100644 --- a/eox_nelp/api_clients/tests/test_sms_vendor.py +++ b/eox_nelp/api_clients/tests/test_sms_vendor.py @@ -5,8 +5,7 @@ """ import unittest -from django.conf import settings -from mock import patch +from mock import Mock, patch from eox_nelp.api_clients.sms_vendor import SMSVendorApiClient from eox_nelp.api_clients.tests.mixins import TestRestApiClientMixin @@ -20,6 +19,7 @@ def setUp(self): self.api_class = SMSVendorApiClient @patch.object(SMSVendorApiClient, "make_post") + @patch.object(SMSVendorApiClient, "_authenticate", Mock()) def test_send_sms(self, post_mock): """Test successful post request. @@ -27,21 +27,21 @@ def test_send_sms(self, post_mock): - Response is the expected value """ expected_value = { - "message": "SMS sent =), waiting what would be this field.", - "responseCode": 200, + "message": "Operation completed successfully", + "transaction_id": "50693df-665d-47e1-affb-01076a83b9023427", + "recipient": "+573219990000", + "timestamp": "1720220972275" } post_mock.return_value = expected_value - recipient = 3219802890 + recipient = "+573219990000" message = "This is a message to test SMS integration." api_client = self.api_class() expected_payload = { - "message": message, - "number": recipient, - "username": settings.SMS_VENDOR_USERNAME, - "password": settings.SMS_VENDOR_PASSWORD, - "sender": settings.SMS_VENDOR_MSG_SENDER, + "sms_message": message, + "recipient_number": recipient, } + response = api_client.send_sms(recipient, message) self.assertDictEqual(response, expected_value) - post_mock.assert_called_once_with("", expected_payload) + post_mock.assert_called_once_with("sms/send", expected_payload) diff --git a/eox_nelp/settings/test.py b/eox_nelp/settings/test.py index 15ae03c1..542c0f3a 100644 --- a/eox_nelp/settings/test.py +++ b/eox_nelp/settings/test.py @@ -53,7 +53,8 @@ def plugin_settings(settings): # pylint: disable=function-redefined settings.SMS_VENDOR_URL = 'https://testing.com' settings.SMS_VENDOR_USERNAME = 'test-user' settings.SMS_VENDOR_PASSWORD = 'test-password' - settings.SMS_VENDOR_MSG_SENDER = 'Nelc-test' + settings.SMS_VENDOR_TOKEN_PATH = "oauth2/v1/token" + settings.SMS_VENDOR_SEND_SMS_PATH = 'sms/send' settings.PEARSON_RTI_WSDL_URL = 'https://testing.com' settings.PEARSON_RTI_CERT = '/openedx/certs/cert.p12'