stages/authenticator_sms: fix twilio sending, add test (#4829)

closes #4823

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L 2023-03-02 14:39:28 +01:00 committed by GitHub
parent ba9cafecc5
commit 7b44d8972f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 62 additions and 3 deletions

View File

@ -86,7 +86,7 @@ class AuthenticatorSMSStage(ConfigurableStage, Stage):
try: try:
message = client.messages.create( message = client.messages.create(
to=device.phone_number, from_=self.from_number, body=self.get_message(token) to=device.phone_number, from_=self.from_number, body=str(self.get_message(token))
) )
LOGGER.debug("Sent SMS", to=device, message=message.sid) LOGGER.debug("Sent SMS", to=device, message=message.sid)
except TwilioRestException as exc: except TwilioRestException as exc:
@ -115,13 +115,13 @@ class AuthenticatorSMSStage(ConfigurableStage, Stage):
if self.auth_type == SMSAuthTypes.BEARER: if self.auth_type == SMSAuthTypes.BEARER:
response = get_http_session().post( response = get_http_session().post(
f"{self.account_sid}", self.account_sid,
json=payload, json=payload,
headers={"Authorization": f"Bearer {self.auth}"}, headers={"Authorization": f"Bearer {self.auth}"},
) )
elif self.auth_type == SMSAuthTypes.BASIC: elif self.auth_type == SMSAuthTypes.BASIC:
response = get_http_session().post( response = get_http_session().post(
f"{self.account_sid}", self.account_sid,
json=payload, json=payload,
auth=(self.auth, self.auth_password), auth=(self.auth, self.auth_password),
) )

View File

@ -1,17 +1,21 @@
"""Test SMS API""" """Test SMS API"""
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
from urllib.parse import parse_qsl
from django.urls import reverse from django.urls import reverse
from requests_mock import Mocker
from authentik.core.tests.utils import create_test_admin_user, create_test_flow from authentik.core.tests.utils import create_test_admin_user, create_test_flow
from authentik.flows.models import FlowStageBinding from authentik.flows.models import FlowStageBinding
from authentik.flows.tests import FlowTestCase from authentik.flows.tests import FlowTestCase
from authentik.lib.generators import generate_id
from authentik.stages.authenticator_sms.models import ( from authentik.stages.authenticator_sms.models import (
AuthenticatorSMSStage, AuthenticatorSMSStage,
SMSDevice, SMSDevice,
SMSProviders, SMSProviders,
hash_phone_number, hash_phone_number,
) )
from authentik.stages.authenticator_sms.stage import SESSION_KEY_SMS_DEVICE
class AuthenticatorSMSStageTests(FlowTestCase): class AuthenticatorSMSStageTests(FlowTestCase):
@ -80,6 +84,61 @@ class AuthenticatorSMSStageTests(FlowTestCase):
phone_number_required=False, phone_number_required=False,
) )
def test_stage_submit_twilio(self):
"""test stage (submit) (twilio)"""
self.stage.account_sid = generate_id()
self.stage.auth = generate_id()
self.stage.from_number = generate_id()
self.stage.save()
self.client.get(
reverse("authentik_flows:configure", kwargs={"stage_uuid": self.stage.stage_uuid}),
)
response = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
)
self.assertStageResponse(
response,
self.flow,
self.user,
component="ak-stage-authenticator-sms",
phone_number_required=True,
)
number = generate_id()
with Mocker() as mocker:
mocker.post(
(
"https://api.twilio.com/2010-04-01/Accounts/"
f"{self.stage.account_sid}/Messages.json"
),
json={},
)
response = self.client.post(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
data={"component": "ak-stage-authenticator-sms", "phone_number": number},
)
self.assertEqual(response.status_code, 200)
self.assertEqual(mocker.call_count, 1)
self.assertEqual(mocker.request_history[0].method, "POST")
request_body = dict(parse_qsl(mocker.request_history[0].body))
device: SMSDevice = self.client.session[SESSION_KEY_SMS_DEVICE]
self.assertEqual(
request_body,
{
"To": number,
"From": self.stage.from_number,
"Body": f"Use this code to authenticate in authentik: {device.token}",
},
)
self.assertStageResponse(
response,
self.flow,
self.user,
component="ak-stage-authenticator-sms",
response_errors={},
phone_number_required=False,
)
def test_stage_context_data(self): def test_stage_context_data(self):
"""test stage context data""" """test stage context data"""
self.client.get( self.client.get(