Skip to content

Commit

Permalink
Merge branch 'web/revision/more-dual-select-uses' into web/revision/m…
Browse files Browse the repository at this point in the history
…ore-dual-select-uses-2

* web/revision/more-dual-select-uses: (83 commits)
  website/docs: fix openssl rand commands (#9554)
  web: bump @sentry/browser from 7.112.2 to 7.113.0 in /web in the sentry group (#9549)
  core, web: update translations (#9548)
  core: bump goauthentik.io/api/v3 from 3.2024041.1 to 3.2024041.2 (#9551)
  core: bump django-model-utils from 4.5.0 to 4.5.1 (#9550)
  providers/scim: fix time_limit not set correctly (#9546)
  web/flows: fix error when enrolling multiple WebAuthn devices consecutively (#9545)
  web: bump ejs from 3.1.9 to 3.1.10 in /tests/wdio (#9542)
  web: bump API Client version (#9543)
  providers/saml: fix ecdsa support (#9537)
  website/integrations: nextcloud: connect to existing user (#9155)
  stages/authenticator_webauthn: Update FIDO MDS3 & Passkey aaguid blobs (#9535)
  web: bump the rollup group across 1 directory with 3 updates (#9532)
  website/developer-docs: Add note for custom YAML tags in an IDE (#9528)
  lifecycle: close database connection after migrating (#9516)
  web: bump the babel group in /web with 3 updates (#9520)
  core: bump node from 21 to 22 (#9521)
  web: bump @codemirror/lang-python from 6.1.5 to 6.1.6 in /web (#9523)
  providers/rac: bump guacd to 1.5.5 (#9514)
  core: only prefetch related objects when required (#9476)
  ...
  • Loading branch information
kensternberg-authentik committed May 6, 2024
2 parents e39a2f9 + a7b321d commit e6b0088
Show file tree
Hide file tree
Showing 130 changed files with 19,506 additions and 3,559 deletions.
4 changes: 3 additions & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 2024.2.3
current_version = 2024.4.1
tag = True
commit = True
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<rc_t>[a-zA-Z-]+)(?P<rc_n>[1-9]\\d*))?
Expand All @@ -21,6 +21,8 @@ optional_value = final

[bumpversion:file:schema.yml]

[bumpversion:file:blueprints/schema.json]

[bumpversion:file:authentik/__init__.py]

[bumpversion:file:internal/constants/constants.go]
Expand Down
12 changes: 6 additions & 6 deletions .github/actions/docker-push-variables/push_vars.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@
image_tags_rendered = ",".join(image_tags)

with open(os.environ["GITHUB_OUTPUT"], "a+", encoding="utf-8") as _output:
print("shouldBuild=%s" % should_build, file=_output)
print("sha=%s" % sha, file=_output)
print("version=%s" % version, file=_output)
print("prerelease=%s" % prerelease, file=_output)
print("imageTags=%s" % image_tags_rendered, file=_output)
print("imageMainTag=%s" % image_main_tag, file=_output)
print(f"shouldBuild={should_build}", file=_output)
print(f"sha={sha}", file=_output)
print(f"version={version}", file=_output)
print(f"prerelease={prerelease}", file=_output)
print(f"imageTags={image_tags_rendered}", file=_output)
print(f"imageMainTag={image_main_tag}", file=_output)
2 changes: 1 addition & 1 deletion .github/workflows/ci-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ jobs:
- name: Setup authentik env
uses: ./.github/actions/setup
- name: Create k8s Kind Cluster
uses: helm/kind-action@v1.9.0
uses: helm/kind-action@v1.10.0
- name: run integration
run: |
poetry run coverage run manage.py test tests/integration
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci-outpost.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
- name: Generate API
run: make gen-client-go
- name: golangci-lint
uses: golangci/golangci-lint-action@v4
uses: golangci/golangci-lint-action@v5
with:
version: v1.54.2
args: --timeout 5000s --verbose
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/ci-web.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ jobs:
- name: Eslint
working-directory: ${{ matrix.project }}/
run: npm run lint
lint-lockfile:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- working-directory: web/
run: |
[ -z "$(jq -r '.packages | to_entries[] | select((.key | startswith("node_modules")) and (.value | has("resolved") | not)) | .key' < package-lock.json)" ]
lint-build:
runs-on: ubuntu-latest
steps:
Expand Down Expand Up @@ -95,6 +102,7 @@ jobs:
run: npm run lit-analyse
ci-web-mark:
needs:
- lint-lockfile
- lint-eslint
- lint-prettier
- lint-lit-analyse
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/ci-website.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ on:
- version-*

jobs:
lint-lockfile:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- working-directory: website/
run: |
[ -z "$(jq -r '.packages | to_entries[] | select((.key | startswith("node_modules")) and (.value | has("resolved") | not)) | .key' < package-lock.json)" ]
lint-prettier:
runs-on: ubuntu-latest
steps:
Expand Down Expand Up @@ -62,6 +69,7 @@ jobs:
run: npm run ${{ matrix.job }}
ci-website-mark:
needs:
- lint-lockfile
- lint-prettier
- test
- build
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,8 @@ jobs:
- uses: actions/checkout@v4
- name: Run test suite in final docker images
run: |
echo "PG_PASS=$(openssl rand -base64 32)" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 32)" >> .env
echo "PG_PASS=$(openssl rand 32 | base64)" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand 32 | base64)" >> .env
docker compose pull -q
docker compose up --no-start
docker compose start postgresql redis
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release-tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ jobs:
- uses: actions/checkout@v4
- name: Pre-release test
run: |
echo "PG_PASS=$(openssl rand -base64 32)" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 32)" >> .env
echo "PG_PASS=$(openssl rand 32 | base64)" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand 32 | base64)" >> .env
docker buildx install
mkdir -p ./gen-ts-api
docker build -t testing:latest .
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# syntax=docker/dockerfile:1

# Stage 1: Build website
FROM --platform=${BUILDPLATFORM} docker.io/node:21 as website-builder
FROM --platform=${BUILDPLATFORM} docker.io/node:22 as website-builder

ENV NODE_ENV=production

Expand All @@ -20,7 +20,7 @@ COPY ./SECURITY.md /work/
RUN npm run build-bundled

# Stage 2: Build webui
FROM --platform=${BUILDPLATFORM} docker.io/node:21 as web-builder
FROM --platform=${BUILDPLATFORM} docker.io/node:22 as web-builder

ENV NODE_ENV=production

Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ test-go:
go test -timeout 0 -v -race -cover ./...

test-docker: ## Run all tests in a docker-compose
echo "PG_PASS=$(openssl rand -base64 32)" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 32)" >> .env
echo "PG_PASS=$(shell openssl rand 32 | base64)" >> .env
echo "AUTHENTIK_SECRET_KEY=$(shell openssl rand 32 | base64)" >> .env
docker compose pull -q
docker compose up --no-start
docker compose start postgresql redis
Expand Down
2 changes: 1 addition & 1 deletion authentik/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from os import environ

__version__ = "2024.2.3"
__version__ = "2024.4.1"
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"


Expand Down
8 changes: 7 additions & 1 deletion authentik/core/api/groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,18 @@ class UserAccountSerializer(PassiveSerializer):

pk = IntegerField(required=True)

queryset = Group.objects.all().select_related("parent").prefetch_related("users")
queryset = Group.objects.none()
serializer_class = GroupSerializer
search_fields = ["name", "is_superuser"]
filterset_class = GroupFilter
ordering = ["name"]

def get_queryset(self):
base_qs = Group.objects.all().select_related("parent").prefetch_related("roles")
if self.serializer_class(context={"request": self.request})._should_include_users:
base_qs = base_qs.prefetch_related("users")
return base_qs

@extend_schema(
parameters=[
OpenApiParameter("include_users", bool, default=True),
Expand Down
16 changes: 9 additions & 7 deletions authentik/core/api/tokens.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from typing import Any

from django.utils.timezone import now
from django_filters.rest_framework import DjangoFilterBackend
from drf_spectacular.utils import OpenApiResponse, extend_schema, inline_serializer
from guardian.shortcuts import assign_perm, get_anonymous_user
Expand All @@ -27,7 +28,6 @@
TokenIntents,
User,
default_token_duration,
token_expires_from_timedelta,
)
from authentik.events.models import Event, EventAction
from authentik.events.utils import model_to_dict
Expand Down Expand Up @@ -68,15 +68,17 @@ def validate(self, attrs: dict[Any, str]) -> dict[Any, str]:
max_token_lifetime_dt = default_token_duration()
if max_token_lifetime is not None:
try:
max_token_lifetime_dt = timedelta_from_string(max_token_lifetime)
max_token_lifetime_dt = now() + timedelta_from_string(max_token_lifetime)
except ValueError:
max_token_lifetime_dt = default_token_duration()
pass

if "expires" in attrs and attrs.get("expires") > token_expires_from_timedelta(
max_token_lifetime_dt
):
if "expires" in attrs and attrs.get("expires") > max_token_lifetime_dt:
raise ValidationError(
{"expires": f"Token expires exceeds maximum lifetime ({max_token_lifetime})."}
{
"expires": (
f"Token expires exceeds maximum lifetime ({max_token_lifetime_dt} UTC)."
)
}
)
elif attrs.get("intent") == TokenIntents.INTENT_API:
# For API tokens, expires cannot be overridden
Expand Down
7 changes: 5 additions & 2 deletions authentik/core/api/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,8 +407,11 @@ class UserViewSet(UsedByMixin, ModelViewSet):
search_fields = ["username", "name", "is_active", "email", "uuid"]
filterset_class = UsersFilter

def get_queryset(self): # pragma: no cover
return User.objects.all().exclude_anonymous().prefetch_related("ak_groups")
def get_queryset(self):
base_qs = User.objects.all().exclude_anonymous()
if self.serializer_class(context={"request": self.request})._should_include_groups:
base_qs = base_qs.prefetch_related("ak_groups")
return base_qs

@extend_schema(
parameters=[
Expand Down
9 changes: 2 additions & 7 deletions authentik/core/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""authentik core models"""

from datetime import datetime, timedelta
from datetime import datetime
from hashlib import sha256
from typing import Any, Optional, Self
from uuid import uuid4
Expand Down Expand Up @@ -68,11 +68,6 @@ def default_token_duration() -> datetime:
return now() + timedelta_from_string(token_duration)


def token_expires_from_timedelta(dt: timedelta) -> datetime:
"""Return a `datetime.datetime` object with the duration of the Token"""
return now() + dt


def default_token_key() -> str:
"""Default token key"""
current_tenant = get_current_tenant()
Expand Down Expand Up @@ -637,7 +632,7 @@ def serializer(self) -> type[Serializer]:
raise NotImplementedError

def __str__(self) -> str:
return f"User-source connection (user={self.user.username}, source={self.source.slug})"
return f"User-source connection (user={self.user_id}, source={self.source_id})"

class Meta:
unique_together = (("user", "source"),)
Expand Down
9 changes: 8 additions & 1 deletion authentik/core/tests/test_groups_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from rest_framework.test import APITestCase

from authentik.core.models import Group, User
from authentik.core.tests.utils import create_test_user
from authentik.core.tests.utils import create_test_admin_user, create_test_user
from authentik.lib.generators import generate_id


Expand All @@ -16,6 +16,13 @@ def setUp(self) -> None:
self.login_user = create_test_user()
self.user = User.objects.create(username="test-user")

def test_list_with_users(self):
"""Test listing with users"""
admin = create_test_admin_user()
self.client.force_login(admin)
response = self.client.get(reverse("authentik_api:group-list"), {"include_users": "true"})
self.assertEqual(response.status_code, 200)

def test_add_user(self):
"""Test add_user"""
group = Group.objects.create(name=generate_id())
Expand Down
7 changes: 2 additions & 5 deletions authentik/core/tests/test_property_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,11 @@ def test_call_policy(self):
expression="return request.http_request.path",
)
http_request = self.factory.get("/")
tmpl = (
"""
res = ak_call_policy('%s')
tmpl = f"""
res = ak_call_policy('{expr.name}')
result = [request.http_request.path, res.raw_result]
return result
"""
% expr.name
)
evaluator = PropertyMapping(expression=tmpl, name=generate_id())
res = evaluator.evaluate(self.user, http_request)
self.assertEqual(res, ["/", "/"])
6 changes: 6 additions & 0 deletions authentik/core/tests/test_users_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ def test_filter_type(self):
)
self.assertEqual(response.status_code, 200)

def test_list_with_groups(self):
"""Test listing with groups"""
self.client.force_login(self.admin)
response = self.client.get(reverse("authentik_api:user-list"), {"include_groups": "true"})
self.assertEqual(response.status_code, 200)

def test_metrics(self):
"""Test user's metrics"""
self.client.force_login(self.admin)
Expand Down
2 changes: 0 additions & 2 deletions authentik/core/tests/test_users_avatars.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

from authentik.core.models import User
from authentik.core.tests.utils import create_test_admin_user
from authentik.lib.config import CONFIG
from authentik.tenants.utils import get_current_tenant


Expand All @@ -25,7 +24,6 @@ def set_avatar_mode(self, mode: str):
tenant.avatars = mode
tenant.save()

@CONFIG.patch("avatars", "none")
def test_avatars_none(self):
"""Test avatars none"""
self.set_avatar_mode("none")
Expand Down
10 changes: 4 additions & 6 deletions authentik/core/tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from authentik.brands.models import Brand
from authentik.core.models import Group, User
from authentik.crypto.builder import CertificateBuilder
from authentik.crypto.builder import CertificateBuilder, PrivateKeyAlg
from authentik.crypto.models import CertificateKeyPair
from authentik.flows.models import Flow, FlowDesignation
from authentik.lib.generators import generate_id
Expand Down Expand Up @@ -50,12 +50,10 @@ def create_test_brand(**kwargs) -> Brand:
return Brand.objects.create(domain=uid, default=True, **kwargs)


def create_test_cert(use_ec_private_key=False) -> CertificateKeyPair:
def create_test_cert(alg=PrivateKeyAlg.RSA) -> CertificateKeyPair:
"""Generate a certificate for testing"""
builder = CertificateBuilder(
name=f"{generate_id()}.self-signed.goauthentik.io",
use_ec_private_key=use_ec_private_key,
)
builder = CertificateBuilder(f"{generate_id()}.self-signed.goauthentik.io")
builder.alg = alg
builder.build(
subject_alt_names=[f"{generate_id()}.self-signed.goauthentik.io"],
validity_days=360,
Expand Down
12 changes: 10 additions & 2 deletions authentik/crypto/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
from rest_framework.fields import CharField, DateTimeField, IntegerField, SerializerMethodField
from rest_framework.fields import (
CharField,
ChoiceField,
DateTimeField,
IntegerField,
SerializerMethodField,
)
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.request import Request
from rest_framework.response import Response
Expand All @@ -26,7 +32,7 @@
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import PassiveSerializer
from authentik.crypto.apps import MANAGED_KEY
from authentik.crypto.builder import CertificateBuilder
from authentik.crypto.builder import CertificateBuilder, PrivateKeyAlg
from authentik.crypto.models import CertificateKeyPair
from authentik.events.models import Event, EventAction
from authentik.rbac.decorators import permission_required
Expand Down Expand Up @@ -178,6 +184,7 @@ class CertificateGenerationSerializer(PassiveSerializer):
common_name = CharField()
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)


class CertificateKeyPairFilter(FilterSet):
Expand Down Expand Up @@ -240,6 +247,7 @@ def generate(self, request: Request) -> Response:
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.alg = data.validated_data["alg"]
builder.build(
subject_alt_names=sans,
validity_days=int(data.validated_data["validity_days"]),
Expand Down
Loading

0 comments on commit e6b0088

Please sign in to comment.