Skip to content

Commit

Permalink
:wqge branch 'main' into dev
Browse files Browse the repository at this point in the history
* main:
  providers/ldap: fix global search_full_directory permission not being sufficient (#12028)
  website/docs: 2024.10.2 release notes (#12025)
  lifecycle: fix ak exit status not being passed (#12024)
  core: use versioned_script for path only (#12003)
  core, web: update translations (#12020)
  core: bump google-api-python-client from 2.152.0 to 2.153.0 (#12021)
  providers/oauth2: fix manual device code entry (#12017)
  crypto: validate that generated certificate's name is unique (#12015)
  core, web: update translations (#12006)
  core: bump google-api-python-client from 2.151.0 to 2.152.0 (#12007)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#12011)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#12010)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#12012)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#12013)
  providers/proxy: fix Issuer when AUTHENTIK_HOST_BROWSER is set (#11968)
  website/docs: move S3 ad GeoIP to System Management/Operations (#11998)
  website/integrations: nextcloud: add SSE warning (#11976)
  • Loading branch information
kensternberg-authentik committed Nov 14, 2024
2 parents 831797b + c9036f8 commit 36b10b4
Show file tree
Hide file tree
Showing 46 changed files with 491 additions and 54 deletions.
2 changes: 1 addition & 1 deletion authentik/api/templates/api/browser.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
{% endblock %}

{% block head %}
{% versioned_script "dist/standalone/api-browser/index-%v.js" %}
<script src="{% versioned_script 'dist/standalone/api-browser/index-%v.js' %}" type="module"></script>
<meta name="theme-color" content="#151515" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#151515" media="(prefers-color-scheme: dark)">
{% endblock %}
Expand Down
4 changes: 2 additions & 2 deletions authentik/core/templates/base/skeleton.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
{% endblock %}
<link rel="stylesheet" type="text/css" href="{% static 'dist/authentik.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'dist/custom.css' %}" data-inject>
{% versioned_script "dist/poly-%v.js" %}
{% versioned_script "dist/standalone/loading/index-%v.js" %}
<script src="{% versioned_script 'dist/poly-%v.js' %}" type="module"></script>
<script src="{% versioned_script 'dist/standalone/loading/index-%v.js' %}" type="module"></script>
{% block head %}
{% endblock %}
<meta name="sentry-trace" content="{{ sentry_trace }}" />
Expand Down
2 changes: 1 addition & 1 deletion authentik/core/templates/if/admin.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{% load authentik_core %}

{% block head %}
{% versioned_script "dist/admin/AdminInterface-%v.js" %}
<script src="{% versioned_script 'dist/admin/AdminInterface-%v.js' %}" type="module"></script>
<meta name="theme-color" content="#18191a" media="(prefers-color-scheme: dark)">
<meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)">
{% include "base/header_js.html" %}
Expand Down
2 changes: 1 addition & 1 deletion authentik/core/templates/if/user.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{% load authentik_core %}

{% block head %}
{% versioned_script "dist/user/UserInterface-%v.js" %}
<script src="{% versioned_script 'dist/user/UserInterface-%v.js' %}" type="module"></script>
<meta name="theme-color" content="#1c1e21" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#1c1e21" media="(prefers-color-scheme: dark)">
{% include "base/header_js.html" %}
Expand Down
9 changes: 1 addition & 8 deletions authentik/core/templatetags/authentik_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

from django import template
from django.templatetags.static import static as static_loader
from django.utils.safestring import mark_safe

from authentik import get_full_version

Expand All @@ -12,10 +11,4 @@
@register.simple_tag()
def versioned_script(path: str) -> str:
"""Wrapper around {% static %} tag that supports setting the version"""
returned_lines = [
(
f'<script src="{static_loader(path.replace("%v", get_full_version()))}'
'" type="module"></script>'
),
]
return mark_safe("".join(returned_lines)) # nosec
return static_loader(path.replace("%v", get_full_version()))
11 changes: 7 additions & 4 deletions authentik/crypto/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.validators import UniqueValidator
from rest_framework.viewsets import ModelViewSet
from structlog.stdlib import get_logger

Expand Down Expand Up @@ -181,7 +182,10 @@ class CertificateDataSerializer(PassiveSerializer):
class CertificateGenerationSerializer(PassiveSerializer):
"""Certificate generation parameters"""

common_name = CharField()
common_name = CharField(
validators=[UniqueValidator(queryset=CertificateKeyPair.objects.all())],
source="name",
)
subject_alt_name = CharField(required=False, allow_blank=True, label=_("Subject-alt name"))
validity_days = IntegerField(initial=365)
alg = ChoiceField(default=PrivateKeyAlg.RSA, choices=PrivateKeyAlg.choices)
Expand Down Expand Up @@ -242,11 +246,10 @@ def list(self, request, *args, **kwargs):
def generate(self, request: Request) -> Response:
"""Generate a new, self-signed certificate-key pair"""
data = CertificateGenerationSerializer(data=request.data)
if not data.is_valid():
return Response(data.errors, status=400)
data.is_valid(raise_exception=True)
raw_san = data.validated_data.get("subject_alt_name", "")
sans = raw_san.split(",") if raw_san != "" else []
builder = CertificateBuilder(data.validated_data["common_name"])
builder = CertificateBuilder(data.validated_data["name"])
builder.alg = data.validated_data["alg"]
builder.build(
subject_alt_names=sans,
Expand Down
11 changes: 11 additions & 0 deletions authentik/crypto/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,17 @@ def test_builder_api(self):
self.assertIsInstance(ext[1], DNSName)
self.assertEqual(ext[1].value, "baz")

def test_builder_api_duplicate(self):
"""Test Builder (via API)"""
cert = create_test_cert()
self.client.force_login(create_test_admin_user())
res = self.client.post(
reverse("authentik_api:certificatekeypair-generate"),
data={"common_name": cert.name, "subject_alt_name": "bar,baz", "validity_days": 3},
)
self.assertEqual(res.status_code, 400)
self.assertJSONEqual(res.content, {"common_name": ["This field must be unique."]})

def test_builder_api_empty_san(self):
"""Test Builder (via API)"""
self.client.force_login(create_test_admin_user())
Expand Down
2 changes: 1 addition & 1 deletion authentik/enterprise/providers/rac/templates/if/rac.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{% load authentik_core %}

{% block head %}
{% versioned_script "dist/enterprise/rac/index-%v.js" %}
<script src="{% versioned_script 'dist/enterprise/rac/index-%v.js' %}" type="module"></script>
<meta name="theme-color" content="#18191a" media="(prefers-color-scheme: dark)">
<meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)">
<link rel="icon" href="{{ tenant.branding_favicon }}">
Expand Down
2 changes: 1 addition & 1 deletion authentik/flows/templates/if/flow.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
{% endblock %}

{% block head %}
{% versioned_script "dist/flow/FlowInterface-%v.js" %}
<script src="{% versioned_script 'dist/flow/FlowInterface-%v.js' %}" type="module"></script>
<style>
:root {
--ak-flow-background: url("{{ flow.background_url }}");
Expand Down
5 changes: 4 additions & 1 deletion authentik/providers/ldap/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,10 @@ def check_access(self, request: Request, pk) -> Response:
access_response = PolicyResult(result.passing)
response = self.LDAPCheckAccessSerializer(
instance={
"has_search_permission": request.user.has_perm("search_full_directory", provider),
"has_search_permission": (
request.user.has_perm("search_full_directory", provider)
or request.user.has_perm("authentik_providers_ldap.search_full_directory")
),
"access": access_response,
}
)
Expand Down
76 changes: 75 additions & 1 deletion authentik/providers/oauth2/tests/test_device_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from urllib.parse import urlencode

from django.urls import reverse
from rest_framework.test import APIClient

from authentik.core.models import Application, Group
from authentik.core.tests.utils import create_test_admin_user, create_test_brand, create_test_flow
Expand Down Expand Up @@ -34,7 +35,10 @@ def setUp(self) -> None:
self.brand.flow_device_code = self.device_flow
self.brand.save()

def test_device_init(self):
self.api_client = APIClient()
self.api_client.force_login(self.user)

def test_device_init_get(self):
"""Test device init"""
res = self.client.get(reverse("authentik_providers_oauth2_root:device-login"))
self.assertEqual(res.status_code, 302)
Expand All @@ -48,6 +52,76 @@ def test_device_init(self):
),
)

def test_device_init_post(self):
"""Test device init"""
res = self.api_client.get(reverse("authentik_providers_oauth2_root:device-login"))
self.assertEqual(res.status_code, 302)
self.assertEqual(
res.url,
reverse(
"authentik_core:if-flow",
kwargs={
"flow_slug": self.device_flow.slug,
},
),
)
res = self.api_client.get(
reverse(
"authentik_api:flow-executor",
kwargs={
"flow_slug": self.device_flow.slug,
},
),
)
self.assertEqual(res.status_code, 200)
self.assertJSONEqual(
res.content,
{
"component": "ak-provider-oauth2-device-code",
"flow_info": {
"background": "/static/dist/assets/images/flow_background.jpg",
"cancel_url": "/flows/-/cancel/",
"layout": "stacked",
"title": self.device_flow.title,
},
},
)

provider = OAuth2Provider.objects.create(
name=generate_id(),
authorization_flow=create_test_flow(),
)
Application.objects.create(name=generate_id(), slug=generate_id(), provider=provider)
token = DeviceToken.objects.create(
provider=provider,
)

res = self.api_client.post(
reverse(
"authentik_api:flow-executor",
kwargs={
"flow_slug": self.device_flow.slug,
},
),
data={
"component": "ak-provider-oauth2-device-code",
"code": token.user_code,
},
)
self.assertEqual(res.status_code, 200)
self.assertJSONEqual(
res.content,
{
"component": "xak-flow-redirect",
"to": reverse(
"authentik_core:if-flow",
kwargs={
"flow_slug": provider.authorization_flow.slug,
},
),
},
)

def test_no_flow(self):
"""Test no flow"""
self.brand.flow_device_code = None
Expand Down
7 changes: 5 additions & 2 deletions authentik/providers/oauth2/views/device_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from django.http import HttpRequest, HttpResponse
from django.utils.translation import gettext as _
from rest_framework.exceptions import ValidationError
from rest_framework.fields import CharField, IntegerField
from rest_framework.fields import CharField
from structlog.stdlib import get_logger

from authentik.brands.models import Brand
Expand Down Expand Up @@ -47,6 +47,9 @@ def resolve_provider_application(self):
self.provider = self.token.provider
self.application = self.token.provider.application

def post(self, request: HttpRequest, *args, **kwargs):
return self.get(request, *args, **kwargs)

def get(self, request: HttpRequest, *args, **kwargs):
scope_descriptions = UserInfoView().get_scope_descriptions(self.token.scope, self.provider)
planner = FlowPlanner(self.provider.authorization_flow)
Expand Down Expand Up @@ -122,7 +125,7 @@ class OAuthDeviceCodeChallenge(Challenge):
class OAuthDeviceCodeChallengeResponse(ChallengeResponse):
"""Response that includes the user-entered device code"""

code = IntegerField()
code = CharField()
component = CharField(default="ak-provider-oauth2-device-code")

def validate_code(self, code: int) -> HttpResponse | None:
Expand Down
11 changes: 10 additions & 1 deletion internal/outpost/proxyv2/application/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus"
"goauthentik.io/api/v3"
"goauthentik.io/internal/config"
"goauthentik.io/internal/outpost/ak"
"goauthentik.io/internal/outpost/proxyv2/constants"
"goauthentik.io/internal/outpost/proxyv2/hs256"
Expand Down Expand Up @@ -121,6 +122,14 @@ func NewApplication(p api.ProxyOutpostConfig, c *http.Client, server Server, old
bs := string(h.Sum([]byte(*p.ClientId)))
sessionName := fmt.Sprintf("authentik_proxy_%s", bs[:8])

// When HOST_BROWSER is set, use that as Host header for token requests to make the issuer match
// otherwise we use the internally configured authentik_host
tokenEndpointHost := server.API().Outpost.Config["authentik_host"].(string)
if config.Get().AuthentikHostBrowser != "" {
tokenEndpointHost = config.Get().AuthentikHostBrowser
}
publicHTTPClient := web.NewHostInterceptor(c, tokenEndpointHost)

a := &Application{
Host: externalHost.Host,
log: muxLogger,
Expand All @@ -131,7 +140,7 @@ func NewApplication(p api.ProxyOutpostConfig, c *http.Client, server Server, old
tokenVerifier: verifier,
proxyConfig: p,
httpClient: c,
publicHostHTTPClient: web.NewHostInterceptor(c, server.API().Outpost.Config["authentik_host"].(string)),
publicHostHTTPClient: publicHTTPClient,
mux: mux,
errorTemplates: templates.GetTemplates(),
ak: server.API(),
Expand Down
6 changes: 4 additions & 2 deletions internal/utils/web/http_host_interceptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ type hostInterceptor struct {
}

func (t hostInterceptor) RoundTrip(r *http.Request) (*http.Response, error) {
r.Host = t.host
r.Header.Set("X-Forwarded-Proto", t.scheme)
if r.Host != t.host {
r.Host = t.host
r.Header.Set("X-Forwarded-Proto", t.scheme)
}
return t.inner.RoundTrip(r)
}

Expand Down
8 changes: 5 additions & 3 deletions lifecycle/ak.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
"""Wrapper for lifecycle/ak, to be installed by poetry"""

from os import system
from os import system, waitstatus_to_exitcode
from pathlib import Path
from sys import argv
from sys import argv, exit


def main():
"""Wrapper around ak bash script"""
current_path = Path(__file__)
args = " ".join(argv[1:])
system(f"{current_path.parent}/ak {args}") # nosec
res = system(f"{current_path.parent}/ak {args}") # nosec
exit_code = waitstatus_to_exitcode(res)
exit(exit_code)


if __name__ == "__main__":
Expand Down
6 changes: 5 additions & 1 deletion 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-11-12 00:08+0000\n"
"POT-Creation-Date: 2024-11-13 00:09+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 @@ -3209,6 +3209,10 @@ msgstr ""
msgid "Globally enable/disable impersonation."
msgstr ""

#: authentik/tenants/models.py
msgid "Require administrators to provide a reason for impersonating a user."
msgstr ""

#: authentik/tenants/models.py
msgid "Default token duration"
msgstr ""
Expand Down
Binary file modified locale/it/LC_MESSAGES/django.mo
Binary file not shown.
6 changes: 5 additions & 1 deletion locale/zh-Hans/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-11-05 00:08+0000\n"
"POT-Creation-Date: 2024-11-12 00:08+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 @@ -1144,6 +1144,10 @@ msgstr "如果 zxcvbn 分数小于等于此值,则策略失败。"
msgid "Password not set in context"
msgstr "未在上下文中设置密码"

#: authentik/policies/password/models.py
msgid "Invalid password."
msgstr "无效密码。"

#: authentik/policies/password/models.py
#, python-format
msgid "Password exists on %(count)d online lists."
Expand Down
6 changes: 5 additions & 1 deletion 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-11-05 00:08+0000\n"
"POT-Creation-Date: 2024-11-12 00:08+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 @@ -1143,6 +1143,10 @@ msgstr "如果 zxcvbn 分数小于等于此值,则策略失败。"
msgid "Password not set in context"
msgstr "未在上下文中设置密码"

#: authentik/policies/password/models.py
msgid "Invalid password."
msgstr "无效密码。"

#: authentik/policies/password/models.py
#, python-format
msgid "Password exists on %(count)d online lists."
Expand Down
Loading

0 comments on commit 36b10b4

Please sign in to comment.