stages/authenticator_sms: fix twilio sending, add test (#4829)
closes #4823 Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
parent
ba9cafecc5
commit
7b44d8972f
|
@ -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),
|
||||||
)
|
)
|
||||||
|
|
|
@ -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(
|
||||||
|
|
Reference in New Issue