Compare commits

...

17 Commits

Author SHA1 Message Date
06337283e8 fix migrations correctly
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-01-16 16:50:46 +01:00
5d28114a4b remove USER_ATTRIBUTE_DEBUG
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-01-16 15:49:05 +01:00
b7c154ccd2 dont always try to pull the image
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-01-16 15:49:05 +01:00
d1fbf2ed65 remove leftover code
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
2025-01-16 15:49:03 +01:00
f35457492b website/integrations: snipe-it: remove ldap property mapping (#12688)
* Remove property mapping from snipe-it

https://github.com/goauthentik/authentik/issues/7058
Property mapping for ldap outpost is not supported at the moment. I removed it, because it creates too much confusion.

Signed-off-by: RogueThorn <DunklerPhoenix@users.noreply.github.com>

* format

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: RogueThorn <DunklerPhoenix@users.noreply.github.com>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
2025-01-16 14:41:22 +00:00
af9ba83529 providers/oauth2: support token revocation for public clients (#12704) 2025-01-16 15:27:37 +01:00
3c6cb9dbad core: bump sentry-sdk from 2.19.2 to 2.20.0 (#12694)
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 2.19.2 to 2.20.0.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/2.19.2...2.20.0)

---
updated-dependencies:
- dependency-name: sentry-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-16 15:15:54 +01:00
1d63359077 core: bump psycopg from 3.2.3 to 3.2.4 (#12695)
Bumps [psycopg](https://github.com/psycopg/psycopg) from 3.2.3 to 3.2.4.
- [Changelog](https://github.com/psycopg/psycopg/blob/master/docs/news.rst)
- [Commits](https://github.com/psycopg/psycopg/compare/3.2.3...3.2.4)

---
updated-dependencies:
- dependency-name: psycopg
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-16 15:15:40 +01:00
33121d86f2 core: bump google-api-python-client from 2.158.0 to 2.159.0 (#12697)
Bumps [google-api-python-client](https://github.com/googleapis/google-api-python-client) from 2.158.0 to 2.159.0.
- [Release notes](https://github.com/googleapis/google-api-python-client/releases)
- [Commits](https://github.com/googleapis/google-api-python-client/compare/v2.158.0...v2.159.0)

---
updated-dependencies:
- dependency-name: google-api-python-client
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-16 15:15:30 +01:00
0c235909a2 core: bump msgraph-sdk from 1.16.0 to 1.17.0 (#12698)
Bumps [msgraph-sdk](https://github.com/microsoftgraph/msgraph-sdk-python) from 1.16.0 to 1.17.0.
- [Release notes](https://github.com/microsoftgraph/msgraph-sdk-python/releases)
- [Changelog](https://github.com/microsoftgraph/msgraph-sdk-python/blob/main/CHANGELOG.md)
- [Commits](https://github.com/microsoftgraph/msgraph-sdk-python/compare/v1.16.0...v1.17.0)

---
updated-dependencies:
- dependency-name: msgraph-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-16 15:15:20 +01:00
91ef8c2c8d core: bump aws-cdk-lib from 2.175.1 to 2.176.0 (#12696)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-16 12:37:32 +01:00
4ee45bb5cc website: bump aws-cdk from 2.175.1 to 2.176.0 in /website (#12692)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-16 12:37:19 +01:00
b4ae3ba390 website/integrations: terrakube: document (#12662)
* website/integrations: terrakube: document

* website/integrations: terrakube: lint

* Update website/integrations/services/terrakube/index.md

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: 4d62 <git@sdko.org>

* Update website/integrations/services/terrakube/index.md

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: 4d62 <git@sdko.org>

* Update website/integrations/services/terrakube/index.md

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: 4d62 <git@sdko.org>

* Update website/integrations/services/terrakube/index.md

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: 4d62 <git@sdko.org>

* Update website/integrations/services/terrakube/index.md

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: 4d62 <git@sdko.org>

* Update website/integrations/services/terrakube/index.md

Signed-off-by: 4d62 <git@sdko.org>

* Apply suggestions from code review

Signed-off-by: 4d62 <git@sdko.org>

* Update website/integrations/services/terrakube/index.md

Signed-off-by: 4d62 <git@sdko.org>

---------

Signed-off-by: 4d62 <git@sdko.org>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-01-16 03:33:08 +00:00
f3834016dc website/docs: add note for trailing-slash in initial setup (#12583)
* docs: add note for trailing-slash in initial setup

Signed-off-by: Mahmoud Abduljawad <mahmoud@masaar.com>

* docs: add note for trailing-slash in k8s initial setup

Signed-off-by: Mahmoud Abduljawad <mahmoud@masaar.com>

* docs: refactor to use admonition syntax

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Mahmoud Abduljawad <abduljawad.mahmoud@gmail.com>

* docs: update wording

Signed-off-by: Mahmoud Abduljawad <mahmoud@masaar.com>

* docs: update wording

Signed-off-by: Mahmoud Abduljawad <mahmoud@masaar.com>

* docs: reword for natural language

Co-authored-by: 4d62 <git@sdko.org>
Signed-off-by: Mahmoud Abduljawad <abduljawad.mahmoud@gmail.com>

* docs: reword for natural language

Signed-off-by: Mahmoud Abduljawad <mahmoud@masaar.com>

* docs: typo

Satisfy `codespell` by changing "falsy" to "false".

---------

Signed-off-by: Mahmoud Abduljawad <mahmoud@masaar.com>
Signed-off-by: Mahmoud Abduljawad <abduljawad.mahmoud@gmail.com>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Co-authored-by: 4d62 <git@sdko.org>
2025-01-15 20:44:50 -06:00
661a966e23 website/integrations: Update Semaphore UI description (#12674)
* Update index.mdx

Signed-off-by: Christopher Fenner <9592452+CFenner@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: Christopher Fenner <9592452+CFenner@users.noreply.github.com>

* Update index.mdx

Signed-off-by: Christopher Fenner <9592452+CFenner@users.noreply.github.com>

* Update index.mdx

Signed-off-by: Christopher Fenner <9592452+CFenner@users.noreply.github.com>

---------

Signed-off-by: Christopher Fenner <9592452+CFenner@users.noreply.github.com>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-01-15 18:13:33 -06:00
813273338e website/integrations: pgadmin: refactor (#12604)
* website/integrations: pgadmin: refactor

Refactors the pgAdmin integration documentation, makes it match existing style guide, and adds subsection for configuration for containerized deployments

* website/integrations: pgadmin: lint

Lints refactored documentation page

* Update website/integrations/services/pgadmin/index.md

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: 4d62 <git@sdko.org>

* website/integrations: pgadmin: updates note

Adds back "based on" note with updated versions

* website/integrations: pgadmin: specify strict/regex rediect uri

Not sure on wording tho

* website/integrations: pgadmin: add configuration validation step

Adds configuration validation step. Log out, log back in with authentik. Button on login page

* website/integrations: pgadmin: fix redirect uri

Fixes incorrect redirect uri introduced during refactor. Probably forgot to copy slug or something. Important thing is that it's fixed

Signed-off-by: 4d62 <git@sdko.org>

* website/integrations: pgadmin: fix another stupidity I probably made

Glorious https://img.sdko.org/u/0k3f46.png

Signed-off-by: 4d62 <git@sdko.org>

---------

Signed-off-by: 4d62 <git@sdko.org>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-01-15 13:37:51 -06:00
99639a9ed0 website/integrations: add Actual budget (#12590)
* Update sidebarsIntegrations.js

Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

* Create index.mdx for Actual Budget

Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

* Update website/integrations/services/actual-budget/index.mdx

Co-authored-by: 4d62 <git@sdko.org>
Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

* Changes made for comments of @4d62

Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

* warning about first user

Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

* make lint & make website...

* removed old dev stuff changes

* index.mdx aktualisieren

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

* index.mdx aktualisieren

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

* index.mdx aktualisieren

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

* index.mdx aktualisieren

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

* index.mdx aktualisieren

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

* index.mdx aktualisieren

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

* Remove step 3 and marketing Blabla

* index.mdx aktualisieren

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

* index.mdx aktualisieren

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

* index.mdx aktualisieren

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

* index.mdx aktualisieren

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

* index.mdx aktualisieren

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

* index.mdx aktualisieren

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

* index.mdx aktualisieren

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

* index.mdx aktualisieren

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

* index.mdx aktualisieren

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

* index.mdx aktualisieren

Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

* Update website/integrations/services/actual-budget/index.mdx

Co-authored-by: 4d62 <git@sdko.org>
Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

* hope that helps a bit => step 6

remove the part about client id and secret with description that it is from authentik because step 6 clears this already up and during the setup of the provider in authentik there is a hint that ID and secret is need later in this guide

Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

* Update index.mdx

now with italic instead of codestuff for placeholders or variables

Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>

---------

Signed-off-by: NiceDevil <17103076+nicedevil007@users.noreply.github.com>
Co-authored-by: 4d62 <git@sdko.org>
Co-authored-by: nicedevil007 <nicedevil007@users.noreply.github.com>
Co-authored-by: Tana M Berry <tanamarieberry@yahoo.com>
2025-01-15 13:30:01 -06:00
30 changed files with 437 additions and 232 deletions

View File

@ -209,7 +209,7 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet):
@extend_schema(
parameters=[
OpenApiParameter(
name="superuser_full_list",
name="list_rbac",
location=OpenApiParameter.QUERY,
type=OpenApiTypes.BOOL,
),
@ -229,10 +229,8 @@ class ApplicationViewSet(UsedByMixin, ModelViewSet):
"""Custom list method that checks Policy based access instead of guardian"""
should_cache = request.query_params.get("search", "") == ""
superuser_full_list = (
str(request.query_params.get("superuser_full_list", "false")).lower() == "true"
)
if superuser_full_list and request.user.is_superuser:
list_rbac = str(request.query_params.get("list_rbac", "false")).lower() == "true"
if list_rbac:
return super().list(request)
only_with_launch_url = str(

View File

@ -4,7 +4,7 @@ from typing import Any
from django.utils.timezone import now
from drf_spectacular.utils import OpenApiResponse, extend_schema, inline_serializer
from guardian.shortcuts import assign_perm, get_anonymous_user
from guardian.shortcuts import assign_perm
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
from rest_framework.fields import CharField
@ -138,13 +138,8 @@ class TokenViewSet(UsedByMixin, ModelViewSet):
owner_field = "user"
rbac_allow_create_without_perm = True
def get_queryset(self):
user = self.request.user if self.request else get_anonymous_user()
if user.is_superuser:
return super().get_queryset()
return super().get_queryset().filter(user=user.pk)
def perform_create(self, serializer: TokenSerializer):
# TODO: better permission check
if not self.request.user.is_superuser:
instance = serializer.save(
user=self.request.user,

View File

@ -0,0 +1,57 @@
# Generated by Django 5.0.10 on 2025-01-08 17:39
from django.db import migrations
from django.apps.registry import Apps
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
def migrate_user_debug_attribute(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
from django.apps import apps as real_apps
from django.contrib.auth.management import create_permissions
db_alias = schema_editor.connection.alias
User = apps.get_model("authentik_core", "User")
USER_ATTRIBUTE_DEBUG = "goauthentik.io/user/debug"
# Permissions are only created _after_ migrations are run
# - https://github.com/django/django/blob/43cdfa8b20e567a801b7d0a09ec67ddd062d5ea4/django/contrib/auth/apps.py#L19
# - https://stackoverflow.com/a/72029063/1870445
create_permissions(real_apps.get_app_config("authentik_core"), using=db_alias)
Permission = apps.get_model("auth", "Permission")
new_prem = Permission.objects.using(db_alias).get(codename="user_view_debug")
db_alias = schema_editor.connection.alias
for user in User.objects.using(db_alias).filter(
**{f"attributes__{USER_ATTRIBUTE_DEBUG}": True}
):
user.permissions.add(new_prem)
class Migration(migrations.Migration):
dependencies = [
("authentik_core", "0042_authenticatedsession_authentik_c_expires_08251d_idx_and_more"),
]
operations = [
migrations.AlterModelOptions(
name="user",
options={
"permissions": [
("reset_user_password", "Reset Password"),
("impersonate", "Can impersonate other users"),
("assign_user_permissions", "Can assign permissions to users"),
("unassign_user_permissions", "Can unassign permissions from users"),
("preview_user", "Can preview user data sent to providers"),
("view_user_applications", "View applications the user has access to"),
("user_view_debug", "User receives additional details for error messages"),
],
"verbose_name": "User",
"verbose_name_plural": "Users",
},
),
migrations.RunPython(migrate_user_debug_attribute),
]

View File

@ -41,7 +41,6 @@ from authentik.tenants.models import DEFAULT_TOKEN_DURATION, DEFAULT_TOKEN_LENGT
from authentik.tenants.utils import get_current_tenant, get_unique_identifier
LOGGER = get_logger()
USER_ATTRIBUTE_DEBUG = "goauthentik.io/user/debug"
USER_ATTRIBUTE_GENERATED = "goauthentik.io/user/generated"
USER_ATTRIBUTE_EXPIRES = "goauthentik.io/user/expires"
USER_ATTRIBUTE_DELETE_ON_LOGOUT = "goauthentik.io/user/delete-on-logout"
@ -282,6 +281,7 @@ class User(SerializerModel, GuardianUserMixin, AttributesMixin, AbstractUser):
("unassign_user_permissions", _("Can unassign permissions from users")),
("preview_user", _("Can preview user data sent to providers")),
("view_user_applications", _("View applications the user has access to")),
("user_view_debug", _("User receives additional details for error messages")),
]
indexes = [
models.Index(fields=["last_login"]),

View File

@ -96,7 +96,7 @@ class EndpointViewSet(UsedByMixin, ModelViewSet):
OpenApiTypes.STR,
),
OpenApiParameter(
name="superuser_full_list",
name="list_rbac",
location=OpenApiParameter.QUERY,
type=OpenApiTypes.BOOL,
),
@ -110,8 +110,8 @@ class EndpointViewSet(UsedByMixin, ModelViewSet):
"""List accessible endpoints"""
should_cache = request.GET.get("search", "") == ""
superuser_full_list = str(request.GET.get("superuser_full_list", "false")).lower() == "true"
if superuser_full_list and request.user.is_superuser:
list_rbac = str(request.GET.get("list_rbac", "false")).lower() == "true"
if list_rbac:
return super().list(request)
queryset = self._filter_queryset_for_list(self.get_queryset())

View File

@ -97,12 +97,9 @@ class FlowErrorChallenge(Challenge):
if not request or not error:
return
self.initial_data["request_id"] = request.request_id
from authentik.core.models import USER_ATTRIBUTE_DEBUG
if request.user and request.user.is_authenticated:
if request.user.is_superuser or request.user.group_attributes(request).get(
USER_ATTRIBUTE_DEBUG, False
):
if request.user.has_perm("authentik_core.user_view_debug"):
self.initial_data["error"] = str(error)
self.initial_data["traceback"] = exception_to_string(error)

View File

@ -13,6 +13,7 @@ from paramiko.ssh_exception import SSHException
from structlog.stdlib import get_logger
from yaml import safe_dump
from authentik import __version__
from authentik.outposts.apps import MANAGED_OUTPOST
from authentik.outposts.controllers.base import BaseClient, BaseController, ControllerException
from authentik.outposts.docker_ssh import DockerInlineSSH, SSHManagedExternallyException
@ -182,10 +183,16 @@ class DockerController(BaseController):
`outposts.container_image_base`, but fall back to known-good images"""
image = self.get_container_image()
try:
self.client.images.pull(image)
except DockerException: # pragma: no cover
image = f"ghcr.io/goauthentik/{self.outpost.type}:latest"
self.client.images.pull(image)
# See if the image exists...
self.client.images.get(image)
except DockerException:
try:
# ...otherwise try to pull it...
self.client.images.pull(image)
except DockerException:
# ...and as a fallback to that default to a sane standard
image = f"ghcr.io/goauthentik/{self.outpost.type}:{__version__}"
self.client.images.pull(image)
return image
def _get_container(self) -> tuple[Container, bool]:

View File

@ -7,7 +7,7 @@ from django.template.response import TemplateResponse
from django.urls import reverse
from django.utils.translation import gettext as _
from authentik.core.models import USER_ATTRIBUTE_DEBUG
from authentik.core.models import User
from authentik.policies.types import PolicyResult
@ -31,12 +31,11 @@ class AccessDeniedResponse(TemplateResponse):
if self.error_message:
context["error"] = self.error_message
# Only show policy result if user is authenticated and
# either superuser or has USER_ATTRIBUTE_DEBUG set
# has permissions to see them
if self.policy_result:
if self._request.user and self._request.user.is_authenticated:
if self._request.user.is_superuser or self._request.user.group_attributes(
self._request
).get(USER_ATTRIBUTE_DEBUG, False):
user: User = self._request.user
if user.has_perm("authentik_core.user_view_debug"):
context["policy_result"] = self.policy_result
context["cancel"] = reverse("authentik_flows:cancel")
return context

View File

@ -2,11 +2,8 @@
from json import dumps
from django_filters.rest_framework import DjangoFilterBackend
from guardian.utils import get_anonymous_user
from rest_framework import mixins
from rest_framework.fields import CharField, ListField, SerializerMethodField
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.viewsets import GenericViewSet
from authentik.core.api.used_by import UsedByMixin
@ -66,17 +63,7 @@ class AuthorizationCodeViewSet(
serializer_class = ExpiringBaseGrantModelSerializer
filterset_fields = ["user", "provider"]
ordering = ["provider", "expires"]
filter_backends = [
DjangoFilterBackend,
OrderingFilter,
SearchFilter,
]
def get_queryset(self):
user = self.request.user if self.request else get_anonymous_user()
if user.is_superuser:
return super().get_queryset()
return super().get_queryset().filter(user=user.pk)
owner_field = "user"
class RefreshTokenViewSet(
@ -92,17 +79,7 @@ class RefreshTokenViewSet(
serializer_class = TokenModelSerializer
filterset_fields = ["user", "provider"]
ordering = ["provider", "expires"]
filter_backends = [
DjangoFilterBackend,
OrderingFilter,
SearchFilter,
]
def get_queryset(self):
user = self.request.user if self.request else get_anonymous_user()
if user.is_superuser:
return super().get_queryset()
return super().get_queryset().filter(user=user.pk)
owner_field = "user"
class AccessTokenViewSet(
@ -118,14 +95,4 @@ class AccessTokenViewSet(
serializer_class = TokenModelSerializer
filterset_fields = ["user", "provider"]
ordering = ["provider", "expires"]
filter_backends = [
DjangoFilterBackend,
OrderingFilter,
SearchFilter,
]
def get_queryset(self):
user = self.request.user if self.request else get_anonymous_user()
if user.is_superuser:
return super().get_queryset()
return super().get_queryset().filter(user=user.pk)
owner_field = "user"

View File

@ -12,6 +12,7 @@ from authentik.core.tests.utils import create_test_admin_user, create_test_cert,
from authentik.lib.generators import generate_id
from authentik.providers.oauth2.models import (
AccessToken,
ClientTypes,
IDToken,
OAuth2Provider,
RedirectURI,
@ -108,3 +109,29 @@ class TesOAuth2Revoke(OAuthTestCase):
},
)
self.assertEqual(res.status_code, 401)
def test_revoke_public(self):
"""Test revoke public client"""
self.provider.client_type = ClientTypes.PUBLIC
self.provider.save()
token: AccessToken = AccessToken.objects.create(
provider=self.provider,
user=self.user,
token=generate_id(),
auth_time=timezone.now(),
_scope="openid user profile",
_id_token=json.dumps(
asdict(
IDToken("foo", "bar"),
)
),
)
auth_public = b64encode(f"{self.provider.client_id}:{generate_id()}".encode()).decode()
res = self.client.post(
reverse("authentik_providers_oauth2:token-revoke"),
HTTP_AUTHORIZATION=f"Basic {auth_public}",
data={
"token": token.token,
},
)
self.assertEqual(res.status_code, 200)

View File

@ -178,12 +178,18 @@ def protected_resource_view(scopes: list[str]):
return wrapper
def authenticate_provider(request: HttpRequest) -> OAuth2Provider | None:
"""Attempt to authenticate via Basic auth of client_id:client_secret"""
def provider_from_request(request: HttpRequest) -> tuple[OAuth2Provider | None, str, str]:
"""Get provider from Basic auth of client_id:client_secret. Does not perform authentication"""
client_id, client_secret = extract_client_auth(request)
if client_id == client_secret == "":
return None
return None, "", ""
provider: OAuth2Provider | None = OAuth2Provider.objects.filter(client_id=client_id).first()
return provider, client_id, client_secret
def authenticate_provider(request: HttpRequest) -> OAuth2Provider | None:
"""Attempt to authenticate via Basic auth of client_id:client_secret"""
provider, client_id, client_secret = provider_from_request(request)
if not provider:
return None
if client_id != provider.client_id or client_secret != provider.client_secret:

View File

@ -9,8 +9,12 @@ from django.views.decorators.csrf import csrf_exempt
from structlog.stdlib import get_logger
from authentik.providers.oauth2.errors import TokenRevocationError
from authentik.providers.oauth2.models import AccessToken, OAuth2Provider, RefreshToken
from authentik.providers.oauth2.utils import TokenResponse, authenticate_provider
from authentik.providers.oauth2.models import AccessToken, ClientTypes, OAuth2Provider, RefreshToken
from authentik.providers.oauth2.utils import (
TokenResponse,
authenticate_provider,
provider_from_request,
)
LOGGER = get_logger()
@ -27,7 +31,9 @@ class TokenRevocationParams:
"""Extract required Parameters from HTTP Request"""
raw_token = request.POST.get("token")
provider = authenticate_provider(request)
provider, _, _ = provider_from_request(request)
if provider and provider.client_type == ClientTypes.CONFIDENTIAL:
provider = authenticate_provider(request)
if not provider:
raise TokenRevocationError("invalid_client")

View File

@ -83,7 +83,7 @@ class RedirectStageView(ChallengeStageView):
target_url_override = self.executor.plan.context.get(PLAN_CONTEXT_REDIRECT_STAGE_TARGET, "")
if target_url_override:
target = self.parse_target(target_url_override)
# `target` is falsy if the override was to a Flow but that Flow doesn't exist.
# `target` is false if the override was to a Flow but that Flow doesn't exist.
if not target:
if current_stage.mode == RedirectMode.STATIC:
target = current_stage.target_static

View File

@ -6445,6 +6445,7 @@
"authentik_core.remove_user_from_group",
"authentik_core.reset_user_password",
"authentik_core.unassign_user_permissions",
"authentik_core.user_view_debug",
"authentik_core.view_application",
"authentik_core.view_applicationentitlement",
"authentik_core.view_authenticatedsession",
@ -12694,6 +12695,7 @@
"authentik_core.remove_user_from_group",
"authentik_core.reset_user_password",
"authentik_core.unassign_user_permissions",
"authentik_core.user_view_debug",
"authentik_core.view_application",
"authentik_core.view_applicationentitlement",
"authentik_core.view_authenticatedsession",
@ -13202,6 +13204,7 @@
"unassign_user_permissions",
"preview_user",
"view_user_applications",
"user_view_debug",
"add_user",
"change_user",
"delete_user",

47
poetry.lock generated
View File

@ -408,13 +408,13 @@ typeguard = ">=2.13.3,<4.3.0"
[[package]]
name = "aws-cdk-lib"
version = "2.175.1"
version = "2.176.0"
description = "Version 2 of the AWS Cloud Development Kit library"
optional = false
python-versions = "~=3.8"
files = [
{file = "aws_cdk_lib-2.175.1-py3-none-any.whl", hash = "sha256:d66ac587a3571b6bfcf11b07f04f02ff3f12e42e87c8783aadb6043df7f638f6"},
{file = "aws_cdk_lib-2.175.1.tar.gz", hash = "sha256:e7bafecb2b9de7e315f0c615a88bc91d226e1ddea3cdfaf4c72c6b6f48a78c74"},
{file = "aws_cdk_lib-2.176.0-py3-none-any.whl", hash = "sha256:c362a92f06b6ea60a7eff7994d3994c462358e7a95ce3de01a28efab4f6d56b6"},
{file = "aws_cdk_lib-2.176.0.tar.gz", hash = "sha256:87a39d2f42fd2ea8ba2bfa364355303953fb5cc2886479ca5acf09a14a9fd679"},
]
[package.dependencies]
@ -1922,13 +1922,13 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"]
[[package]]
name = "google-api-python-client"
version = "2.158.0"
version = "2.159.0"
description = "Google API Client Library for Python"
optional = false
python-versions = ">=3.7"
files = [
{file = "google_api_python_client-2.158.0-py2.py3-none-any.whl", hash = "sha256:36f8c8d2e79e50f76790ca5946d2f3f8333e210dc8539a6c88e0742416474ad2"},
{file = "google_api_python_client-2.158.0.tar.gz", hash = "sha256:b6664597a9955e04977a62752e33fe44cb35c580e190c1cb08a041893172bd67"},
{file = "google_api_python_client-2.159.0-py2.py3-none-any.whl", hash = "sha256:baef0bb631a60a0bd7c0bf12a5499e3a40cd4388484de7ee55c1950bf820a0cf"},
{file = "google_api_python_client-2.159.0.tar.gz", hash = "sha256:55197f430f25c907394b44fa078545ffef89d33fd4dca501b7db9f0d8e224bd6"},
]
[package.dependencies]
@ -3107,13 +3107,13 @@ dev = ["bumpver", "isort", "mypy", "pylint", "pytest", "yapf"]
[[package]]
name = "msgraph-sdk"
version = "1.16.0"
version = "1.17.0"
description = "The Microsoft Graph Python SDK"
optional = false
python-versions = ">=3.8"
python-versions = ">=3.9"
files = [
{file = "msgraph_sdk-1.16.0-py3-none-any.whl", hash = "sha256:1dd26ece74c43167818e2ff58b062180233ce7187ad2a061057af1195395c56c"},
{file = "msgraph_sdk-1.16.0.tar.gz", hash = "sha256:980d19617d8d8b20545ef77fa5629fef768ce4ea1f2d1a124c5a9dd88d77940c"},
{file = "msgraph_sdk-1.17.0-py3-none-any.whl", hash = "sha256:5582a258ded19a486ab407a67b5f65d666758a63864da77bd20c2581d1c00fba"},
{file = "msgraph_sdk-1.17.0.tar.gz", hash = "sha256:577e41942b0f794b8cf2f54db030bc039a750a81b515dcd0ba1d66fd961fa7bf"},
]
[package.dependencies]
@ -3800,36 +3800,36 @@ files = [
[[package]]
name = "psycopg"
version = "3.2.3"
version = "3.2.4"
description = "PostgreSQL database adapter for Python"
optional = false
python-versions = ">=3.8"
files = [
{file = "psycopg-3.2.3-py3-none-any.whl", hash = "sha256:644d3973fe26908c73d4be746074f6e5224b03c1101d302d9a53bf565ad64907"},
{file = "psycopg-3.2.3.tar.gz", hash = "sha256:a5764f67c27bec8bfac85764d23c534af2c27b893550377e37ce59c12aac47a2"},
{file = "psycopg-3.2.4-py3-none-any.whl", hash = "sha256:43665368ccd48180744cab26b74332f46b63b7e06e8ce0775547a3533883d381"},
{file = "psycopg-3.2.4.tar.gz", hash = "sha256:f26f1346d6bf1ef5f5ef1714dd405c67fb365cfd1c6cea07de1792747b167b92"},
]
[package.dependencies]
psycopg-c = {version = "3.2.3", optional = true, markers = "implementation_name != \"pypy\" and extra == \"c\""}
psycopg-c = {version = "3.2.4", optional = true, markers = "implementation_name != \"pypy\" and extra == \"c\""}
typing-extensions = {version = ">=4.6", markers = "python_version < \"3.13\""}
tzdata = {version = "*", markers = "sys_platform == \"win32\""}
[package.extras]
binary = ["psycopg-binary (==3.2.3)"]
c = ["psycopg-c (==3.2.3)"]
dev = ["ast-comments (>=1.1.2)", "black (>=24.1.0)", "codespell (>=2.2)", "dnspython (>=2.1)", "flake8 (>=4.0)", "mypy (>=1.11)", "types-setuptools (>=57.4)", "wheel (>=0.37)"]
binary = ["psycopg-binary (==3.2.4)"]
c = ["psycopg-c (==3.2.4)"]
dev = ["ast-comments (>=1.1.2)", "black (>=24.1.0)", "codespell (>=2.2)", "dnspython (>=2.1)", "flake8 (>=4.0)", "mypy (>=1.14)", "pre-commit (>=4.0.1)", "types-setuptools (>=57.4)", "wheel (>=0.37)"]
docs = ["Sphinx (>=5.0)", "furo (==2022.6.21)", "sphinx-autobuild (>=2021.3.14)", "sphinx-autodoc-typehints (>=1.12)"]
pool = ["psycopg-pool"]
test = ["anyio (>=4.0)", "mypy (>=1.11)", "pproxy (>=2.7)", "pytest (>=6.2.5)", "pytest-cov (>=3.0)", "pytest-randomly (>=3.5)"]
test = ["anyio (>=4.0)", "mypy (>=1.14)", "pproxy (>=2.7)", "pytest (>=6.2.5)", "pytest-cov (>=3.0)", "pytest-randomly (>=3.5)"]
[[package]]
name = "psycopg-c"
version = "3.2.3"
version = "3.2.4"
description = "PostgreSQL database adapter for Python -- C optimisation distribution"
optional = false
python-versions = ">=3.8"
files = [
{file = "psycopg_c-3.2.3.tar.gz", hash = "sha256:06ae7db8eaec1a3845960fa7f997f4ccdb1a7a7ab8dc593a680bcc74e1359671"},
{file = "psycopg_c-3.2.4.tar.gz", hash = "sha256:22097a04263efb2efd2cc8b00a51fa90e23f9cd4a2e09903fe4d9c6923dac17a"},
]
[[package]]
@ -4710,13 +4710,13 @@ websocket-client = ">=1.8,<2.0"
[[package]]
name = "sentry-sdk"
version = "2.19.2"
version = "2.20.0"
description = "Python client for Sentry (https://sentry.io)"
optional = false
python-versions = ">=3.6"
files = [
{file = "sentry_sdk-2.19.2-py2.py3-none-any.whl", hash = "sha256:ebdc08228b4d131128e568d696c210d846e5b9d70aa0327dec6b1272d9d40b84"},
{file = "sentry_sdk-2.19.2.tar.gz", hash = "sha256:467df6e126ba242d39952375dd816fbee0f217d119bf454a8ce74cf1e7909e8d"},
{file = "sentry_sdk-2.20.0-py2.py3-none-any.whl", hash = "sha256:c359a1edf950eb5e80cffd7d9111f3dbeef57994cb4415df37d39fda2cf22364"},
{file = "sentry_sdk-2.20.0.tar.gz", hash = "sha256:afa82713a92facf847df3c6f63cec71eb488d826a50965def3d7722aa6f0fdab"},
]
[package.dependencies]
@ -4761,6 +4761,7 @@ sqlalchemy = ["sqlalchemy (>=1.2)"]
starlette = ["starlette (>=0.19.1)"]
starlite = ["starlite (>=1.48)"]
tornado = ["tornado (>=6)"]
unleash = ["UnleashClient (>=6.0.1)"]
[[package]]
name = "service-identity"

View File

@ -4,6 +4,9 @@ version = "2024.12.2"
description = ""
authors = ["authentik Team <hello@goauthentik.io>"]
[tool.poetry.requires-plugins]
poetry-plugin-export = ">1.8"
[tool.black]
line-length = 100
target-version = ['py312']

View File

@ -3391,6 +3391,10 @@ paths:
name: group
schema:
type: string
- in: query
name: list_rbac
schema:
type: boolean
- in: query
name: meta_description
schema:
@ -3439,10 +3443,6 @@ paths:
name: slug
schema:
type: string
- in: query
name: superuser_full_list
schema:
type: boolean
tags:
- core
security:
@ -23204,6 +23204,10 @@ paths:
operationId: rac_endpoints_list
description: List accessible endpoints
parameters:
- in: query
name: list_rbac
schema:
type: boolean
- in: query
name: name
schema:
@ -23234,10 +23238,6 @@ paths:
name: search
schema:
type: string
- in: query
name: superuser_full_list
schema:
type: boolean
tags:
- rac
security:

View File

@ -66,7 +66,7 @@ export class ApplicationListPage extends WithBrandConfig(TablePage<Application>)
async apiEndpoint(): Promise<PaginatedResponse<Application>> {
return new CoreApi(DEFAULT_CONFIG).coreApplicationsList({
...(await this.defaultEndpointConfig()),
superuserFullList: true,
listRbac: true,
});
}

View File

@ -156,7 +156,7 @@ export class BrandForm extends ModelForm<Brand, string> {
.fetchObjects=${async (query?: string): Promise<Application[]> => {
const args: CoreApplicationsListRequest = {
ordering: "name",
superuserFullList: true,
listRbac: true,
};
if (query !== undefined) {
args.search = query;

View File

@ -46,7 +46,7 @@ export class EndpointListPage extends Table<Endpoint> {
return new RacApi(DEFAULT_CONFIG).racEndpointsList({
...(await this.defaultEndpointConfig()),
provider: this.provider?.pk,
superuserFullList: true,
listRbac: true,
});
}

View File

@ -117,6 +117,10 @@ The `docker-compose.yml` file statically references the latest version available
To start the initial setup, navigate to `http://<your server's IP or hostname>:9000/if/flow/initial-setup/`.
:::info
You will get `Not Found` error if initial setup URL doesn't include the trailing forward slash `/`. Make sure you use the complete url (`http://<your server's IP or hostname>:9000/if/flow/initial-setup/`) including the trailing forward slash.
:::
There you are prompted to set a password for the `akadmin` user (the default user).
For an explanation about what each service in the docker compose file does, see [Architecture](../../core/architecture.md).

View File

@ -74,6 +74,10 @@ During the installation process, the database migrations will be applied automat
After the installation is complete, access authentik at `https://<ingress-host-name>/if/flow/initial-setup/`. Here, you can set a password for the default `akadmin` user.
:::info
You will get `Not Found` error if initial setup URL doesn't include the trailing forward slash `/`. Make sure you use the complete url (`http://<ingress-host-name>/if/flow/initial-setup/`) including the trailing forward slash.
:::
### Optional step: Configure global email credentials
It is recommended to configure global email credentials as well. These are used by authentik to notify you about alerts and configuration issues. Additionally, they can be utilized by [Email stages](../../add-secure-apps/flows-stages/stages/email/index.mdx) to send verification and recovery emails.

View File

@ -0,0 +1,82 @@
---
title: Integrate with Actual Budget
sidebar_label: Actual Budget
---
# Actual Budget
<span class="badge badge--secondary">Support level: Community</span>
## What is Actual Budget
> Actual Budget is a web-based financial management software. It helps users track and manage their income, expenses, and budgets in real time.
> The software compares actual spending with planned budgets to improve financial decisions.
>
> -- https://actualbudget.org/
>
> This guide explains how to configure Actual Budget to use authentik as the OAuth provider for logging in to the Web GUI.
## Preparation
The following placeholders are used in this guide:
- _actual.company_ is the FQDN of the Actual Budget install.
- _authentik.company_ is the FQDN of the authentik install.
## authentik configuration
[Create](https://docs.goauthentik.io/docs/add-secure-apps/applications/manage_apps#add-new-applications) an OAuth2/OpenID provider and an application in authentik. Use the following parameters for the OAuth2/OpenID provider:
**Provider:**
- Name: _SP-actual_
- Client type: _Confidential_
- Redirect URIs/Origins (RegEx): https://_actual.company_/openid/callback
- Signing Key: Select any available signing keys.
:::info
Actual Budget supports the RS256 algorithm. Be aware of this when choosing the appropriate signing key.
:::
Take note of the Client ID and Client Secret; you will need to provide them to Actual Budget in the last step.
Leave the remaining values as default. Durations can be adjusted as needed.
**Application:**
- Name: _Actual Budget_
- Slug: _actual_
- Launch URL: https://_actual.company_/
## Actual Budget configuration
1. Sign in to Actual Budget with a browser of your choice and access your budget by clicking on its name.
2. Click your budget in the top-left corner to open the dropdown menu and select **Settings**.
3. Scroll to the bottom and select **Show advanced settings**. Scroll again and select **I understand the risks, show experimental features**.
4. To enable the option **OpenID authentication method** select the checkbox next to it.
5. Scroll up to the new option **Authentication method...** and click **Start using OpenID**.
6. Set the following values from the authentik provider:
- Set **OpenID Provider** to **authentik**
- Set **OpenID provider URL** to https://_authentik.company_/application/o/_actual_/
- Set **Client ID** to _client-id_
- Set **Client secret** to _client-secret_
:::warning
The first user to log into Actual Budget via OpenID will become the owner and administrator with the highest privileges for the budget. For more information on how to create additional users, see the Note below.
:::
## Test the login
- Open a browser of your choice and navigate to https://_actual.company_.
- Select the OpenID login method in the dropdown menu and click **Sign in with OpenID**.
- You should be redirected to authentik (with the login flows you created), and then authentik will redirect you back to the https://_actual.company_ URL.
- If you are redirected back to the https://_actual.company_ URL and can see the budget file selection page, the setup was successful.
:::info
Users are not automatically created when logging in with authentik. The owner must manually create each user in Actual Budget. To do so, click **Server online** at the top next to your name and select **User Directory**. Add a new user. The `Username` must match the one in authentik. You can now grant the new user access to your budget by clicking **Server online** next to your name at the top and selecting **User Access**.
:::

View File

@ -14,7 +14,7 @@ sidebar_label: pgAdmin
> -- https://www.pgadmin.org/
:::note
This is based on authentik 2022.3.3 and pgAdmin4 6.19
This is based on authentik 2024.12.2 and pgAdmin4 8.14
:::
## Preparation
@ -24,78 +24,79 @@ The following placeholders are used in this guide:
- `pgadmin.company` is the FQDN of pgAdmin.
- `authentik.company` is the FQDN of authentik.
### Step 1: Create authentik Provider
# authentik configuration
In authentik, under _Providers_, create an _OAuth2/OpenID Provider_ with these settings:
1. From the Admin interface, navigate to **Applications** -> **Applications**.
2. Use the wizard to create a new application and provider. During this process:
- Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later.
- Set a `Strict` redirect URI to `https://pgadmin.company/oauth2/authorize`.
- Select any available signing key.
**Provider Settings**
## pgAdmin OAuth Configuration
- Name: pgAdmin
- Client ID: Copy and Save this for Later
- Client Secret: Copy and Save this for later
- Redirect URIs/Origins: `http://pgadmin.company/oauth2/authorize`
- Signing Key: Select any available key
To configure OAuth in pgAdmin, you can either use the `config_local.py` file or set environment variables if you are deploying pgAdmin in a containerized setup.
### Step 2: Create authentik Application
### Using `config_local.py`
In authentik, create an application which uses this provider. Optionally apply access restrictions to the application using policy bindings.
1. Locate or create the `config_local.py` file in the `/pgadmin4/` directory.
- Name: pgAdmin
- Slug: pgadmin
- Provider: pgAdmin
- Launch URL: https://pgadmin.company
- If the file does not exist, create it manually.
### Step 3: Configure pgAdmin
2. Add the following configuration settings to `config_local.py`:
All settings for OAuth in pgAdmin are configured in the `config_local.py` file. This file can usually be found in the path `/pgadmin4/config_local.py`
```python
AUTHENTICATION_SOURCES = ['oauth2', 'internal']
OAUTH2_AUTO_CREATE_USER = True
OAUTH2_CONFIG = [{
'OAUTH2_NAME': 'authentik',
'OAUTH2_DISPLAY_NAME': 'authentik',
'OAUTH2_CLIENT_ID': '<Client ID from authentik>',
'OAUTH2_CLIENT_SECRET': '<Client secret from authentik>',
'OAUTH2_TOKEN_URL': 'https://authentik.company/application/o/token/',
'OAUTH2_AUTHORIZATION_URL': 'https://authentik.company/application/o/authorize/',
'OAUTH2_API_BASE_URL': 'https://authentik.company/',
'OAUTH2_USERINFO_ENDPOINT': 'https://authentik.company/application/o/userinfo/',
'OAUTH2_SERVER_METADATA_URL': 'https://authentik.company/application/o/<App Slug>/.well-known/openid-configuration',
'OAUTH2_SCOPE': 'openid email profile',
'OAUTH2_ICON': '<Fontawesome icon key (e.g., fa-key)>',
'OAUTH2_BUTTON_COLOR': '<Hexadecimal color code for the login button>'
}]
```
:::note
More information on that file can be found in the official pgAdmin [documentation](https://www.pgadmin.org/docs/pgadmin4/development/config_py.html)
:::
3. Save the file and restart pgAdmin for the changes to take effect.
Copy the following code into the `config_local.py` file and replace all placeholders and FQDN placeholders
:::note
If the `config_local.py` file does not exist, it needs to be created in the `/pgadmin4/` directory.
:::
:::note
You must restart pgAdmin every time you make changes to `config_local.py`.
:::
```py
AUTHENTICATION_SOURCES = ['oauth2', 'internal']
OAUTH2_AUTO_CREATE_USER = True
OAUTH2_CONFIG = [{
'OAUTH2_NAME' : 'authentik',
'OAUTH2_DISPLAY_NAME' : '<display-name>',
'OAUTH2_CLIENT_ID' : '<client-id>',
'OAUTH2_CLIENT_SECRET' : '<client-secret>',
'OAUTH2_TOKEN_URL' : 'https://authentik.company/application/o/token/',
'OAUTH2_AUTHORIZATION_URL' : 'https://authentik.company/application/o/authorize/',
'OAUTH2_API_BASE_URL' : 'https://authentik.company/',
'OAUTH2_USERINFO_ENDPOINT' : 'https://authentik.company/application/o/userinfo/',
'OAUTH2_SERVER_METADATA_URL' : 'https://authentik.company/application/o/<app-slug>/.well-known/openid-configuration',
'OAUTH2_SCOPE' : 'openid email profile',
'OAUTH2_ICON' : '<fontawesome-icon>',
'OAUTH2_BUTTON_COLOR' : '<button-color>'
}]
### Using Environment Variables for Containerized Deployments
For deployments using Docker or Kubernetes, you can configure OAuth using the following environment variables:
1. Set these environment variables in your container:
```bash
PGADMIN_CONFIG_AUTHENTICATION_SOURCES="['oauth2', 'internal']"
PGADMIN_CONFIG_OAUTH2_AUTO_CREATE_USER=True
PGADMIN_CONFIG_OAUTH2_CONFIG="[{'OAUTH2_NAME':'authentik','OAUTH2_DISPLAY_NAME':'Login with authentik','OAUTH2_CLIENT_ID':'<Client ID from authentik>','OAUTH2_CLIENT_SECRET':'<Client secret from authentik>','OAUTH2_TOKEN_URL':'https://authentik.company/application/o/token/','OAUTH2_AUTHORIZATION_URL':'https://authentik.company/application/o/authorize/','OAUTH2_API_BASE_URL':'https://authentik.company/','OAUTH2_USERINFO_ENDPOINT':'https://authentik.company/application/o/userinfo/','OAUTH2_SERVER_METADATA_URL':'https://authentik.company/application/o/<App Slug>/.well-known/openid-configuration','OAUTH2_SCOPE':'openid email profile','OAUTH2_ICON':'<Fontawesome icon key (e.g., fa-key)>','OAUTH2_BUTTON_COLOR':'<Hexadecimal color code for the login button>'}]"
```
In the code above the following placeholders have been used:
### General Notes
- `<display-name>`: The name that is displayed on the Login Button
- `<client-id>`: The Client ID from step 1
- `<client-secret>`: The Client Secret from step 1
- `<app-slug>`: The App Slug from step 2, it should be `pgadmin` if you did not change it
- `<fontawesome-icon>`: An icon name from [fontawesome](https://fontawesome.com). Only brand icons seem to be supported. This icon is displayed in front of the `<display-name>`. E.g.: _fa-github_.
- `<button-color>`: Sets the color of the Login Button. Should be in Hex format, E.g.: _#fd4b2d_
- To **only allow OAuth2 login**, set:
:::note
To only allow authentication via authentik set `AUTHENTICATION_SOURCES` to _['oauth2']_. This should **only** be done once at least one user registered via authentik has been made an admin in pgAdmin.
:::
```python
AUTHENTICATION_SOURCES = ['oauth2']
```
:::note
To disable user creation on pgAdmin, set `OAUTH2_AUTO_CREATE_USER` to _False_
:::
Ensure that you promote at least one user to an admin before disabling the internal authentication.
Finally, restart pgAdmin to apply the changes.
- To **disable automatic user creation**, set:
```python
OAUTH2_AUTO_CREATE_USER = False
```
Setting this value to `False` disables automatic user creation. This ensures that only the first signed-in user is registered.
:::note
pgAdmin needs to be restarted **every** time changes to `config_local.py` are made
:::
## Configuration verification
To confirm that authentik is properly configured with pgAdmin, log out and log back in via authentik. A new button should have appeared on the login page.

View File

@ -10,6 +10,7 @@ sidebar_label: Semaphore
## What is Semaphore UI
> Semaphore UI is a modern web interface for managing popular DevOps tools.
>
> -- https://semaphoreui.com/
>
> This guide explains how to configure Semaphore UI to use authentik as the OAuth provider for logging in to the Web GUI.
@ -23,49 +24,63 @@ The following placeholders are used in this guide:
## authentik configuration
[Create](https://docs.goauthentik.io/docs/add-secure-apps/applications/manage_apps#add-new-applications) an OAuth2/OpenID provider and an application in authentik. Use the following parameters for the OAuth2/OpenID provider:
Start the wizard for adding a new application.
**Provider:**
- Name: `SP-semaphore`
- Client type: `Confidential`
- Redirect URIs/Origins (RegEx): `https://semaphore.company/api/auth/oidc/authentik/redirect/`
- Signing Key: `authentik Self-signed Certificate`
Take note of the Client ID and Client Secret, you'll need to give them to Semaphore UI in Step 3.
Leave the rest as default values. The durations can be changed as needed.
**Application:**
**1. Application:**
- Name: `Semaphore UI`
- Slug: `semaphore`
- Launch URL: `https://semaphore.company/`
**2. Choose a Provider**
Select `OAuth2/OpenID Provider`
**3. Configure Provider**
Select implicit or explicit authorization flow as desired.
Take note of the Client ID and Client Secret, you'll need to give them to Semaphore UI later.
- Redirect URIs/Origins (RegEx): `https://semaphore.company/api/auth/oidc/authentik/redirect/`
- Signing Key: `authentik Self-signed Certificate`
Leave the rest as default values.
## Semaphore UI configuration
Log in to your Semaphore UI host via SSH. Edit the `config.json` file (should be located under `/etc/semaphore`) file with the text editor of your choice.
Log in to your Semaphore UI host via SSH. Edit the `/etc/semaphore/config.json` file with the text editor of your choice.
Before the last curly brace, add the following content:
Add the `oidc_providers` configuration:
```
"oidc_providers": {
"authentik": {
"display_name": "SSO-Login",
"provider_url": "https://authentik.company/application/o/semaphore/",
"client_id": "<client-id>",
"client_secret": "<client-secret>",
"redirect_url": "https://semaphore.company/api/auth/oidc/authentik/redirect/",
"username_claim": "username",
"name_claim": "name",
"email_claim": "email",
"scopes": ["openid", "profile", "email"]
}
{
"oidc_providers": {
"authentik": {
"display_name": "Sign in with Authentik",
"provider_url": "https://authentik.company/application/o/<slug>/",
"client_id": "<client-id>",
"client_secret": "<client-secret>",
"redirect_url": "https://semaphore.company/api/auth/oidc/authentik/redirect/",
"username_claim": "username",
"name_claim": "name",
"email_claim": "email",
"scopes": ["openid", "profile", "email"]
},
...
}
```
:::info
It is mandatory to include 'authentik' in lowercase letters. There should also be another curly brace above these lines. Make sure to add a `,` after it to maintain proper formatting.
The name of the oidc_provider (e.g. `authentik`) needs to match the name on the redirect URL.
:::
:::info
If a `Not Found` error is displayed after the login, you might need to set the web_root to `/` (see https://github.com/semaphoreui/semaphore/issues/2681):
```
SEMAPHORE_WEB_ROOT: /
```
:::
More information on this can be found in the Semaphore documentation https://docs.semaphoreui.com/administration-guide/openid/authentik/.

View File

@ -113,42 +113,9 @@ You must sync your LDAP database with Snipe-IT. Go to People on the sidebar menu
- Select your Location
- Click Synchronize
:::note
Snipe-IT will only import users with both a first and last name set. If you do not have first and last names stored in your users attributes, you can create a property mapping to set first and last name.
Snipe-IT will only import users with both a first and last name set. You need to create user attributes with first and last names.
:::
## authentik Property Mapping
To create a policy mapping, go to _Customization/Property Mappings_, click `Create` then `LDAP Property Mapping`. Name is 'sn' and set Object field to sn:
```ini
def getLastName():
if len(request.user.name) >= 1:
return request.user.name.split(" ")[1]
elif len(request.user.name) == 1:
return request.user.name.split(" ")[1]
else:
return ""
return {
"sn": getLastName(),
}
```
Create a second policy mapping, name it 'givenname' and set Object field to 'givenname'
```
def getFirstName():
if len(request.user.name) >= 1:
return request.user.name.split(" ")[0]
else:
return f"N/A"
return {
"givenname": getFirstName(),
}
```
## authentik SAML Config
### Step 1

View File

@ -0,0 +1,64 @@
---
title: Integrate with Terrakube
sidebar_label: Terrakube
---
# Terrakube
<span class="badge badge--secondary">Support level: Community</span>
## What is Terrakube
> Terrakube is an open-source collaboration platform designed for managing remote Infrastructure-as-Code (IaC) operations with Terraform. It serves as a alternative to proprietary tools like Terraform Enterprise.
>
> -- https://terrakube.io/
## Preparation
The following placeholders are used in this guide:
- `terrakube-dex.company` is the FQDN of the [Dex](https://dexidp.io/) container of the Terrakube installation.
- `authentik.company` is the FQDN of the authentik installation.
## authentik configuration
1. From the Admin interface, navigate to **Applications** -> **Applications**.
2. Use the wizard to create a new application and provider. During this process:
- Note the **Client ID**, **Client Secret**, and **slug** values because they will be required later.
- Set a `Strict` redirect URI to ` https://terrakube-dex.company/dex/callback`.
- Select any available signing key.
## Terrakube configuration
This guide assumes that you have environment variables `$TERRAKUBE_OIDC_CLIENT_ID` and `$TERRAKUBE_OIDC_CLIENT_SECRET` set up. You can hard-code values if your setup doesnt support environment variables, but be aware that doing so is not recommended for security reasons.
1. **Locate the Dex Configuration File**
Find the Dex configuration file, typically named `config.yaml` or `config.docker.yaml`. Its usually located in the `/etc/dex` directory or the corresponding directory for a containerized setup.
2. **Update the Dex Configuration**
To define the Terrakube OIDC connector, open the configuration file and add the following block:
```yaml
connectors:
- type: oidc
id: TerrakubeClient
name: TerrakubeClient
config:
issuer: "https://authentik.company/application/o/<Your application slug>/"
clientID: $TERRAKUBE_OIDC_CLIENT_ID
clientSecret: $TERRAKUBE_OIDC_CLIENT_SECRET
redirectURI: "https://terrakube-dex.company/dex/callback"
insecureEnableGroups: true
```
3. **Set Environment Variables**
Add the following variables to your `.env` file, replacing them with the appropriate values for your Client ID and Client Secret:
```env
TERRAKUBE_OIDC_CLIENT_ID=*your Client ID*
TERRAKUBE_OIDC_CLIENT_SECRET=*your Client Secret*
```
## Configuration verification
To ensure that authentik is correctly configured with Terrakube, log out and log back in through authentik. Depending on the number of connectors you have set up, you should either be redirected to authentik or see a new button appear on the Dex login page.

View File

@ -35,7 +35,7 @@
"@docusaurus/tsconfig": "^3.7.0",
"@docusaurus/types": "^3.3.2",
"@types/react": "^18.3.13",
"aws-cdk": "^2.175.1",
"aws-cdk": "^2.176.0",
"cross-env": "^7.0.3",
"prettier": "3.4.2",
"typescript": "~5.7.3",
@ -5715,9 +5715,9 @@
}
},
"node_modules/aws-cdk": {
"version": "2.175.1",
"resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.175.1.tgz",
"integrity": "sha512-duvy0FtGAAYqJi/x0MjBfCp60ZlDYl0X5/GrADwMz4AfHQ8aTXCyaVsdJuCxz0ZMHSNaFRuCNkAlc2Xu43zQmQ==",
"version": "2.176.0",
"resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.176.0.tgz",
"integrity": "sha512-yRjIXzK2ddznwuSjasWAViYBtBSQbEu6GHlylaC3GHsIUPhrK3KguqIuhdlxjMeiQ1Fvok8REDLCReZJdrSLLg==",
"dev": true,
"bin": {
"cdk": "bin/cdk"

View File

@ -56,7 +56,7 @@
"@docusaurus/tsconfig": "^3.7.0",
"@docusaurus/types": "^3.3.2",
"@types/react": "^18.3.13",
"aws-cdk": "^2.175.1",
"aws-cdk": "^2.176.0",
"cross-env": "^7.0.3",
"prettier": "3.4.2",
"typescript": "~5.7.3",

View File

@ -96,6 +96,7 @@ module.exports = {
"services/skyhigh/index",
"services/snipe-it/index",
"services/sssd/index",
"services/terrakube/index",
"services/truecommand/index",
"services/veeam-enterprise-manager/index",
"services/zammad/index",
@ -119,6 +120,7 @@ module.exports = {
type: "category",
label: "Miscellaneous",
items: [
"services/actual-budget/index",
"services/engomo/index",
"services/frappe/index",
"services/freshrss/index",