diff --git a/.bumpversion.cfg b/.bumpversion.cfg index cc4a5bc17..1adaaa2cb 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 2023.6.1 +current_version = 2023.8.1 tag = True commit = True parse = (?P\d+)\.(?P\d+)\.(?P\d+) diff --git a/Makefile b/Makefile index 3343c9968..fb08cc604 100644 --- a/Makefile +++ b/Makefile @@ -148,8 +148,7 @@ web-lint-fix: web-lint: cd web && npm run lint - # TODO: The analyzer hasn't run correctly in awhile. - # cd web && npm run lit-analyse + cd web && npm run lit-analyse web-check-compile: cd web && npm run tsc diff --git a/SECURITY.md b/SECURITY.md index 0e3b00b9e..0d9d6a673 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -16,8 +16,8 @@ Even if the issue is not a CVE, we still greatly appreciate your help in hardeni | Version | Supported | | --- | --- | -| 2023.5.x | ✅ | | 2023.6.x | ✅ | +| 2023.8.x | ✅ | ## Reporting a Vulnerability diff --git a/authentik/__init__.py b/authentik/__init__.py index 941d9e88b..f36d231ff 100644 --- a/authentik/__init__.py +++ b/authentik/__init__.py @@ -2,7 +2,7 @@ from os import environ from typing import Optional -__version__ = "2023.6.1" +__version__ = "2023.8.1" ENV_GIT_HASH_KEY = "GIT_BUILD_HASH" diff --git a/authentik/events/api/events.py b/authentik/events/api/events.py index fda11c090..e3226c407 100644 --- a/authentik/events/api/events.py +++ b/authentik/events/api/events.py @@ -4,7 +4,7 @@ from json import loads import django_filters from django.db.models.aggregates import Count -from django.db.models.fields.json import KeyTextTransform +from django.db.models.fields.json import KeyTextTransform, KeyTransform from django.db.models.functions import ExtractDay from drf_spectacular.types import OpenApiTypes from drf_spectacular.utils import OpenApiParameter, extend_schema @@ -134,11 +134,11 @@ class EventViewSet(ModelViewSet): """Get the top_n events grouped by user count""" filtered_action = request.query_params.get("action", EventAction.LOGIN) top_n = int(request.query_params.get("top_n", "15")) - return Response( + events = ( get_objects_for_user(request.user, "authentik_events.view_event") .filter(action=filtered_action) .exclude(context__authorized_application=None) - .annotate(application=KeyTextTransform("authorized_application", "context")) + .annotate(application=KeyTransform("authorized_application", "context")) .annotate(user_pk=KeyTextTransform("pk", "user")) .values("application") .annotate(counted_events=Count("application")) @@ -146,6 +146,7 @@ class EventViewSet(ModelViewSet): .values("unique_users", "application", "counted_events") .order_by("-counted_events")[:top_n] ) + return Response(EventTopPerUserSerializer(instance=events, many=True).data) @extend_schema( methods=["GET"], diff --git a/authentik/root/settings.py b/authentik/root/settings.py index 4e6514144..0302b3116 100644 --- a/authentik/root/settings.py +++ b/authentik/root/settings.py @@ -279,15 +279,14 @@ DATABASES = { "SSLROOTCERT": CONFIG.get("postgresql.sslrootcert"), "SSLCERT": CONFIG.get("postgresql.sslcert"), "SSLKEY": CONFIG.get("postgresql.sslkey"), - # https://docs.djangoproject.com/en/4.0/ref/databases/#persistent-connections - "CONN_MAX_AGE": None, - "CONN_HEALTH_CHECKS": True, } } if CONFIG.get_bool("postgresql.use_pgbouncer", False): # https://docs.djangoproject.com/en/4.0/ref/databases/#transaction-pooling-server-side-cursors DATABASES["default"]["DISABLE_SERVER_SIDE_CURSORS"] = True + # https://docs.djangoproject.com/en/4.0/ref/databases/#persistent-connections + DATABASES["default"]["CONN_MAX_AGE"] = None # persistent # Email # These values should never actually be used, emails are only sent from email stages, which diff --git a/authentik/stages/email/stage.py b/authentik/stages/email/stage.py index f116f7de0..a28fb3f39 100644 --- a/authentik/stages/email/stage.py +++ b/authentik/stages/email/stage.py @@ -12,7 +12,7 @@ from rest_framework.fields import CharField from rest_framework.serializers import ValidationError from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes -from authentik.flows.models import FlowToken +from authentik.flows.models import FlowDesignation, FlowToken from authentik.flows.planner import PLAN_CONTEXT_IS_RESTORED, PLAN_CONTEXT_PENDING_USER from authentik.flows.stage import ChallengeStageView from authentik.flows.views.executor import QS_KEY_TOKEN @@ -82,6 +82,11 @@ class EmailStageView(ChallengeStageView): """Helper function that sends the actual email. Implies that you've already checked that there is a pending user.""" pending_user = self.get_pending_user() + if not pending_user.pk and self.executor.flow.designation == FlowDesignation.RECOVERY: + # Pending user does not have a primary key, and we're in a recovery flow, + # which means the user entered an invalid identifier, so we pretend to send the + # email, to not disclose if the user exists + return email = self.executor.plan.context.get(PLAN_CONTEXT_EMAIL_OVERRIDE, None) if not email: email = pending_user.email diff --git a/authentik/stages/email/tests/test_sending.py b/authentik/stages/email/tests/test_sending.py index b1c2aea15..424d474ce 100644 --- a/authentik/stages/email/tests/test_sending.py +++ b/authentik/stages/email/tests/test_sending.py @@ -5,18 +5,20 @@ from unittest.mock import MagicMock, PropertyMock, patch from django.core import mail from django.core.mail.backends.locmem import EmailBackend from django.urls import reverse -from rest_framework.test import APITestCase +from authentik.core.models import User from authentik.core.tests.utils import create_test_admin_user, create_test_flow from authentik.events.models import Event, EventAction from authentik.flows.markers import StageMarker from authentik.flows.models import FlowDesignation, FlowStageBinding from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, 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.email.models import EmailStage -class TestEmailStageSending(APITestCase): +class TestEmailStageSending(FlowTestCase): """Email tests""" def setUp(self): @@ -44,6 +46,13 @@ class TestEmailStageSending(APITestCase): ): response = self.client.post(url) self.assertEqual(response.status_code, 200) + self.assertStageResponse( + response, + self.flow, + response_errors={ + "non_field_errors": [{"string": "email-sent", "code": "email-sent"}] + }, + ) self.assertEqual(len(mail.outbox), 1) self.assertEqual(mail.outbox[0].subject, "authentik") events = Event.objects.filter(action=EventAction.EMAIL_SENT) @@ -54,6 +63,32 @@ class TestEmailStageSending(APITestCase): self.assertEqual(event.context["to_email"], [self.user.email]) self.assertEqual(event.context["from_email"], "system@authentik.local") + def test_pending_fake_user(self): + """Test with pending (fake) user""" + self.flow.designation = FlowDesignation.RECOVERY + self.flow.save() + plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()]) + plan.context[PLAN_CONTEXT_PENDING_USER] = User(username=generate_id()) + session = self.client.session + session[SESSION_KEY_PLAN] = plan + session.save() + + url = reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}) + with patch( + "authentik.stages.email.models.EmailStage.backend_class", + PropertyMock(return_value=EmailBackend), + ): + response = self.client.post(url) + self.assertEqual(response.status_code, 200) + self.assertStageResponse( + response, + self.flow, + response_errors={ + "non_field_errors": [{"string": "email-sent", "code": "email-sent"}] + }, + ) + self.assertEqual(len(mail.outbox), 0) + def test_send_error(self): """Test error during sending (sending will be retried)""" plan = FlowPlan(flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()]) diff --git a/authentik/stages/identification/stage.py b/authentik/stages/identification/stage.py index a54de07d9..3a6a5bd25 100644 --- a/authentik/stages/identification/stage.py +++ b/authentik/stages/identification/stage.py @@ -118,8 +118,12 @@ class IdentificationChallengeResponse(ChallengeResponse): username=uid_field, email=uid_field, ) + self.pre_user = self.stage.executor.plan.context[PLAN_CONTEXT_PENDING_USER] if not current_stage.show_matched_user: self.stage.executor.plan.context[PLAN_CONTEXT_PENDING_USER_IDENTIFIER] = uid_field + if self.stage.executor.flow.designation == FlowDesignation.RECOVERY: + # When used in a recovery flow, always continue to not disclose if a user exists + return attrs raise ValidationError("Failed to authenticate.") self.pre_user = pre_user if not current_stage.password_stage: diff --git a/authentik/stages/identification/tests.py b/authentik/stages/identification/tests.py index cdd7bf0e9..dabdea050 100644 --- a/authentik/stages/identification/tests.py +++ b/authentik/stages/identification/tests.py @@ -188,7 +188,7 @@ class TestIdentificationStage(FlowTestCase): ], ) - def test_recovery_flow(self): + def test_link_recovery_flow(self): """Test that recovery flow is linked correctly""" flow = create_test_flow() self.stage.recovery_flow = flow @@ -226,6 +226,38 @@ class TestIdentificationStage(FlowTestCase): ], ) + def test_recovery_flow_invalid_user(self): + """Test that an invalid user can proceed in a recovery flow""" + self.flow.designation = FlowDesignation.RECOVERY + self.flow.save() + response = self.client.get( + reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}), + ) + self.assertStageResponse( + response, + self.flow, + component="ak-stage-identification", + user_fields=["email"], + password_fields=False, + show_source_labels=False, + primary_action="Continue", + sources=[ + { + "challenge": { + "component": "xak-flow-redirect", + "to": "/source/oauth/login/test/", + "type": ChallengeTypes.REDIRECT.value, + }, + "icon_url": "/static/authentik/sources/default.svg", + "name": "test", + } + ], + ) + form_data = {"uid_field": generate_id()} + url = reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}) + response = self.client.post(url, form_data) + self.assertEqual(response.status_code, 200) + def test_api_validate(self): """Test API validation""" self.assertTrue( diff --git a/blueprints/default/flow-default-authentication-flow.yaml b/blueprints/default/flow-default-authentication-flow.yaml index 47cf27863..123c4e5a7 100644 --- a/blueprints/default/flow-default-authentication-flow.yaml +++ b/blueprints/default/flow-default-authentication-flow.yaml @@ -51,6 +51,8 @@ entries: order: 20 stage: !KeyOf default-authentication-password target: !KeyOf flow + attrs: + re_evaluate_policies: true id: default-authentication-flow-password-binding model: authentik_flows.flowstagebinding - identifiers: @@ -69,10 +71,12 @@ entries: name: default-authentication-flow-password-stage attrs: expression: | - flow_plan = request.context["flow_plan"] + flow_plan = request.context.get("flow_plan") + if not flow_plan: + return True # If the user does not have a backend attached to it, they haven't # been authenticated yet and we need the password stage - return not hasattr(flow_plan.context["pending_user"], "backend") + return not hasattr(flow_plan.context.get("pending_user"), "backend") - model: authentik_policies.policybinding identifiers: order: 10 diff --git a/docker-compose.yml b/docker-compose.yml index 16d873d0b..68970fcfa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -32,7 +32,7 @@ services: volumes: - redis:/data server: - image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.6.1} + image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.8.1} restart: unless-stopped command: server environment: @@ -53,7 +53,7 @@ services: - postgresql - redis worker: - image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.6.1} + image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2023.8.1} restart: unless-stopped command: worker environment: diff --git a/go.mod b/go.mod index 24e205327..68d230a48 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.7.0 github.com/stretchr/testify v1.8.4 - goauthentik.io/api/v3 v3.2023061.13 + goauthentik.io/api/v3 v3.2023081.1 golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab golang.org/x/oauth2 v0.11.0 golang.org/x/sync v0.3.0 diff --git a/go.sum b/go.sum index 431d21471..ac5de0546 100644 --- a/go.sum +++ b/go.sum @@ -1071,8 +1071,8 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -goauthentik.io/api/v3 v3.2023061.13 h1:0V5XrryJdMrOug/5wWazmH+D3Y/dDGPyLDhWcbJ5Gm0= -goauthentik.io/api/v3 v3.2023061.13/go.mod h1:sP1/Ak/vGw96xNgpyoObHgXfyAElcTN5CbbC+VdPQXk= +goauthentik.io/api/v3 v3.2023081.1 h1:kXD9ZxOEjVxTK+qGeB0I13A5TzvO/PlAQqVQOCYevUM= +goauthentik.io/api/v3 v3.2023081.1/go.mod h1:sP1/Ak/vGw96xNgpyoObHgXfyAElcTN5CbbC+VdPQXk= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= diff --git a/internal/constants/constants.go b/internal/constants/constants.go index f47f80b29..d2d1aec48 100644 --- a/internal/constants/constants.go +++ b/internal/constants/constants.go @@ -29,4 +29,4 @@ func UserAgent() string { return fmt.Sprintf("authentik@%s", FullVersion()) } -const VERSION = "2023.6.1" +const VERSION = "2023.8.1" diff --git a/poetry.lock b/poetry.lock index 97640bbab..d8cf8ee2a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3458,13 +3458,13 @@ urllib3 = {version = ">=1.26,<3", extras = ["socks"]} [[package]] name = "sentry-sdk" -version = "1.29.2" +version = "1.30.0" description = "Python client for Sentry (https://sentry.io)" optional = false python-versions = "*" files = [ - {file = "sentry-sdk-1.29.2.tar.gz", hash = "sha256:a99ee105384788c3f228726a88baf515fe7b5f1d2d0f215a03d194369f158df7"}, - {file = "sentry_sdk-1.29.2-py2.py3-none-any.whl", hash = "sha256:3e17215d8006612e2df02b0e73115eb8376c37e3f586d8436fa41644e605074d"}, + {file = "sentry-sdk-1.30.0.tar.gz", hash = "sha256:7dc873b87e1faf4d00614afd1058bfa1522942f33daef8a59f90de8ed75cd10c"}, + {file = "sentry_sdk-1.30.0-py2.py3-none-any.whl", hash = "sha256:2e53ad63f96bb9da6570ba2e755c267e529edcf58580a2c0d2a11ef26e1e678b"}, ] [package.dependencies] @@ -3487,6 +3487,7 @@ httpx = ["httpx (>=0.16.0)"] huey = ["huey (>=2)"] loguru = ["loguru (>=0.5)"] opentelemetry = ["opentelemetry-distro (>=0.35b0)"] +opentelemetry-experimental = ["opentelemetry-distro (>=0.40b0,<1.0)", "opentelemetry-instrumentation-aiohttp-client (>=0.40b0,<1.0)", "opentelemetry-instrumentation-django (>=0.40b0,<1.0)", "opentelemetry-instrumentation-fastapi (>=0.40b0,<1.0)", "opentelemetry-instrumentation-flask (>=0.40b0,<1.0)", "opentelemetry-instrumentation-requests (>=0.40b0,<1.0)", "opentelemetry-instrumentation-sqlite3 (>=0.40b0,<1.0)", "opentelemetry-instrumentation-urllib (>=0.40b0,<1.0)"] pure-eval = ["asttokens", "executing", "pure-eval"] pymongo = ["pymongo (>=3.1)"] pyspark = ["pyspark (>=2.4.4)"] diff --git a/pyproject.toml b/pyproject.toml index 8c88bed32..714ad0600 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -113,7 +113,7 @@ filterwarnings = [ [tool.poetry] name = "authentik" -version = "2023.6.1" +version = "2023.8.1" description = "" authors = ["authentik Team "] diff --git a/schema.yml b/schema.yml index af6ce96f0..8ee8d9906 100644 --- a/schema.yml +++ b/schema.yml @@ -1,7 +1,7 @@ openapi: 3.0.3 info: title: authentik - version: 2023.6.1 + version: 2023.8.1 description: Making authentication simple. contact: email: hello@goauthentik.io diff --git a/web/package-lock.json b/web/package-lock.json index 028accd89..32083a7be 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -17,7 +17,7 @@ "@codemirror/theme-one-dark": "^6.1.2", "@formatjs/intl-listformat": "^7.4.0", "@fortawesome/fontawesome-free": "^6.4.2", - "@goauthentik/api": "^2023.6.1-1692789666", + "@goauthentik/api": "^2023.8.1-1693356037", "@lit-labs/context": "^0.4.0", "@lit-labs/task": "^3.0.1", "@lit/localize": "^0.11.4", @@ -80,8 +80,8 @@ "eslint-plugin-storybook": "^0.6.13", "lit-analyzer": "^1.2.1", "npm-run-all": "^4.1.5", - "prettier": "^3.0.2", - "pyright": "^1.1.324", + "prettier": "^3.0.3", + "pyright": "^1.1.325", "react": "^18.2.0", "react-dom": "^18.2.0", "rollup": "^3.28.1", @@ -2904,9 +2904,9 @@ } }, "node_modules/@goauthentik/api": { - "version": "2023.6.1-1692789666", - "resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2023.6.1-1692789666.tgz", - "integrity": "sha512-nzHb5P5wLChtDWeKVQZbVo8OayouncrIs4W0WXT9LD62H9fFg/9IUf9bNm/gUW7MjqUre/QF9miHyHZ58sZzXQ==" + "version": "2023.8.1-1693356037", + "resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2023.8.1-1693356037.tgz", + "integrity": "sha512-I1puw6j3BDoKpYMYESwi7KYyR+QnHcENdhifWdQbcPrCRd3JMNWWbBvG6XgCF16364Exsndwt5R1PllZSDQznA==" }, "node_modules/@hcaptcha/types": { "version": "1.0.3", @@ -18932,9 +18932,9 @@ } }, "node_modules/prettier": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.2.tgz", - "integrity": "sha512-o2YR9qtniXvwEZlOKbveKfDQVyqxbEIWn48Z8m3ZJjBjcCmUy3xZGIv+7AkaeuaTr6yPXJjwv07ZWlsWbEy1rQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -19165,9 +19165,9 @@ } }, "node_modules/pyright": { - "version": "1.1.324", - "resolved": "https://registry.npmjs.org/pyright/-/pyright-1.1.324.tgz", - "integrity": "sha512-/Ng8G2Gb17dzQEHKgPa+Z5a6LPCLYNA4BVno1UdpDjnC9iLw0VAn5k/RNuaGkB/mhA82lV0OBcd5JEdaWcA3qg==", + "version": "1.1.325", + "resolved": "https://registry.npmjs.org/pyright/-/pyright-1.1.325.tgz", + "integrity": "sha512-hMvcY5G9WTRbvEKGiiqTepyORAppNPXZDUer5GZ15t1DYB79WwP3M0Tec6S0an7FDoY6eaJ5CtK+diJbmISIBQ==", "dev": true, "bin": { "pyright": "index.js", diff --git a/web/package.json b/web/package.json index f0e90cb65..c2407691f 100644 --- a/web/package.json +++ b/web/package.json @@ -34,7 +34,7 @@ "@codemirror/theme-one-dark": "^6.1.2", "@formatjs/intl-listformat": "^7.4.0", "@fortawesome/fontawesome-free": "^6.4.2", - "@goauthentik/api": "^2023.6.1-1692789666", + "@goauthentik/api": "^2023.8.1-1693356037", "@lit-labs/context": "^0.4.0", "@lit-labs/task": "^3.0.1", "@lit/localize": "^0.11.4", @@ -75,8 +75,8 @@ "@rollup/plugin-commonjs": "^25.0.4", "@rollup/plugin-node-resolve": "^15.2.1", "@rollup/plugin-replace": "^5.0.2", - "@rollup/plugin-typescript": "^11.1.3", "@rollup/plugin-terser": "^0.4.3", + "@rollup/plugin-typescript": "^11.1.3", "@storybook/addon-essentials": "^7.4.0", "@storybook/addon-links": "^7.4.0", "@storybook/blocks": "^7.1.1", @@ -97,8 +97,8 @@ "eslint-plugin-storybook": "^0.6.13", "lit-analyzer": "^1.2.1", "npm-run-all": "^4.1.5", - "prettier": "^3.0.2", - "pyright": "^1.1.324", + "prettier": "^3.0.3", + "pyright": "^1.1.325", "react": "^18.2.0", "react-dom": "^18.2.0", "rollup": "^3.28.1", diff --git a/web/src/admin/admin-overview/cards/VersionStatusCard.ts b/web/src/admin/admin-overview/cards/VersionStatusCard.ts index 77b075467..01689aede 100644 --- a/web/src/admin/admin-overview/cards/VersionStatusCard.ts +++ b/web/src/admin/admin-overview/cards/VersionStatusCard.ts @@ -43,7 +43,9 @@ export class VersionStatusCard extends AdminStatusCard { renderValue(): TemplateResult { let text = this.value?.versionCurrent; - let link = `https://goauthentik.io/docs/releases/${this.value?.versionCurrent}`; + const versionFamily = this.value?.versionCurrent.split("."); + versionFamily?.pop(); + let link = `https://goauthentik.io/docs/releases/${versionFamily?.join(".")}`; if (this.value?.buildHash) { text = this.value.buildHash?.substring(0, 7); link = `https://github.com/goauthentik/authentik/commit/${this.value.buildHash}`; diff --git a/web/src/admin/blueprints/BlueprintForm.ts b/web/src/admin/blueprints/BlueprintForm.ts index 3176ddb0e..d8d34dd82 100644 --- a/web/src/admin/blueprints/BlueprintForm.ts +++ b/web/src/admin/blueprints/BlueprintForm.ts @@ -1,6 +1,7 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { docLink } from "@goauthentik/common/global"; import { first } from "@goauthentik/common/utils"; +import "@goauthentik/components/ak-toggle-group"; import "@goauthentik/elements/CodeMirror"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; @@ -18,9 +19,9 @@ import PFContent from "@patternfly/patternfly/components/Content/content.css"; import { BlueprintFile, BlueprintInstance, ManagedApi } from "@goauthentik/api"; enum blueprintSource { - file, - oci, - internal, + file = "file", + oci = "oci", + internal = "internal", } @customElement("ak-blueprint-form") diff --git a/web/src/admin/policies/PolicyBindingForm.ts b/web/src/admin/policies/PolicyBindingForm.ts index 098a57546..a69638a43 100644 --- a/web/src/admin/policies/PolicyBindingForm.ts +++ b/web/src/admin/policies/PolicyBindingForm.ts @@ -1,5 +1,6 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { first, groupBy } from "@goauthentik/common/utils"; +import "@goauthentik/components/ak-toggle-group"; import "@goauthentik/elements/forms/HorizontalFormElement"; import { ModelForm } from "@goauthentik/elements/forms/ModelForm"; import "@goauthentik/elements/forms/SearchSelect"; @@ -24,9 +25,9 @@ import { } from "@goauthentik/api"; enum target { - policy, - group, - user, + policy = "policy", + group = "group", + user = "user", } @customElement("ak-policy-binding-form") @@ -51,7 +52,7 @@ export class PolicyBindingForm extends ModelForm { @property() targetPk?: string; - @property({ type: Number }) + @state() policyGroupUser: target = target.policy; @property({ type: Boolean }) diff --git a/web/src/common/constants.ts b/web/src/common/constants.ts index 782ecb016..cd5c58e2a 100644 --- a/web/src/common/constants.ts +++ b/web/src/common/constants.ts @@ -3,7 +3,7 @@ export const SUCCESS_CLASS = "pf-m-success"; export const ERROR_CLASS = "pf-m-danger"; export const PROGRESS_CLASS = "pf-m-in-progress"; export const CURRENT_CLASS = "pf-m-current"; -export const VERSION = "2023.6.1"; +export const VERSION = "2023.8.1"; export const TITLE_DEFAULT = "authentik"; export const ROUTE_SEPARATOR = ";"; diff --git a/web/src/components/ak-toggle-group.ts b/web/src/components/ak-toggle-group.ts index be3382891..2e5b4f90e 100644 --- a/web/src/components/ak-toggle-group.ts +++ b/web/src/components/ak-toggle-group.ts @@ -6,6 +6,7 @@ import { customElement, property } from "lit/decorators.js"; import { classMap } from "lit/directives/class-map.js"; import PFToggleGroup from "@patternfly/patternfly/components/ToggleGroup/toggle-group.css"; +import PFBase from "@patternfly/patternfly/patternfly-base.css"; type Pair = [string, string]; @@ -26,6 +27,7 @@ type Pair = [string, string]; export class AkToggleGroup extends CustomEmitterElement(AKElement) { static get styles() { return [ + PFBase, PFToggleGroup, css` .pf-c-toggle-group { diff --git a/web/src/elements/notifications/APIDrawer.ts b/web/src/elements/notifications/APIDrawer.ts index b42e63ead..8f93bd8d2 100644 --- a/web/src/elements/notifications/APIDrawer.ts +++ b/web/src/elements/notifications/APIDrawer.ts @@ -38,6 +38,9 @@ export class APIDrawer extends AKElement { white-space: pre-wrap; font-family: monospace; } + .pf-c-notification-drawer__body { + overflow-x: hidden; + } `, ]; } diff --git a/web/src/elements/notifications/NotificationDrawer.ts b/web/src/elements/notifications/NotificationDrawer.ts index e3cdeb7c1..d8d11c664 100644 --- a/web/src/elements/notifications/NotificationDrawer.ts +++ b/web/src/elements/notifications/NotificationDrawer.ts @@ -34,6 +34,7 @@ export class NotificationDrawer extends AKElement { } .pf-c-notification-drawer__body { flex-grow: 1; + overflow-x: hidden; } .pf-c-notification-drawer__header { height: 114px; diff --git a/web/src/flow/FlowInspector.ts b/web/src/flow/FlowInspector.ts index 3e8f02bea..377fc4ad9 100644 --- a/web/src/flow/FlowInspector.ts +++ b/web/src/flow/FlowInspector.ts @@ -45,6 +45,9 @@ export class FlowInspector extends AKElement { overflow-x: hidden; white-space: break-spaces; } + .pf-c-notification-drawer__body { + overflow-x: hidden; + } `, ]; } diff --git a/website/docs/enterprise/entsupport.md b/website/docs/enterprise/entsupport.md new file mode 100644 index 000000000..40e7179d6 --- /dev/null +++ b/website/docs/enterprise/entsupport.md @@ -0,0 +1,15 @@ +--- +title: Support +--- + +Enterprise authentik provides dedicated support, with a Support center where you can open a request and view the progress and communications for your current requests. + +### Managing tickets and requests + +To access the Requests page, where you can open a request and view current requests, go to the Customer Portal and then click **Support** in the top menu. + +You can also bookmark the direct link to your Requests page, using the following URL: + +> . + +You can also always reach out to us via email, using email address. diff --git a/website/docs/enterprise/get-started.md b/website/docs/enterprise/get-started.md new file mode 100644 index 000000000..cf87defaa --- /dev/null +++ b/website/docs/enterprise/get-started.md @@ -0,0 +1,28 @@ +--- +title: Get started +--- + +Installing authentik is exactly the same process for both Enterprise version and our free [open source](https://github.com/goauthentik/authentik) version. + +> This **_Preview_** version of Enterprise authentik is available with our 2023.8.x release. Send us feedback through the Customer portal or to . + +## Install Enterprise + +To get started working with Enterprise authentik, upgrade to the [2023.8.x](../releases) version or later. For installation steps, refer to our [technical documentation](../installation/index.md) for instructions to install and configure authentik. + +- [Docker Compose installation](../installation/docker-compose.md) +- [Kubernetes installation](../installation/kubernetes.md) + +## Access Enterprise + +Access your Enterprise features by first [purchasing a license](./manage-enterprise.md#buy-a-license) for the organization. + +To open the Customer portal and buy a license, go to the Admin interface and in the left pane, navigate to **Enterprise -> Licenses**, and then click **Go to Customer portal**. + +The license key provides direct access to the Customer portal, where you define your organization and its members, manage billing, and access our Support center. + +## Visit the Support center + +Enterprise authentik provides dedicated support, with a Support center where you can open a request and view the progress and communications for your current requests. + +To learn about our Support center, see ["Enterprise support"](./entsupport.md). diff --git a/website/docs/enterprise/index.md b/website/docs/enterprise/index.md new file mode 100644 index 000000000..2a963f517 --- /dev/null +++ b/website/docs/enterprise/index.md @@ -0,0 +1,13 @@ +--- +title: Welcome to authentik Enterprise +--- + +The Enterprise release of authentik provides all of the functionality that we have spent years building in our open source product, with a full support plan and an expanded feature set. + +Refer to our Enterprise documentation for information about creating and managing your organization, purchasing and activating a license, support, and managing billing and organization members. + +- [Get started with Enterprise](./get-started.md) +- [Manage your Enterprise account](./manage-enterprise.md) +- [Support for Enterprise accounts](./entsupport.md) + +Our standard technical documentation covers how to configure, customize, and use authentik, whether the open source version that we have built our reputation on, or our Enterprise version with dedicated support. diff --git a/website/docs/enterprise/licenses-page-admin.png b/website/docs/enterprise/licenses-page-admin.png new file mode 100644 index 000000000..92b264a19 Binary files /dev/null and b/website/docs/enterprise/licenses-page-admin.png differ diff --git a/website/docs/enterprise/manage-enterprise.md b/website/docs/enterprise/manage-enterprise.md new file mode 100644 index 000000000..b1f0eee7b --- /dev/null +++ b/website/docs/enterprise/manage-enterprise.md @@ -0,0 +1,132 @@ +--- +title: Manage your Enterprise account +--- + +## Organization management + +Your organization defines the members, their roles, the licenses associated with the organization, and account management for billing, payment methods, and invoice history. + +### Create an Organization + +1. To create a new organization, log in to the [Customer portal](./get-started#access-enterprise). + +2. On the **My organizations** page, click **Create an organization**. + +3. Specify the organization's name and notification email address, and then click **Create**. + + Your new organization page displays. + +:::info +If you need to delete an organization open a ticket in the Support center. +::: + +### Add/remove members of an organization + +In the Customer portal you can remove members and invite new members to the organization. When you invite new members, you can specify the role for the new member. + +- **Member**: can view licenses, including the license key. +- **Owner**: can do everything the Member role can do, plus: add and remove members, order and renew licenses, and edit the organization. + +1. To manage membership in an organization, log in to the [Customer portal](./get-started#access-enterprise). + +2. On the **My organizations** page, click the name of the organization you want to edit membership in. + + Your organization page displays. + + - To remove a member, scroll down to the **Membership** area and then click **Remove** beside the name of the member. + + - To invite a new member, scroll down to the **Pending invitations** area, and enter the email address for the person, select the role, and then click **Invite**. + + A message appears that the invitation has been sent. When the recipient accepts the invitation by clicking a link in the email, they will be added to the organization. + +## License management + +### Buy a license + +:::info +[Learn more](#about-users) about **internal** and **external** users, and how we forecast the number of users. +::: + +1. To get a license key, log in to your authentik account with your admin credentials, and then click **Admin interface** in the upper right. + +!["Admin interface licenses page"](./licenses-page-admin.png) + +2. On the **Admin interface**, navigate to **Enterprise → Licenses** in the left menu, and then click **Go to Customer portal** under the **Get a license** section. + +3. In the Authentik login screen, sign up and then log in to the Customer Portal. + + In the Customer Portal, if you have not already created an Organization (nor been invited to join one), you are first prompted to create an organization. + +4. On the **My organizations** page, click **Create an organization**. + +5. Specify the organization's name and notification email address, and then click **Create**. + + Your new organization page displays. + +6. Click **Purchase license**, and then on the **Purchase a license** page, review the pricing plans and (optionally) change the name of the license. The name is simply a nickname, a convenient way to label the license. + +7. Click **Continue** to display the checkout page. Select the number of users, provide your payment information, and then click **Subscribe**. + + When payment verification is complete, you are redirected to the **My organizations** page, where you should see a message saying "Successful purchase. Your license will appear here once we've validated your payment. If it doesn't, please contact us." + + When ready, the license displays on the organization's page. + +:::info +If you access the checkout page directly from the Customer portal, and not through the admin interface, you are prompted to provide the Install ID for your authentik installation. This ID can be found in the Admin interface on the **Licenses** page; click **Install** to view the **Install ID** number. +::: + +8. To retrieve your license key, click on **Details** beside the license name and copy the key to your clipboard. + +9. Go back to the Admin interface, navigate to **Enterprise -> Licenses** page, click on **Install**, paste the key, and then click **Install**. + +#### License verification + +To verify that the license was successfully installed, confirm that the expriry date on the **Enterprise --> Licenses** page displays a date one year later. + +### How to view your license key + +You can view the list of licenses that are applied to your organization on either the Admin interface, on the **Enterprise -> Licenses** page, or in the Customer portal, under your organization's page. + +### About the license expiry date + +The **Enterprise -> Licenses** page shows your current licenses' **Cumulative license expiry**. Expiry date calculation works by verifying the individual expiry date for all valid licenses and then picking the lowest expiry date. After the date of the earliest expiring license, all calculations will be updated without that license, by selecting the next earliest date. + +### License violation notifications + +The following events occur when a license expeires and is not renewed within two weeks. + +- After 2 weeks of the expiry date administrators see a warning banner on the Admin interface + +- After another 2 weeks, users get a warning banner + +- After another 2 weeks, the authentik Enterprise instance becomes “read-only” + +### About users and licenses + +License usage is calculated based on total user counts and log-in data data that authentik regularly captures. This data is checked against all valid licenses, and the sum total of all users. + +- The **_default user_** count is calculated based on actual users assigned to the organization. + +- The **_external user_** count is calculated based on how many external users were active (i.e. logged in) since the start of the current month. + +:::info +An **internal** user is typically a team member, such as company employees, who gets access to the full Enterprise feature set. An **external** user might be an external consultant or a B2C customer who logged onto your website to shop. These users don't get access to enterprise features. +::: + +## Manage Billing + +Billing is based on each individual organization. + +1. To manage your billing, go to the Customer portal and click "My organizations" in the top menu bar. + +2. Select the organization for which you want to manage bulling. + + The organization detail page displays. + +3. Click **Manage Billing** in the top left of the page. + + On the billing page you can: + + - update your account information (address, name, phone number, and tax ID) + - add a payment method + - view your invoice and payment history diff --git a/website/docs/releases/2023/v2023.5.md b/website/docs/releases/2023/v2023.5.md index f879b205e..5ec1d2f68 100644 --- a/website/docs/releases/2023/v2023.5.md +++ b/website/docs/releases/2023/v2023.5.md @@ -152,6 +152,10 @@ image: - \*: fix [CVE-2023-36456](../security/CVE-2023-36456), Reported by [@thijsa](https://github.com/thijsa) +## Fixed in 2023.5.6 + +- \*: fix [CVE-2023-39522](../security/CVE-2023-39522), Reported by [@markrassamni](https://github.com/markrassamni) + ## API Changes #### What's Changed diff --git a/website/docs/releases/2023/v2023.6.md b/website/docs/releases/2023/v2023.6.md index a81ade848..7032044d0 100644 --- a/website/docs/releases/2023/v2023.6.md +++ b/website/docs/releases/2023/v2023.6.md @@ -88,6 +88,10 @@ helm upgrade authentik authentik/authentik -f values.yaml --version ^2023.6 - sources/ldap: fix more errors (#6191) - sources/ldap: fix page size (#6187) +## Fixed in 2023.6.2 + +- \*: fix [CVE-2023-39522](../security/CVE-2023-39522), Reported by [@markrassamni](https://github.com/markrassamni) + ## API Changes #### What's New diff --git a/website/docs/releases/2023/v2023.8.md b/website/docs/releases/2023/v2023.8.md index 3075d54df..0e992cb0c 100644 --- a/website/docs/releases/2023/v2023.8.md +++ b/website/docs/releases/2023/v2023.8.md @@ -23,9 +23,17 @@ slug: "/releases/2023.8" ## New features +- Enterprise (preview) + + This is the first release to include the _Enterprise_ section, where you can acquire a license in our Customer Portal and get enterprise licenses for your authentik instance. See more info [here](../../enterprise/index.md) + +- Config reloading + + For better security and to better support running in a cloud-native environment, authentik now supports dynamic PostgreSQL and Email credentials. In previous versions, both the authentik server and worker containers required restarting to detect the new credentials. In 2023.8, these credentials are automatically refreshed just before they are used. This means you can use something like [Hashicorp Vault](https://vaultproject.io) to manage short-term credentials that are rotated once a day or even more frequently without needing to restart authentik. + ## Upgrading -This release does not introduce any new requirements. +This release changes the PostgreSQL dependency to require Version 12 or later, which only affects Kubernetes installs. See [here](../../troubleshooting/postgres/upgrade_kubernetes.md) for more info on upgrading. ### docker-compose @@ -50,11 +58,14 @@ image: ## Minor changes/fixes +- \*: fix api errors raised in general validate() to specify a field (#6663) - api: optimise pagination in API schema (#6478) - blueprints: fix blueprint importer logging potentially sensitive data (#6567) +- blueprints: fix tag values not resolved correctly (#6653) - blueprints: prevent duplicate password stage in default flow when using combined identification stage (#6432) - core: bump django from 4.1.7 to 4.2 (#5238) - core: fix UUID filter field for users api (#6203) +- core: fix filtering users by type attribute (#6638) - core: rework recursive group membership (#6017) - enterprise: add more info to enterprise forecast (#6292) - enterprise: initial enterprise (#5721) @@ -63,15 +74,18 @@ image: - outposts/ldap: add more tests (#6188) - outposts/ldap: add test for attribute filtering (#6189) - outposts: Fix infinite self-recursion in traefik reconciler (#6336) -- outposts: fix patch processing (#6338) +- outposts: fix Kubernetes patch processing (#6338) - outposts: make metrics compliant with Prometheus best-practices (#6398) - outposts: support json patch for Kubernetes (#6319) - providers/oauth2: fix aud (Audience) field type which can be a list of… (#6447) - providers/oauth2: fix grant_type password raising an exception (#6333) +- providers/oauth2: fix id_token being saved incorrectly leading to lost claims (#6645) +- providers/proxy: fix JWKS URL in embedded outpost (#6644) - providers/proxy: only intercept auth header when a value is set (#6488) - providers/proxy: set outpost session cookie to httponly and secure wh… (#6482) -- root: add get_int to config loader instead of casting to int everywhere (#6436) - root: always use persistent database connections (#6560) +- root: config: config discovery parity between Go and Python +- root: config: remove redundant default configs - root: migrate bootstrap to blueprints (#6433) - root: partial Live-updating config (#5959) - root: replace builtin psycopg libpq binary implementation with distro… (#6448) @@ -85,16 +99,31 @@ image: - web/admin: fix admin overview layout (#6220) - web/admin: fix user sorting by active field (#6485) - web/admin: hide pagination when no data is loaded yet (#6353) +- web/admin: make version clickable for stable releases (#6626) +- web/admin: only show token expiry when token is set to expire (#6643) +- web/admin: set required flag to false for user attributes (#6418) +- web/common: make API errors more prominent in developer tools (#6637) +- web/elements: improve table error handling, prevent infinite loading … (#6636) - web/flows: fix identification stage band color (#6489) - web/flows: update flow background (#6579) - web/user: fix alignment between image icons and fallback text icons (#6416) - web/user: fix app icon size for user interface - web/user: fix background alignment (#6383) - web/user: fix user settings colours on dark theme (#6499) +- web/user: fix user settings elements not being in cards (#6608) +- web/user: only render expand element when required (#6641) - web: fix app icon rendering, style refinements (#6409) - web: refactor locale handler into top-level context handler (#6022) +- web: replace deprecated terser rollup plugin, remove unused plugin (#6615) - web: rework and expand tooltips (#6435) +## Fixed in 2023.8.1 + +- blueprints: fix policy exception causing password stage to be skipped after upgrade (#6674) +- root: revert persistent connections causing postgres out of connections errors (#6677) +- web: fix notification drawer scrolling (#6675) +- web/admin: fix version link to release notes (#6676) + ## API Changes #### What's New diff --git a/website/docs/security/CVE-2023-39522.md b/website/docs/security/CVE-2023-39522.md new file mode 100644 index 000000000..18f09b134 --- /dev/null +++ b/website/docs/security/CVE-2023-39522.md @@ -0,0 +1,27 @@ +# CVE-2023-39522 + +_Reported by [@markrassamni](https://github.com/markrassamni)_ + +## Username enumeration attack + +### Summary + +Using a recovery flow with an identification stage an attacker is able to determine if a username exists. + +### Patches + +authentik 2023.5.6 and 2023.6.2 fix this issue. + +### Impact + +Only setups configured with a recovery flow are impacted by this. + +### Details + +An attacker can easily enumerate and check users' existence using the recovery flow, as a clear message is shown when a user doesn't exist. Depending on configuration this can either be done by username, email, or both. + +### For more information + +If you have any questions or comments about this advisory: + +- Email us at [security@goauthentik.io](mailto:security@goauthentik.io) diff --git a/website/package-lock.json b/website/package-lock.json index 6a83cad30..3fe80746f 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -15,7 +15,7 @@ "@mdx-js/react": "^1.6.22", "clsx": "^2.0.0", "disqus-react": "^1.1.5", - "postcss": "^8.4.28", + "postcss": "^8.4.29", "rapidoc": "^9.3.4", "react": "^17.0.2", "react-before-after-slider-component": "^1.1.8", @@ -26,7 +26,7 @@ "remark-github": "^11.2.4" }, "devDependencies": { - "prettier": "3.0.2" + "prettier": "3.0.3" } }, "node_modules/@algolia/autocomplete-core": { @@ -9406,9 +9406,9 @@ } }, "node_modules/postcss": { - "version": "8.4.28", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.28.tgz", - "integrity": "sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==", + "version": "8.4.29", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz", + "integrity": "sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==", "funding": [ { "type": "opencollective", @@ -10008,9 +10008,9 @@ } }, "node_modules/prettier": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.2.tgz", - "integrity": "sha512-o2YR9qtniXvwEZlOKbveKfDQVyqxbEIWn48Z8m3ZJjBjcCmUy3xZGIv+7AkaeuaTr6yPXJjwv07ZWlsWbEy1rQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -20579,9 +20579,9 @@ } }, "postcss": { - "version": "8.4.28", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.28.tgz", - "integrity": "sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==", + "version": "8.4.29", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz", + "integrity": "sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==", "requires": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -20927,9 +20927,9 @@ "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==" }, "prettier": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.2.tgz", - "integrity": "sha512-o2YR9qtniXvwEZlOKbveKfDQVyqxbEIWn48Z8m3ZJjBjcCmUy3xZGIv+7AkaeuaTr6yPXJjwv07ZWlsWbEy1rQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", "dev": true }, "pretty-error": { diff --git a/website/package.json b/website/package.json index 295051de5..654488d7c 100644 --- a/website/package.json +++ b/website/package.json @@ -22,7 +22,7 @@ "@mdx-js/react": "^1.6.22", "clsx": "^2.0.0", "disqus-react": "^1.1.5", - "postcss": "^8.4.28", + "postcss": "^8.4.29", "rapidoc": "^9.3.4", "react": "^17.0.2", "react-before-after-slider-component": "^1.1.8", @@ -45,6 +45,6 @@ ] }, "devDependencies": { - "prettier": "3.0.2" + "prettier": "3.0.3" } } diff --git a/website/sidebars.js b/website/sidebars.js index 6f5307144..6b8a56bdf 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -32,7 +32,7 @@ const docsSidebar = { { type: "category", label: "Core Concepts", - collapsed: false, + collapsed: true, items: [ "core/terminology", "core/applications", @@ -42,6 +42,20 @@ const docsSidebar = { "core/architecture", ], }, + { + type: "category", + label: "Enterprise", + collapsed: true, + link: { + type: "doc", + id: "enterprise/index", + }, + items: [ + "enterprise/get-started", + "enterprise/manage-enterprise", + "enterprise/entsupport", + ], + }, { type: "category", label: "Providers", @@ -258,13 +272,14 @@ const docsSidebar = { description: "Release notes for recent authentik versions", }, items: [ + "releases/2023/v2023.8", "releases/2023/v2023.6", "releases/2023/v2023.5", - "releases/2023/v2023.4", { type: "category", label: "Previous versions", items: [ + "releases/2023/v2023.4", "releases/2023/v2023.3", "releases/2023/v2023.2", "releases/2023/v2023.1", @@ -347,6 +362,7 @@ const docsSidebar = { }, items: [ "security/policy", + "security/CVE-2023-39522", "security/CVE-2023-36456", "security/2023-06-cure53", "security/CVE-2023-26481", diff --git a/website/src/pages/pricing/index.jsx b/website/src/pages/pricing/index.jsx index 11cb4e635..1d3e4ded2 100644 --- a/website/src/pages/pricing/index.jsx +++ b/website/src/pages/pricing/index.jsx @@ -2,6 +2,7 @@ import React from "react"; import Layout from "@theme/Layout"; import Link from "@docusaurus/Link"; import Card from "../../components/PricingQuestions/Card"; +import useBaseUrl from "@docusaurus/useBaseUrl"; export default function pricingPage() { return ( @@ -64,10 +65,12 @@ export default function pricingPage() { /external user/month - Join waitlist + Get Started diff --git a/website/src/pages/pricing/waitlist/enterprise.jsx b/website/src/pages/pricing/waitlist/enterprise.jsx deleted file mode 100644 index 5035945ea..000000000 --- a/website/src/pages/pricing/waitlist/enterprise.jsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react"; -import { WaitListForm } from "../../../components/Waitlist"; -import Layout from "@theme/Layout"; - -export default function waitListEnterprise() { - return ( - - - - ); -}