Skip to content

Commit

Permalink
Merge branch 'main' into dev
Browse files Browse the repository at this point in the history
* main: (21 commits)
  web: manage stacked modals with a stack (#9193)
  website/docs: ensure yaml code blocks have language tags (#9240)
  blueprints: only create default brand if no other default brand exists (#9222)
  web: bump API Client version (#9239)
  website/integrations: portainer: Fix Redirect URL mismatch (#9226)
  api: fix authentication schema (#9238)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#9229)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#9230)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#9228)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#9231)
  core: bump pydantic from 2.6.4 to 2.7.0 (#9232)
  core: bump ruff from 0.3.5 to 0.3.7 (#9233)
  web: bump @sentry/browser from 7.109.0 to 7.110.0 in /web in the sentry group (#9234)
  website: bump @types/react from 18.2.75 to 18.2.77 in /website (#9236)
  core, web: update translations (#9225)
  website/integrations: add pfSense search scope (#9221)
  core: bump idna from 3.6 to 3.7 (#9224)
  website/docs: add websocket support to nginx snippets (#9220)
  internal: add tests to go flow executor (#9219)
  website/integrations: nextcloud: add tip to solve hashed groups configuring OAuth2 (#9153)
  ...
  • Loading branch information
kensternberg-authentik committed Apr 12, 2024
2 parents cacdf64 + 8e4929c commit 085debf
Show file tree
Hide file tree
Showing 68 changed files with 1,065 additions and 447 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/repo-stale.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
repo-token: ${{ steps.generate_token.outputs.token }}
days-before-stale: 60
days-before-close: 7
exempt-issue-labels: pinned,security,pr_wanted,enhancement,bug/confirmed,enhancement/confirmed,question
exempt-issue-labels: pinned,security,pr_wanted,enhancement,bug/confirmed,enhancement/confirmed,question,status/reviewing
stale-issue-label: wontfix
stale-issue-message: >
This issue has been automatically marked as stale because it has not had
Expand Down
23 changes: 0 additions & 23 deletions authentik/api/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,3 @@ class AuthentikAPIConfig(AppConfig):
label = "authentik_api"
mountpoint = "api/"
verbose_name = "authentik API"

def ready(self) -> None:
from drf_spectacular.extensions import OpenApiAuthenticationExtension

from authentik.api.authentication import TokenAuthentication

# Class is defined here as it needs to be created early enough that drf-spectacular will
# find it, but also won't cause any import issues

class TokenSchema(OpenApiAuthenticationExtension):
"""Auth schema"""

target_class = TokenAuthentication
name = "authentik"

def get_security_definition(self, auto_schema):
"""Auth schema"""
return {
"type": "apiKey",
"in": "header",
"name": "Authorization",
"scheme": "bearer",
}
12 changes: 12 additions & 0 deletions authentik/api/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from typing import Any

from django.conf import settings
from drf_spectacular.extensions import OpenApiAuthenticationExtension
from rest_framework.authentication import BaseAuthentication, get_authorization_header
from rest_framework.exceptions import AuthenticationFailed
from rest_framework.request import Request
Expand Down Expand Up @@ -102,3 +103,14 @@ def authenticate(self, request: Request) -> tuple[User, Any] | None:
return None

return (user, None) # pragma: no cover


class TokenSchema(OpenApiAuthenticationExtension):
"""Auth schema"""

target_class = TokenAuthentication
name = "authentik"

def get_security_definition(self, auto_schema):
"""Auth schema"""
return {"type": "http", "scheme": "bearer"}
21 changes: 21 additions & 0 deletions authentik/root/test_plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from os import environ

import pytest

from authentik import get_full_version

IS_CI = "CI" in environ


@pytest.hookimpl(hookwrapper=True)
def pytest_sessionstart(*_, **__):
"""Clear the console ahead of the pytest output starting"""
if not IS_CI:
print("\x1b[2J\x1b[H")
yield


@pytest.hookimpl(trylast=True)
def pytest_report_header(*_, **__):
"""Add authentik version to pytest output"""
return [f"authentik version: {get_full_version()}"]
3 changes: 1 addition & 2 deletions authentik/root/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from argparse import ArgumentParser
from unittest import TestCase

import pytest
from django.conf import settings
from django.test.runner import DiscoverRunner

Expand Down Expand Up @@ -105,6 +106,4 @@ def run_tests(self, test_labels, extra_tests=None, **kwargs):
f"path instead."
)

import pytest

return pytest.main(self.args)
3 changes: 2 additions & 1 deletion authentik/stages/user_login/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,14 @@ def test_expiry_remember(self):
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
data={"remember_me": True},
)
_now = now().timestamp()
self.assertEqual(response.status_code, 200)
self.assertStageRedirects(response, reverse("authentik_core:root-redirect"))
self.assertNotEqual(list(self.client.session.keys()), [])
session_key = self.client.session.session_key
session = AuthenticatedSession.objects.filter(session_key=session_key).first()
self.assertAlmostEqual(
session.expires.timestamp() - now().timestamp(),
session.expires.timestamp() - _now,
timedelta_from_string(self.stage.session_duration).total_seconds()
+ timedelta_from_string(self.stage.remember_me_offset).total_seconds(),
delta=1,
Expand Down
5 changes: 4 additions & 1 deletion blueprints/default/default-brand.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ entries:
!Find [authentik_flows.flow, [slug, default-user-settings-flow]]
identifiers:
domain: authentik-default
default: True
default: true
state: created
conditions:
# Only create default brand if no other default brand exists
- !Condition [NOR, !Find [authentik_brands.brand, [default, True]]]
model: authentik_brands.brand
4 changes: 3 additions & 1 deletion internal/outpost/flow/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ func NewFlowExecutor(ctx context.Context, flowSlug string, refConfig *api.Config
Jar: jar,
Transport: fe,
}
fe.token = strings.Split(refConfig.DefaultHeader["Authorization"], " ")[1]
if authz, ok := refConfig.DefaultHeader["Authorization"]; ok {
fe.token = strings.Split(authz, " ")[1]
}
config.AddDefaultHeader(HeaderAuthentikOutpostToken, fe.token)
fe.api = api.NewAPIClient(config)
return fe
Expand Down
68 changes: 68 additions & 0 deletions internal/outpost/flow/solvers_mfa_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package flow_test

import (
"context"
"encoding/base64"
"fmt"
"strconv"
"testing"

"github.com/gorilla/securecookie"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"goauthentik.io/api/v3"
"goauthentik.io/internal/outpost/flow"
)

func testSecret() string {
return base64.RawURLEncoding.EncodeToString(securecookie.GenerateRandomKey(32))
}

func TestFlowExecutor_SetSecrets_Plain(t *testing.T) {
fe := flow.NewFlowExecutor(context.TODO(), "", api.NewConfiguration(), logrus.Fields{})
pw := testSecret()
fe.SetSecrets(pw, false)
assert.Equal(t, pw, fe.Answers[flow.StagePassword])
assert.Equal(t, pw, fe.Answers[flow.StageAuthenticatorValidate])
}

func TestFlowExecutor_SetSecrets_TOTP_6(t *testing.T) {
fe := flow.NewFlowExecutor(context.TODO(), "", api.NewConfiguration(), logrus.Fields{})
pw := testSecret()
totp := 123456
formatted := fmt.Sprintf("%s%s%d", pw, flow.CodePasswordSeparator, totp)
fe.SetSecrets(formatted, true)
assert.Equal(t, pw, fe.Answers[flow.StagePassword])
assert.Equal(t, strconv.Itoa(totp), fe.Answers[flow.StageAuthenticatorValidate])
}

func TestFlowExecutor_SetSecrets_TOTP_8(t *testing.T) {
fe := flow.NewFlowExecutor(context.TODO(), "", api.NewConfiguration(), logrus.Fields{})
pw := testSecret()
totp := 12345678
formatted := fmt.Sprintf("%s%s%d", pw, flow.CodePasswordSeparator, totp)
fe.SetSecrets(formatted, true)
assert.Equal(t, pw, fe.Answers[flow.StagePassword])
assert.Equal(t, strconv.Itoa(totp), fe.Answers[flow.StageAuthenticatorValidate])
}

func TestFlowExecutor_SetSecrets_TOTP_TooLong(t *testing.T) {
fe := flow.NewFlowExecutor(context.TODO(), "", api.NewConfiguration(), logrus.Fields{})
pw := testSecret()
totp := 1234567890
formatted := fmt.Sprintf("%s%s%d", pw, flow.CodePasswordSeparator, totp)
fe.SetSecrets(formatted, true)
assert.Equal(t, formatted, fe.Answers[flow.StagePassword])
assert.Equal(t, "", fe.Answers[flow.StageAuthenticatorValidate])
}

func TestFlowExecutor_SetSecrets_TOTP_NoCode(t *testing.T) {
fe := flow.NewFlowExecutor(context.TODO(), "", api.NewConfiguration(), logrus.Fields{})
pw := testSecret()
fe.SetSecrets(pw, true)
assert.Equal(t, pw, fe.Answers[flow.StagePassword])
assert.Equal(t, "", fe.Answers[flow.StageAuthenticatorValidate])
fe.SetSecrets(pw+flow.CodePasswordSeparator, true)
assert.Equal(t, pw, fe.Answers[flow.StagePassword])
assert.Equal(t, "", fe.Answers[flow.StageAuthenticatorValidate])
}
25 changes: 19 additions & 6 deletions locale/en/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-04-09 00:08+0000\n"
"POT-Creation-Date: 2024-04-12 00:07+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
Expand Down Expand Up @@ -2186,6 +2186,12 @@ msgid ""
"again."
msgstr ""

#: authentik/stages/authenticator_validate/challenge.py
#: authentik/stages/authenticator_webauthn/stage.py
#, python-brace-format
msgid "Invalid device type. Contact your {brand} administrator for help."
msgstr ""

#: authentik/stages/authenticator_validate/models.py
msgid "Static"
msgstr ""
Expand Down Expand Up @@ -2235,6 +2241,10 @@ msgstr ""
msgid "Authenticator Validation Stages"
msgstr ""

#: authentik/stages/authenticator_validate/stage.py
msgid "No (allowed) MFA authenticator configured."
msgstr ""

#: authentik/stages/authenticator_webauthn/models.py
msgid "WebAuthn Authenticator Setup Stage"
msgstr ""
Expand All @@ -2259,11 +2269,6 @@ msgstr ""
msgid "WebAuthn Device types"
msgstr ""

#: authentik/stages/authenticator_webauthn/stage.py
#, python-brace-format
msgid "Invalid device type. Contact your {brand} administrator for help."
msgstr ""

#: authentik/stages/captcha/models.py
msgid "Public key, acquired your captcha Provider."
msgstr ""
Expand Down Expand Up @@ -2846,6 +2851,14 @@ msgstr ""
msgid "Globally enable/disable impersonation."
msgstr ""

#: authentik/tenants/models.py
msgid "Default token duration"
msgstr ""

#: authentik/tenants/models.py
msgid "Default token length"
msgstr ""

#: authentik/tenants/models.py
msgid "Tenant"
msgstr ""
Expand Down
Binary file modified locale/zh-Hans/LC_MESSAGES/django.mo
Binary file not shown.
25 changes: 19 additions & 6 deletions locale/zh-Hans/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-04-09 00:08+0000\n"
"POT-Creation-Date: 2024-04-12 00:07+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: deluxghost, 2024\n"
"Language-Team: Chinese Simplified (https://app.transifex.com/authentik/teams/119923/zh-Hans/)\n"
Expand Down Expand Up @@ -2222,6 +2222,12 @@ msgid ""
"again."
msgstr "无效的令牌。请确保设备上的时间准确并重试。"

#: authentik/stages/authenticator_validate/challenge.py
#: authentik/stages/authenticator_webauthn/stage.py
#, python-brace-format
msgid "Invalid device type. Contact your {brand} administrator for help."
msgstr "无效的设备类型。请联系您的 {brand} 管理员获得帮助。"

#: authentik/stages/authenticator_validate/models.py
msgid "Static"
msgstr "静态"
Expand Down Expand Up @@ -2271,6 +2277,10 @@ msgstr "身份验证器验证阶段"
msgid "Authenticator Validation Stages"
msgstr "身份验证器验证阶段"

#: authentik/stages/authenticator_validate/stage.py
msgid "No (allowed) MFA authenticator configured."
msgstr "未配置(允许的)MFA 身份验证器。"

#: authentik/stages/authenticator_webauthn/models.py
msgid "WebAuthn Authenticator Setup Stage"
msgstr "WebAuthn 身份验证器设置阶段"
Expand All @@ -2295,11 +2305,6 @@ msgstr "WebAuthn 设备类型"
msgid "WebAuthn Device types"
msgstr "WebAuthn 设备类型"

#: authentik/stages/authenticator_webauthn/stage.py
#, python-brace-format
msgid "Invalid device type. Contact your {brand} administrator for help."
msgstr "无效的设备类型。请联系您的 {brand} 管理员获得帮助。"

#: authentik/stages/captcha/models.py
msgid "Public key, acquired your captcha Provider."
msgstr "公钥,从您的验证码提供商处取得。"
Expand Down Expand Up @@ -2902,6 +2907,14 @@ msgstr "启用时,所有由用户造成的事件会在相应用户被删除时
msgid "Globally enable/disable impersonation."
msgstr "全局启用/禁用模拟身份。"

#: authentik/tenants/models.py
msgid "Default token duration"
msgstr "默认令牌持续时间"

#: authentik/tenants/models.py
msgid "Default token length"
msgstr "默认令牌长度"

#: authentik/tenants/models.py
msgid "Tenant"
msgstr "租户"
Expand Down
25 changes: 19 additions & 6 deletions locale/zh_CN/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-04-09 00:08+0000\n"
"POT-Creation-Date: 2024-04-12 00:07+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: deluxghost, 2024\n"
"Language-Team: Chinese (China) (https://app.transifex.com/authentik/teams/119923/zh_CN/)\n"
Expand Down Expand Up @@ -2222,6 +2222,12 @@ msgid ""
"again."
msgstr "无效的令牌。请确保设备上的时间准确并重试。"

#: authentik/stages/authenticator_validate/challenge.py
#: authentik/stages/authenticator_webauthn/stage.py
#, python-brace-format
msgid "Invalid device type. Contact your {brand} administrator for help."
msgstr "无效的设备类型。请联系您的 {brand} 管理员获得帮助。"

#: authentik/stages/authenticator_validate/models.py
msgid "Static"
msgstr "静态"
Expand Down Expand Up @@ -2271,6 +2277,10 @@ msgstr "身份验证器验证阶段"
msgid "Authenticator Validation Stages"
msgstr "身份验证器验证阶段"

#: authentik/stages/authenticator_validate/stage.py
msgid "No (allowed) MFA authenticator configured."
msgstr "未配置(允许的)MFA 身份验证器。"

#: authentik/stages/authenticator_webauthn/models.py
msgid "WebAuthn Authenticator Setup Stage"
msgstr "WebAuthn 身份验证器设置阶段"
Expand All @@ -2295,11 +2305,6 @@ msgstr "WebAuthn 设备类型"
msgid "WebAuthn Device types"
msgstr "WebAuthn 设备类型"

#: authentik/stages/authenticator_webauthn/stage.py
#, python-brace-format
msgid "Invalid device type. Contact your {brand} administrator for help."
msgstr "无效的设备类型。请联系您的 {brand} 管理员获得帮助。"

#: authentik/stages/captcha/models.py
msgid "Public key, acquired your captcha Provider."
msgstr "公钥,从您的验证码提供商处取得。"
Expand Down Expand Up @@ -2902,6 +2907,14 @@ msgstr "启用时,所有由用户造成的事件会在相应用户被删除时
msgid "Globally enable/disable impersonation."
msgstr "全局启用/禁用模拟身份。"

#: authentik/tenants/models.py
msgid "Default token duration"
msgstr "默认令牌持续时间"

#: authentik/tenants/models.py
msgid "Default token length"
msgstr "默认令牌长度"

#: authentik/tenants/models.py
msgid "Tenant"
msgstr "租户"
Expand Down
Loading

0 comments on commit 085debf

Please sign in to comment.