Skip to content

Commit

Permalink
Merge branch 'main' into dev
Browse files Browse the repository at this point in the history
* main: (28 commits)
  web: fix typo in traefik name
  web/admin: disable wizard banner for now (#7294)
  web/admin: small fixes (#7292)
  core: Use branding_title in the end session page (#7282)
  web: bump pyright from 1.1.332 to 1.1.333 in /web (#7287)
  website: bump react-tooltip from 5.21.5 to 5.21.6 in /website (#7283)
  web: bump the sentry group in /web with 2 updates (#7285)
  web: bump the eslint group in /web with 1 update (#7286)
  core: bump ruff from 0.1.1 to 0.1.2 (#7289)
  core: bump pytest from 7.4.2 to 7.4.3 (#7288)
  web: bump the wdio group in /tests/wdio with 3 updates (#7290)
  website/blogs: fixed typo in blog (#7281)
  core: bump pylint from 2.17.7 to 3.0.2 (#7270)
  web: bump the eslint group in /tests/wdio with 2 updates (#7274)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#7278)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#7277)
  ci: bump actions/setup-node from 3 to 4 (#7268)
  core: bump pylint-django from 2.5.4 to 2.5.5 (#7271)
  web: bump the eslint group in /web with 2 updates (#7269)
  web: bump @trivago/prettier-plugin-sort-imports from 4.2.0 to 4.2.1 in /tests/wdio (#7275)
  ...
  • Loading branch information
kensternberg-authentik committed Oct 25, 2023
2 parents 8e89237 + 488420e commit 0449fd0
Show file tree
Hide file tree
Showing 41 changed files with 1,278 additions and 908 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci-outpost.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ jobs:
- uses: actions/setup-go@v4
with:
go-version-file: "go.mod"
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/ci-web.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- tests/wdio
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
Expand All @@ -37,7 +37,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
Expand All @@ -59,7 +59,7 @@ jobs:
- tests/wdio
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
Expand All @@ -75,7 +75,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
Expand Down Expand Up @@ -107,7 +107,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/ci-website.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
Expand All @@ -29,7 +29,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
Expand All @@ -50,7 +50,7 @@ jobs:
- build-docs-only
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ jobs:
- uses: actions/setup-go@v4
with:
go-version-file: "go.mod"
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/web-api-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- uses: actions/checkout@v4
with:
token: ${{ steps.generate_token.outputs.token }}
- uses: actions/setup-node@v3
- uses: actions/setup-node@v4
with:
node-version: "20"
registry-url: "https://registry.npmjs.org"
Expand Down
4 changes: 2 additions & 2 deletions authentik/core/templates/if/end_session.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
{% block card %}
<form method="POST" class="pf-c-form">
<p>
{% blocktrans with application=application.name %}
You've logged out of {{ application }}. You can go back to the overview to launch another application, or log out of your authentik account.
{% blocktrans with application=application.name branding_title=tenant.branding_title %}
You've logged out of {{ application }}. You can go back to the overview to launch another application, or log out of your {{ branding_title }} account.
{% endblocktrans %}
</p>

Expand Down
24 changes: 17 additions & 7 deletions authentik/stages/authenticator_sms/stage.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
Challenge,
ChallengeResponse,
ChallengeTypes,
ErrorDetailSerializer,
WithUserInfoChallenge,
)
from authentik.flows.stage import ChallengeStageView
Expand All @@ -24,6 +23,7 @@
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT

SESSION_KEY_SMS_DEVICE = "authentik/stages/authenticator_sms/sms_device"
PLAN_CONTEXT_PHONE = "phone"


class AuthenticatorSMSChallenge(WithUserInfoChallenge):
Expand All @@ -48,6 +48,8 @@ class AuthenticatorSMSChallengeResponse(ChallengeResponse):
def validate(self, attrs: dict) -> dict:
"""Check"""
if "code" not in attrs:
if "phone_number" not in attrs:
raise ValidationError("phone_number required")
self.device.phone_number = attrs["phone_number"]
self.stage.validate_and_send(attrs["phone_number"])
return super().validate(attrs)
Expand All @@ -67,6 +69,7 @@ def validate_and_send(self, phone_number: str):
stage: AuthenticatorSMSStage = self.executor.current_stage
hashed_number = hash_phone_number(phone_number)
query = Q(phone_number=hashed_number) | Q(phone_number=phone_number)
print(SMSDevice.objects.filter(query, stage=stage.pk))
if SMSDevice.objects.filter(query, stage=stage.pk).exists():
raise ValidationError(_("Invalid phone number"))
# No code yet, but we have a phone number, so send a verification message
Expand All @@ -75,9 +78,9 @@ def validate_and_send(self, phone_number: str):

def _has_phone_number(self) -> Optional[str]:
context = self.executor.plan.context
if "phone" in context.get(PLAN_CONTEXT_PROMPT, {}):
if PLAN_CONTEXT_PHONE in context.get(PLAN_CONTEXT_PROMPT, {}):
self.logger.debug("got phone number from plan context")
return context.get(PLAN_CONTEXT_PROMPT, {}).get("phone")
return context.get(PLAN_CONTEXT_PROMPT, {}).get(PLAN_CONTEXT_PHONE)
if SESSION_KEY_SMS_DEVICE in self.request.session:
self.logger.debug("got phone number from device in session")
device: SMSDevice = self.request.session[SESSION_KEY_SMS_DEVICE]
Expand Down Expand Up @@ -113,10 +116,17 @@ def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
try:
self.validate_and_send(phone_number)
except ValidationError as exc:
response = AuthenticatorSMSChallengeResponse()
response._errors.setdefault("phone_number", [])
response._errors["phone_number"].append(ErrorDetailSerializer(exc.detail))
return self.challenge_invalid(response)
# We had a phone number given already (at this point only possible from flow
# context), but an error occurred while sending a number (most likely)
# due to a duplicate device, so delete the number we got given, reset the state
# (ish) and retry
device.phone_number = ""
self.executor.plan.context.get(PLAN_CONTEXT_PROMPT, {}).pop(
PLAN_CONTEXT_PHONE, None
)
self.request.session.pop(SESSION_KEY_SMS_DEVICE, None)
self.logger.warning("failed to send SMS message to pre-set number", exc=exc)
return self.get(request, *args, **kwargs)
return super().get(request, *args, **kwargs)

def challenge_valid(self, response: ChallengeResponse) -> HttpResponse:
Expand Down
44 changes: 43 additions & 1 deletion authentik/stages/authenticator_sms/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@

from authentik.core.tests.utils import create_test_admin_user, create_test_flow
from authentik.flows.models import FlowStageBinding
from authentik.flows.planner import FlowPlan
from authentik.flows.tests import FlowTestCase
from authentik.flows.views.executor import SESSION_KEY_PLAN
from authentik.lib.generators import generate_id
from authentik.stages.authenticator_sms.models import (
AuthenticatorSMSStage,
SMSDevice,
SMSProviders,
hash_phone_number,
)
from authentik.stages.authenticator_sms.stage import SESSION_KEY_SMS_DEVICE
from authentik.stages.authenticator_sms.stage import PLAN_CONTEXT_PHONE, SESSION_KEY_SMS_DEVICE
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT


class AuthenticatorSMSStageTests(FlowTestCase):
Expand Down Expand Up @@ -172,6 +175,45 @@ def test_stage_context_data(self):
phone_number_required=False,
)

def test_stage_context_data_duplicate(self):
"""test stage context data (phone number exists already)"""
self.client.get(
reverse("authentik_flows:configure", kwargs={"stage_uuid": self.stage.stage_uuid}),
)
plan: FlowPlan = self.client.session[SESSION_KEY_PLAN]
plan.context[PLAN_CONTEXT_PROMPT] = {
PLAN_CONTEXT_PHONE: "1234",
}
session = self.client.session
session[SESSION_KEY_PLAN] = plan
session.save()
SMSDevice.objects.create(
phone_number="1234",
user=self.user,
stage=self.stage,
)
sms_send_mock = MagicMock()
with (
patch(
"authentik.stages.authenticator_sms.models.AuthenticatorSMSStage.send",
sms_send_mock,
),
):
print(self.client.session[SESSION_KEY_PLAN])
response = self.client.get(
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
)
print(response.content.decode())
self.assertStageResponse(
response,
self.flow,
self.user,
component="ak-stage-authenticator-sms",
phone_number_required=True,
)
plan: FlowPlan = self.client.session[SESSION_KEY_PLAN]
self.assertEqual(plan.context[PLAN_CONTEXT_PROMPT], {})

def test_stage_submit_full(self):
"""test stage (submit)"""
self.client.get(
Expand Down
16 changes: 8 additions & 8 deletions lifecycle/migrate.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,20 +51,20 @@ def run(self):
"""Run the actual migration"""


def wait_for_lock():
def wait_for_lock(cursor: Cursor):
"""lock an advisory lock to prevent multiple instances from migrating at once"""
LOGGER.info("waiting to acquire database lock")
curr.execute("SELECT pg_advisory_lock(%s)", (ADV_LOCK_UID,))
cursor.execute("SELECT pg_advisory_lock(%s)", (ADV_LOCK_UID,))
# pylint: disable=global-statement
global LOCKED
LOCKED = True


def release_lock():
def release_lock(cursor: Cursor):
"""Release database lock"""
if not LOCKED:
return
curr.execute("SELECT pg_advisory_unlock(%s)", (ADV_LOCK_UID,))
cursor.execute("SELECT pg_advisory_unlock(%s)", (ADV_LOCK_UID,))


if __name__ == "__main__":
Expand Down Expand Up @@ -93,14 +93,14 @@ def release_lock():
continue
migration = sub(curr, conn)
if migration.needs_migration():
wait_for_lock()
wait_for_lock(curr)
LOGGER.info("Migration needs to be applied", migration=migration_path.name)
migration.run()
LOGGER.info("Migration finished applying", migration=migration_path.name)
release_lock()
release_lock(curr)
LOGGER.info("applying django migrations")
environ.setdefault("DJANGO_SETTINGS_MODULE", "authentik.root.settings")
wait_for_lock()
wait_for_lock(curr)
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
Expand All @@ -111,4 +111,4 @@ def release_lock():
) from exc
execute_from_command_line(["", "migrate"])
finally:
release_lock()
release_lock(curr)
Loading

0 comments on commit 0449fd0

Please sign in to comment.