Skip to content

Commit

Permalink
Merge branch 'dev' into web/sidebar-with-live-content-3
Browse files Browse the repository at this point in the history
* dev: (72 commits)
  web/flows: show logo in card (#7824)
  blueprints: improve file change handler (#7813)
  web/user: fix search not updating app (#7825)
  web: bump the storybook group in /web with 5 updates (#7819)
  core: compile backend translations (#7827)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in de (#7812)
  core: bump github.com/go-openapi/strfmt from 0.21.8 to 0.21.9 (#7814)
  ci: bump actions/stale from 8 to 9 (#7815)
  web: bump the wdio group in /tests/wdio with 1 update (#7816)
  translate: Updates for file web/xliff/en.xlf in zh_CN (#7820)
  web: bump the sentry group in /web with 2 updates (#7817)
  web: bump vite-tsconfig-paths from 4.2.1 to 4.2.2 in /web (#7818)
  translate: Updates for file web/xliff/en.xlf in zh-Hans (#7821)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh-Hans (#7822)
  translate: Updates for file locale/en/LC_MESSAGES/django.po in zh_CN (#7823)
  web: bump typescript from 5.3.2 to 5.3.3 in /web (#7806)
  website: bump typescript from 5.3.2 to 5.3.3 in /website (#7807)
  web: bump typescript from 5.3.2 to 5.3.3 in /tests/wdio (#7808)
  core: bump goauthentik.io/api/v3 from 3.2023104.1 to 3.2023104.2 (#7809)
  ci: bump actions/setup-go from 4 to 5
  ...
  • Loading branch information
kensternberg-authentik committed Dec 8, 2023
2 parents a367390 + ef8a119 commit 2a11356
Show file tree
Hide file tree
Showing 92 changed files with 5,913 additions and 7,081 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/ci-outpost.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
- uses: actions/setup-go@v5
with:
go-version-file: "go.mod"
- name: Prepare and generate API
Expand All @@ -37,7 +37,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
- uses: actions/setup-go@v5
with:
go-version-file: "go.mod"
- name: Setup authentik env
Expand Down Expand Up @@ -125,7 +125,7 @@ jobs:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- uses: actions/setup-go@v4
- uses: actions/setup-go@v5
with:
go-version-file: "go.mod"
- uses: actions/setup-node@v4
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 @@ -67,7 +67,7 @@ jobs:
- radius
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
- uses: actions/setup-go@v5
with:
go-version-file: "go.mod"
- name: Set up QEMU
Expand Down Expand Up @@ -126,7 +126,7 @@ jobs:
goarch: [amd64, arm64]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
- uses: actions/setup-go@v5
with:
go-version-file: "go.mod"
- uses: actions/setup-node@v4
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/repo-stale.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
with:
app_id: ${{ secrets.GH_APP_ID }}
private_key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- uses: actions/stale@v8
- uses: actions/stale@v9
with:
repo-token: ${{ steps.generate_token.outputs.token }}
days-before-stale: 60
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ COPY ./gen-ts-api /work/web/node_modules/@goauthentik/api
RUN npm run build

# Stage 3: Build go proxy
FROM --platform=${BUILDPLATFORM} docker.io/golang:1.21.4-bookworm AS go-builder
FROM --platform=${BUILDPLATFORM} docker.io/golang:1.21.5-bookworm AS go-builder

ARG TARGETOS
ARG TARGETARCH
Expand Down Expand Up @@ -121,7 +121,7 @@ WORKDIR /
# We cannot cache this layer otherwise we'll end up with a bigger image
RUN apt-get update && \
# Required for runtime
apt-get install -y --no-install-recommends libpq5 openssl libxmlsec1-openssl libmaxminddb0 && \
apt-get install -y --no-install-recommends libpq5 openssl libxmlsec1-openssl libmaxminddb0 ca-certificates && \
# Required for bootstrap & healtcheck
apt-get install -y --no-install-recommends runit && \
apt-get clean && \
Expand Down
4 changes: 3 additions & 1 deletion authentik/api/v3/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
for _authentik_app in get_apps():
try:
api_urls = import_module(f"{_authentik_app.name}.urls")
except (ModuleNotFoundError, ImportError) as exc:
except ModuleNotFoundError:
continue
except ImportError as exc:
LOGGER.warning("Could not import app's URLs", app_name=_authentik_app.name, exc=exc)
continue
if not hasattr(api_urls, "api_urlpatterns"):
Expand Down
35 changes: 17 additions & 18 deletions authentik/blueprints/v1/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,13 @@ def on_any_event(self, event: FileSystemEvent):
return
if event.is_directory:
return
root = Path(CONFIG.get("blueprints_dir")).absolute()
path = Path(event.src_path).absolute()
rel_path = str(path.relative_to(root))
if isinstance(event, FileCreatedEvent):
LOGGER.debug("new blueprint file created, starting discovery")
blueprints_discovery.delay()
LOGGER.debug("new blueprint file created, starting discovery", path=rel_path)
blueprints_discovery.delay(rel_path)
if isinstance(event, FileModifiedEvent):
path = Path(event.src_path)
root = Path(CONFIG.get("blueprints_dir")).absolute()
rel_path = str(path.relative_to(root))
for instance in BlueprintInstance.objects.filter(path=rel_path, enabled=True):
LOGGER.debug("modified blueprint file, starting apply", instance=instance)
apply_blueprint.delay(instance.pk.hex)
Expand All @@ -98,50 +98,45 @@ def blueprints_find_dict():
return blueprints


def blueprints_find():
def blueprints_find() -> list[BlueprintFile]:
"""Find blueprints and return valid ones"""
blueprints = []
root = Path(CONFIG.get("blueprints_dir"))
for path in root.rglob("**/*.yaml"):
rel_path = path.relative_to(root)
# Check if any part in the path starts with a dot and assume a hidden file
if any(part for part in path.parts if part.startswith(".")):
continue
LOGGER.debug("found blueprint", path=str(path))
with open(path, "r", encoding="utf-8") as blueprint_file:
try:
raw_blueprint = load(blueprint_file.read(), BlueprintLoader)
except YAMLError as exc:
raw_blueprint = None
LOGGER.warning("failed to parse blueprint", exc=exc, path=str(path))
LOGGER.warning("failed to parse blueprint", exc=exc, path=str(rel_path))
if not raw_blueprint:
continue
metadata = raw_blueprint.get("metadata", None)
version = raw_blueprint.get("version", 1)
if version != 1:
LOGGER.warning("invalid blueprint version", version=version, path=str(path))
LOGGER.warning("invalid blueprint version", version=version, path=str(rel_path))
continue
file_hash = sha512(path.read_bytes()).hexdigest()
blueprint = BlueprintFile(
str(path.relative_to(root)), version, file_hash, int(path.stat().st_mtime)
)
blueprint = BlueprintFile(str(rel_path), version, file_hash, int(path.stat().st_mtime))
blueprint.meta = from_dict(BlueprintMetadata, metadata) if metadata else None
blueprints.append(blueprint)
LOGGER.debug(
"parsed & loaded blueprint",
hash=file_hash,
path=str(path),
)
return blueprints


@CELERY_APP.task(
throws=(DatabaseError, ProgrammingError, InternalError), base=MonitoredTask, bind=True
)
@prefill_task
def blueprints_discovery(self: MonitoredTask):
def blueprints_discovery(self: MonitoredTask, path: Optional[str] = None):
"""Find blueprints and check if they need to be created in the database"""
count = 0
for blueprint in blueprints_find():
if path and blueprint.path != path:
continue
check_blueprint_v1_file(blueprint)
count += 1
self.set_status(
Expand Down Expand Up @@ -171,7 +166,11 @@ def check_blueprint_v1_file(blueprint: BlueprintFile):
metadata={},
)
instance.save()
LOGGER.info(
"Creating new blueprint instance from file", instance=instance, path=instance.path
)
if instance.last_applied_hash != blueprint.hash:
LOGGER.info("Applying blueprint due to changed file", instance=instance, path=instance.path)
apply_blueprint.delay(str(instance.pk))


Expand Down
2 changes: 1 addition & 1 deletion authentik/core/api/sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class SourceSerializer(ModelSerializer, MetaNameSerializer):

managed = ReadOnlyField()
component = SerializerMethodField()
icon = ReadOnlyField(source="get_icon")
icon = ReadOnlyField(source="icon_url")

def get_component(self, obj: Source) -> str:
"""Get object component so that we know how to edit the object"""
Expand Down
2 changes: 1 addition & 1 deletion authentik/core/templates/if/flow.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

{% block body %}
<ak-message-container></ak-message-container>
<ak-flow-executor>
<ak-flow-executor flowSlug="{{ flow.slug }}">
<ak-loading></ak-loading>
</ak-flow-executor>
{% endblock %}
12 changes: 10 additions & 2 deletions authentik/events/api/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import django_filters
from django.db.models.aggregates import Count
from django.db.models.fields.json import KeyTextTransform, KeyTransform
from django.db.models.functions import ExtractDay
from django.db.models.functions import ExtractDay, ExtractHour
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, extend_schema
from guardian.shortcuts import get_objects_for_user
Expand Down Expand Up @@ -149,7 +149,15 @@ def top_per_user(self, request: Request):
return Response(EventTopPerUserSerializer(instance=events, many=True).data)

@extend_schema(
methods=["GET"],
responses={200: CoordinateSerializer(many=True)},
)
@action(detail=False, methods=["GET"], pagination_class=None)
def volume(self, request: Request) -> Response:
"""Get event volume for specified filters and timeframe"""
queryset = self.filter_queryset(self.get_queryset())
return Response(queryset.get_events_per(timedelta(days=7), ExtractHour, 7 * 3))

@extend_schema(
responses={200: CoordinateSerializer(many=True)},
filters=[],
parameters=[
Expand Down
6 changes: 5 additions & 1 deletion authentik/flows/stage.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,11 @@ def _get_challenge(self, *args, **kwargs) -> Challenge:
stage_type=self.__class__.__name__, method="get_challenge"
).time(),
):
challenge = self.get_challenge(*args, **kwargs)
try:
challenge = self.get_challenge(*args, **kwargs)
except StageInvalidException as exc:
self.logger.debug("Got StageInvalidException", exc=exc)
return self.executor.stage_invalid()
with Hub.current.start_span(
op="authentik.flow.stage._get_challenge",
description=self.__class__.__name__,
Expand Down
49 changes: 37 additions & 12 deletions authentik/root/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@
from authentik.lib.logging import get_logger_config, structlog_configure
from authentik.lib.sentry import sentry_init
from authentik.lib.utils.reflection import get_env
from authentik.stages.password import BACKEND_APP_PASSWORD, BACKEND_INBUILT, BACKEND_LDAP
from authentik.stages.password import (
BACKEND_APP_PASSWORD,
BACKEND_INBUILT,
BACKEND_LDAP,
)

BASE_DIR = Path(__file__).absolute().parent.parent.parent
STATICFILES_DIRS = [BASE_DIR / Path("web")]
Expand Down Expand Up @@ -129,7 +133,9 @@
"CONTACT": {
"email": "hello@goauthentik.io",
},
"AUTHENTICATION_WHITELIST": ["authentik.api.authentication.TokenAuthentication"],
"AUTHENTICATION_WHITELIST": [
"authentik.api.authentication.TokenAuthentication"
],
"LICENSE": {
"name": "MIT",
"url": "https://github.com/goauthentik/authentik/blob/main/LICENSE",
Expand Down Expand Up @@ -164,7 +170,9 @@
"DEFAULT_PARSER_CLASSES": [
"rest_framework.parsers.JSONParser",
],
"DEFAULT_PERMISSION_CLASSES": ("authentik.rbac.permissions.ObjectPermissions",),
"DEFAULT_PERMISSION_CLASSES": (
"authentik.rbac.permissions.ObjectPermissions",
),
"DEFAULT_AUTHENTICATION_CLASSES": (
"authentik.api.authentication.TokenAuthentication",
"rest_framework.authentication.SessionAuthentication",
Expand All @@ -184,7 +192,9 @@
_redis_celery_tls_requirements = ""
if CONFIG.get_bool("redis.tls", False):
_redis_protocol_prefix = "rediss://"
_redis_celery_tls_requirements = f"?ssl_cert_reqs={CONFIG.get('redis.tls_reqs')}"
_redis_celery_tls_requirements = (

Check warning on line 195 in authentik/root/settings.py

View check run for this annotation

Codecov / codecov/patch

authentik/root/settings.py#L195

Added line #L195 was not covered by tests
f"?ssl_cert_reqs={CONFIG.get('redis.tls_reqs')}"
)
_redis_url = (
f"{_redis_protocol_prefix}:"
f"{quote_plus(CONFIG.get('redis.password'))}@{quote_plus(CONFIG.get('redis.host'))}:"
Expand All @@ -194,7 +204,8 @@
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": CONFIG.get("cache.url") or f"{_redis_url}/{CONFIG.get('redis.db')}",
"LOCATION": CONFIG.get("cache.url")
or f"{_redis_url}/{CONFIG.get('redis.db')}",
"TIMEOUT": CONFIG.get_int("cache.timeout", 300),
"OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient"},
"KEY_PREFIX": "authentik_cache",
Expand Down Expand Up @@ -255,7 +266,11 @@
"default": {
"BACKEND": "channels_redis.pubsub.RedisPubSubChannelLayer",
"CONFIG": {
"hosts": [CONFIG.get("channel.url", f"{_redis_url}/{CONFIG.get('redis.db')}")],
"hosts": [
CONFIG.get(
"channel.url", f"{_redis_url}/{CONFIG.get('redis.db')}"
)
],
"prefix": "authentik_channels_",
},
},
Expand Down Expand Up @@ -313,7 +328,9 @@
},
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"},
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"},
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"
},
]


Expand Down Expand Up @@ -350,7 +367,9 @@
"task_default_queue": "authentik",
"broker_url": CONFIG.get("broker.url")
or f"{_redis_url}/{CONFIG.get('redis.db')}{_redis_celery_tls_requirements}",
"broker_transport_options": CONFIG.get_dict_from_b64_json("broker.transport_options"),
"broker_transport_options": CONFIG.get_dict_from_b64_json(
"broker.transport_options"
),
"result_backend": CONFIG.get("result_backend.url")
or f"{_redis_url}/{CONFIG.get('redis.db')}{_redis_celery_tls_requirements}",
}
Expand All @@ -361,7 +380,10 @@
if _ERROR_REPORTING:
sentry_env = CONFIG.get("error_reporting.environment", "customer")
sentry_init()
set_tag("authentik.uuid", sha512(str(SECRET_KEY).encode("ascii")).hexdigest()[:16])
set_tag(

Check warning on line 383 in authentik/root/settings.py

View check run for this annotation

Codecov / codecov/patch

authentik/root/settings.py#L383

Added line #L383 was not covered by tests
"authentik.uuid",
sha512(str(SECRET_KEY).encode("ascii")).hexdigest()[:16],
)


# Static files (CSS, JavaScript, Images)
Expand Down Expand Up @@ -391,8 +413,12 @@ def _update_settings(app_path: str):
CONFIG.log("debug", "Loaded app settings", path=app_path)
INSTALLED_APPS.extend(getattr(settings_module, "INSTALLED_APPS", []))
MIDDLEWARE.extend(getattr(settings_module, "MIDDLEWARE", []))
AUTHENTICATION_BACKENDS.extend(getattr(settings_module, "AUTHENTICATION_BACKENDS", []))
CELERY["beat_schedule"].update(getattr(settings_module, "CELERY_BEAT_SCHEDULE", {}))
AUTHENTICATION_BACKENDS.extend(
getattr(settings_module, "AUTHENTICATION_BACKENDS", [])
)
CELERY["beat_schedule"].update(
getattr(settings_module, "CELERY_BEAT_SCHEDULE", {})
)
for _attr in dir(settings_module):
if not _attr.startswith("__") and _attr not in _DISALLOWED_ITEMS:
globals()[_attr] = getattr(settings_module, _attr)
Expand All @@ -411,7 +437,6 @@ def _update_settings(app_path: str):
CELERY["task_always_eager"] = True
os.environ[ENV_GIT_HASH_KEY] = "dev"
INSTALLED_APPS.append("silk")
SILKY_PYTHON_PROFILER = False
MIDDLEWARE = ["silk.middleware.SilkyMiddleware"] + MIDDLEWARE
REST_FRAMEWORK["DEFAULT_RENDERER_CLASSES"].append(
"rest_framework.renderers.BrowsableAPIRenderer"
Expand Down
Loading

0 comments on commit 2a11356

Please sign in to comment.