Merge branch 'master' into publish-api-to-npm

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

# Conflicts:
#	web/package-lock.json
#	web/src/pages/sources/oauth/OAuthSourceForm.ts
This commit is contained in:
Jens Langhammer 2021-08-23 09:32:04 +02:00
commit b74681f22c
74 changed files with 4022 additions and 2665 deletions

View File

@ -1,5 +1,5 @@
[bumpversion]
current_version = 2021.7.3
current_version = 2021.8.1-rc1
tag = True
commit = True
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-?(?P<release>.*)

View File

@ -33,14 +33,14 @@ jobs:
with:
push: ${{ github.event_name == 'release' }}
tags: |
beryju/authentik:2021.7.3,
beryju/authentik:2021.8.1-rc1,
beryju/authentik:latest,
ghcr.io/goauthentik/server:2021.7.3,
ghcr.io/goauthentik/server:2021.8.1-rc1,
ghcr.io/goauthentik/server:latest
platforms: linux/amd64,linux/arm64
context: .
- name: Building Docker Image (stable)
if: ${{ github.event_name == 'release' && !contains('2021.7.3', 'rc') }}
if: ${{ github.event_name == 'release' && !contains('2021.8.1-rc1', 'rc') }}
run: |
docker pull beryju/authentik:latest
docker tag beryju/authentik:latest beryju/authentik:stable
@ -75,14 +75,14 @@ jobs:
with:
push: ${{ github.event_name == 'release' }}
tags: |
beryju/authentik-proxy:2021.7.3,
beryju/authentik-proxy:2021.8.1-rc1,
beryju/authentik-proxy:latest,
ghcr.io/goauthentik/proxy:2021.7.3,
ghcr.io/goauthentik/proxy:2021.8.1-rc1,
ghcr.io/goauthentik/proxy:latest
file: proxy.Dockerfile
platforms: linux/amd64,linux/arm64
- name: Building Docker Image (stable)
if: ${{ github.event_name == 'release' && !contains('2021.7.3', 'rc') }}
if: ${{ github.event_name == 'release' && !contains('2021.8.1-rc1', 'rc') }}
run: |
docker pull beryju/authentik-proxy:latest
docker tag beryju/authentik-proxy:latest beryju/authentik-proxy:stable
@ -117,14 +117,14 @@ jobs:
with:
push: ${{ github.event_name == 'release' }}
tags: |
beryju/authentik-ldap:2021.7.3,
beryju/authentik-ldap:2021.8.1-rc1,
beryju/authentik-ldap:latest,
ghcr.io/goauthentik/ldap:2021.7.3,
ghcr.io/goauthentik/ldap:2021.8.1-rc1,
ghcr.io/goauthentik/ldap:latest
file: ldap.Dockerfile
platforms: linux/amd64,linux/arm64
- name: Building Docker Image (stable)
if: ${{ github.event_name == 'release' && !contains('2021.7.3', 'rc') }}
if: ${{ github.event_name == 'release' && !contains('2021.8.1-rc1', 'rc') }}
run: |
docker pull beryju/authentik-ldap:latest
docker tag beryju/authentik-ldap:latest beryju/authentik-ldap:stable
@ -175,7 +175,7 @@ jobs:
SENTRY_PROJECT: authentik
SENTRY_URL: https://sentry.beryju.org
with:
version: authentik@2021.7.3
version: authentik@2021.8.1-rc1
environment: beryjuorg-prod
sourcemaps: './web/dist'
url_prefix: '~/static/dist'

View File

@ -27,7 +27,7 @@ jobs:
docker-compose run -u root server test
- name: Extract version number
id: get_version
uses: actions/github-script@v4.0.2
uses: actions/github-script@v4.1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |

View File

@ -12,7 +12,7 @@ jobs:
# Setup .npmrc file to publish to npm
- uses: actions/setup-node@v2
with:
node-version: '12.x'
node-version: '16.x'
registry-url: 'https://registry.npmjs.org'
- run: make gen-web
- run: |

View File

@ -54,7 +54,7 @@ ENV NODE_ENV=production
RUN cd /static && npm i && npm run build
# Stage 5: Build go proxy
FROM golang:1.16.7 AS builder
FROM golang:1.17.0 AS builder
WORKDIR /work

118
Pipfile.lock generated
View File

@ -122,19 +122,19 @@
},
"boto3": {
"hashes": [
"sha256:00748c760dc30be61c6db4b092718f6a9f8d27c767da0e232695a65adb75cde8",
"sha256:59b6e8e79b2114e21388288a06a004f2a9378b1e0fc58466a35da8fb74fe2dd8"
"sha256:39ed0f5004b671e4a4241ae23023ad63674cd25f766bfe1617cfc809728bc3e0",
"sha256:3eedef0719639892dc263bed7adfc00821544388e3d86a6fa31d82f936a6b613"
],
"index": "pypi",
"version": "==1.18.21"
"version": "==1.18.26"
},
"botocore": {
"hashes": [
"sha256:12cfe74b0a5c44afb34bdd86c1f8ad74bc2ad9ec168eaed9040ef70cb3db944f",
"sha256:fa5ac13829d24fcdd385e82c3b6d78e22d93f427cca8dac38158cae84a8cc2f5"
"sha256:37f77bf5f72c86d9b5f38e107c3822da66dbf0ef123768a6e80a58590c2796bf",
"sha256:911246faac450e13a3ef0e81993dd9bd9c282a7c0f4546bfe8cccf9649364cef"
],
"markers": "python_version >= '3.6'",
"version": "==1.21.21"
"version": "==1.21.26"
},
"cachetools": {
"hashes": [
@ -487,11 +487,11 @@
},
"google-auth": {
"hashes": [
"sha256:bd6aa5916970a823e76ffb3d5c3ad3f0bedafca0a7fa53bc15149ab21cb71e05",
"sha256:f1094088bae046fb06f3d1a3d7df14717e8d959e9105b79c57725bd4e17597a2"
"sha256:c012c8be7c442c8309ca8fa0876fef33f5fd977c467be1e1c1c2f721e8ebd73c",
"sha256:ea1af050b3e06eb73e4470f704d23007307bc0e87c13e015f6b90460f1407bd3"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
"version": "==1.34.0"
"markers": "python_version >= '3.6'",
"version": "==2.0.1"
},
"gunicorn": {
"hashes": [
@ -630,11 +630,11 @@
},
"kubernetes": {
"hashes": [
"sha256:225a95a0aadbd5b645ab389d941a7980db8cdad2a776fde64d1b43fc3299bde9",
"sha256:c69b318696ba797dcf63eb928a8d4370c52319f4140023c502d7dfdf2080eb79"
"sha256:0c72d00e7883375bd39ae99758425f5e6cb86388417cf7cc84305c211b2192cf",
"sha256:ff31ec17437293e7d4e1459f1228c42d27c7724dfb56b4868aba7a901a5b72c9"
],
"index": "pypi",
"version": "==17.17.0"
"version": "==18.20.0"
},
"ldap3": {
"hashes": [
@ -810,11 +810,11 @@
},
"prompt-toolkit": {
"hashes": [
"sha256:08360ee3a3148bdb5163621709ee322ec34fc4375099afa4bbf751e9b7b7fa4f",
"sha256:7089d8d2938043508aa9420ec18ce0922885304cddae87fb96eebca942299f88"
"sha256:6076e46efae19b1e0ca1ec003ed37a933dc94b4d20f486235d436e64771dcd5c",
"sha256:eb71d5a6b72ce6db177af4a7d4d7085b99756bf656d98ffcc4fecd36850eea6c"
],
"markers": "python_full_version >= '3.6.1'",
"version": "==3.0.19"
"markers": "python_full_version >= '3.6.2'",
"version": "==3.0.20"
},
"psycopg2-binary": {
"hashes": [
@ -1068,7 +1068,7 @@
"sha256:78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2",
"sha256:9d689e6ca1b3038bc82bf8d23e944b6b6037bc02301a574935b2dd946e0353b9"
],
"markers": "python_version >= '3.6'",
"markers": "python_version >= '3.5' and python_version < '4'",
"version": "==4.7.2"
},
"s3transfer": {
@ -1747,41 +1747,49 @@
},
"regex": {
"hashes": [
"sha256:026beb631097a4a3def7299aa5825e05e057de3c6d72b139c37813bfa351274b",
"sha256:14caacd1853e40103f59571f169704367e79fb78fac3d6d09ac84d9197cadd16",
"sha256:16d9eaa8c7e91537516c20da37db975f09ac2e7772a0694b245076c6d68f85da",
"sha256:18fdc51458abc0a974822333bd3a932d4e06ba2a3243e9a1da305668bd62ec6d",
"sha256:28e8af338240b6f39713a34e337c3813047896ace09d51593d6907c66c0708ba",
"sha256:3835de96524a7b6869a6c710b26c90e94558c31006e96ca3cf6af6751b27dca1",
"sha256:3905c86cc4ab6d71635d6419a6f8d972cab7c634539bba6053c47354fd04452c",
"sha256:3c09d88a07483231119f5017904db8f60ad67906efac3f1baa31b9b7f7cca281",
"sha256:4551728b767f35f86b8e5ec19a363df87450c7376d7419c3cac5b9ceb4bce576",
"sha256:459bbe342c5b2dec5c5223e7c363f291558bc27982ef39ffd6569e8c082bdc83",
"sha256:4f421e3cdd3a273bace013751c345f4ebeef08f05e8c10757533ada360b51a39",
"sha256:577737ec3d4c195c4aef01b757905779a9e9aee608fa1cf0aec16b5576c893d3",
"sha256:57fece29f7cc55d882fe282d9de52f2f522bb85290555b49394102f3621751ee",
"sha256:7976d410e42be9ae7458c1816a416218364e06e162b82e42f7060737e711d9ce",
"sha256:85f568892422a0e96235eb8ea6c5a41c8ccbf55576a2260c0160800dbd7c4f20",
"sha256:8764a78c5464ac6bde91a8c87dd718c27c1cabb7ed2b4beaf36d3e8e390567f9",
"sha256:8935937dad2c9b369c3d932b0edbc52a62647c2afb2fafc0c280f14a8bf56a6a",
"sha256:8fe58d9f6e3d1abf690174fd75800fda9bdc23d2a287e77758dc0e8567e38ce6",
"sha256:937b20955806381e08e54bd9d71f83276d1f883264808521b70b33d98e4dec5d",
"sha256:9569da9e78f0947b249370cb8fadf1015a193c359e7e442ac9ecc585d937f08d",
"sha256:a3b73390511edd2db2d34ff09aa0b2c08be974c71b4c0505b4a048d5dc128c2b",
"sha256:a4eddbe2a715b2dd3849afbdeacf1cc283160b24e09baf64fa5675f51940419d",
"sha256:a5c6dbe09aff091adfa8c7cfc1a0e83fdb8021ddb2c183512775a14f1435fe16",
"sha256:b63e3571b24a7959017573b6455e05b675050bbbea69408f35f3cb984ec54363",
"sha256:bb350eb1060591d8e89d6bac4713d41006cd4d479f5e11db334a48ff8999512f",
"sha256:bf6d987edd4a44dd2fa2723fca2790f9442ae4de2c8438e53fcb1befdf5d823a",
"sha256:bfa6a679410b394600eafd16336b2ce8de43e9b13f7fb9247d84ef5ad2b45e91",
"sha256:c856ec9b42e5af4fe2d8e75970fcc3a2c15925cbcc6e7a9bcb44583b10b95e80",
"sha256:cea56288eeda8b7511d507bbe7790d89ae7049daa5f51ae31a35ae3c05408531",
"sha256:ea212df6e5d3f60341aef46401d32fcfded85593af1d82b8b4a7a68cd67fdd6b",
"sha256:f35567470ee6dbfb946f069ed5f5615b40edcbb5f1e6e1d3d2b114468d505fc6",
"sha256:fbc20975eee093efa2071de80df7f972b7b35e560b213aafabcec7c0bd00bd8c",
"sha256:ff4a8ad9638b7ca52313d8732f37ecd5fd3c8e3aff10a8ccb93176fd5b3812f6"
"sha256:03840a07a402576b8e3a6261f17eb88abd653ad4e18ec46ef10c9a63f8c99ebd",
"sha256:06ba444bbf7ede3890a912bd4904bb65bf0da8f0d8808b90545481362c978642",
"sha256:1f9974826aeeda32a76648fc677e3125ade379869a84aa964b683984a2dea9f1",
"sha256:330836ad89ff0be756b58758878409f591d4737b6a8cef26a162e2a4961c3321",
"sha256:38600fd58c2996829480de7d034fb2d3a0307110e44dae80b6b4f9b3d2eea529",
"sha256:3a195e26df1fbb40ebee75865f9b64ba692a5824ecb91c078cc665b01f7a9a36",
"sha256:41acdd6d64cd56f857e271009966c2ffcbd07ec9149ca91f71088574eaa4278a",
"sha256:45f97ade892ace20252e5ccecdd7515c7df5feeb42c3d2a8b8c55920c3551c30",
"sha256:4b0c211c55d4aac4309c3209833c803fada3fc21cdf7b74abedda42a0c9dc3ce",
"sha256:5d5209c3ba25864b1a57461526ebde31483db295fc6195fdfc4f8355e10f7376",
"sha256:615fb5a524cffc91ab4490b69e10ae76c1ccbfa3383ea2fad72e54a85c7d47dd",
"sha256:61e734c2bcb3742c3f454dfa930ea60ea08f56fd1a0eb52d8cb189a2f6be9586",
"sha256:640ccca4d0a6fcc6590f005ecd7b16c3d8f5d52174e4854f96b16f34c39d6cb7",
"sha256:6dbd51c3db300ce9d3171f4106da18fe49e7045232630fe3d4c6e37cb2b39ab9",
"sha256:71a904da8c9c02aee581f4452a5a988c3003207cb8033db426f29e5b2c0b7aea",
"sha256:8021dee64899f993f4b5cca323aae65aabc01a546ed44356a0965e29d7893c94",
"sha256:8b8d551f1bd60b3e1c59ff55b9e8d74607a5308f66e2916948cafd13480b44a3",
"sha256:93f9f720081d97acee38a411e861d4ce84cbc8ea5319bc1f8e38c972c47af49f",
"sha256:96f0c79a70642dfdf7e6a018ebcbea7ea5205e27d8e019cad442d2acfc9af267",
"sha256:9966337353e436e6ba652814b0a957a517feb492a98b8f9d3b6ba76d22301dcc",
"sha256:a34ba9e39f8269fd66ab4f7a802794ffea6d6ac500568ec05b327a862c21ce23",
"sha256:a49f85f0a099a5755d0a2cc6fc337e3cb945ad6390ec892332c691ab0a045882",
"sha256:a795829dc522227265d72b25d6ee6f6d41eb2105c15912c230097c8f5bfdbcdc",
"sha256:a89ca4105f8099de349d139d1090bad387fe2b208b717b288699ca26f179acbe",
"sha256:ac95101736239260189f426b1e361dc1b704513963357dc474beb0f39f5b7759",
"sha256:ae87ab669431f611c56e581679db33b9a467f87d7bf197ac384e71e4956b4456",
"sha256:b091dcfee169ad8de21b61eb2c3a75f9f0f859f851f64fdaf9320759a3244239",
"sha256:b511c6009d50d5c0dd0bab85ed25bc8ad6b6f5611de3a63a59786207e82824bb",
"sha256:b79dc2b2e313565416c1e62807c7c25c67a6ff0a0f8d83a318df464555b65948",
"sha256:bca14dfcfd9aae06d7d8d7e105539bd77d39d06caaae57a1ce945670bae744e0",
"sha256:c835c30f3af5c63a80917b72115e1defb83de99c73bc727bddd979a3b449e183",
"sha256:ccd721f1d4fc42b541b633d6e339018a08dd0290dc67269df79552843a06ca92",
"sha256:d6c2b1d78ceceb6741d703508cd0e9197b34f6bf6864dab30f940f8886e04ade",
"sha256:d6ec4ae13760ceda023b2e5ef1f9bc0b21e4b0830458db143794a117fdbdc044",
"sha256:d8b623fc429a38a881ab2d9a56ef30e8ea20c72a891c193f5ebbddc016e083ee",
"sha256:ea9753d64cba6f226947c318a923dadaf1e21cd8db02f71652405263daa1f033",
"sha256:ebbceefbffae118ab954d3cd6bf718f5790db66152f95202ebc231d58ad4e2c2",
"sha256:ecb6e7c45f9cd199c10ec35262b53b2247fb9a408803ed00ee5bb2b54aa626f5",
"sha256:ef9326c64349e2d718373415814e754183057ebc092261387a2c2f732d9172b2",
"sha256:f93a9d8804f4cec9da6c26c8cfae2c777028b4fdd9f49de0302e26e00bb86504",
"sha256:faf08b0341828f6a29b8f7dd94d5cf8cc7c39bfc3e67b78514c54b494b66915a"
],
"version": "==2021.8.3"
"version": "==2021.8.21"
},
"requests": {
"hashes": [
@ -1825,11 +1833,11 @@
},
"stevedore": {
"hashes": [
"sha256:3a5bbd0652bf552748871eaa73a4a8dc2899786bc497a2aa1fcb4dcdb0debeee",
"sha256:50d7b78fbaf0d04cd62411188fa7eedcb03eb7f4c4b37005615ceebe582aa82a"
"sha256:59b58edb7f57b11897f150475e7bc0c39c5381f0b8e3fa9f5c20ce6c89ec4aa1",
"sha256:920ce6259f0b2498aaa4545989536a27e4e4607b8318802d7ddc3a533d3d069e"
],
"markers": "python_version >= '3.6'",
"version": "==3.3.0"
"version": "==3.4.0"
},
"toml": {
"hashes": [

View File

@ -1,3 +1,3 @@
"""authentik"""
__version__ = "2021.7.3"
__version__ = "2021.8.1-rc1"
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"

View File

@ -5,7 +5,7 @@ from django.conf import settings
from django.db import models
from drf_spectacular.utils import extend_schema
from kubernetes.config.incluster_config import SERVICE_HOST_ENV_NAME
from rest_framework.fields import BooleanField, CharField, ChoiceField, ListField
from rest_framework.fields import BooleanField, CharField, ChoiceField, IntegerField, ListField
from rest_framework.permissions import AllowAny
from rest_framework.request import Request
from rest_framework.response import Response
@ -33,6 +33,11 @@ class ConfigSerializer(PassiveSerializer):
capabilities = ListField(child=ChoiceField(choices=Capabilities.choices))
cache_timeout = IntegerField(required=True)
cache_timeout_flows = IntegerField(required=True)
cache_timeout_policies = IntegerField(required=True)
cache_timeout_reputation = IntegerField(required=True)
class ConfigView(APIView):
"""Read-only view set that returns the current session's Configs"""
@ -65,6 +70,10 @@ class ConfigView(APIView):
"error_reporting_environment": CONFIG.y("error_reporting.environment"),
"error_reporting_send_pii": CONFIG.y("error_reporting.send_pii"),
"capabilities": self.get_capabilities(),
"cache_timeout": int(CONFIG.y("redis.cache_timeout")),
"cache_timeout_flows": int(CONFIG.y("redis.cache_timeout_flows")),
"cache_timeout_policies": int(CONFIG.y("redis.cache_timeout_policies")),
"cache_timeout_reputation": int(CONFIG.y("redis.cache_timeout_reputation")),
}
)
return Response(config.data)

View File

@ -58,7 +58,8 @@ from authentik.providers.saml.api import SAMLPropertyMappingViewSet, SAMLProvide
from authentik.sources.ldap.api import LDAPPropertyMappingViewSet, LDAPSourceViewSet
from authentik.sources.oauth.api.source import OAuthSourceViewSet
from authentik.sources.oauth.api.source_connection import UserOAuthSourceConnectionViewSet
from authentik.sources.plex.api import PlexSourceViewSet
from authentik.sources.plex.api.source import PlexSourceViewSet
from authentik.sources.plex.api.source_connection import PlexSourceConnectionViewSet
from authentik.sources.saml.api import SAMLSourceViewSet
from authentik.stages.authenticator_duo.api import (
AuthenticatorDuoStageViewSet,
@ -127,7 +128,8 @@ router.register("events/transports", NotificationTransportViewSet)
router.register("events/rules", NotificationRuleViewSet)
router.register("sources/all", SourceViewSet)
router.register("sources/oauth_user_connections", UserOAuthSourceConnectionViewSet)
router.register("sources/user_connections/oauth", UserOAuthSourceConnectionViewSet)
router.register("sources/user_connections/plex", PlexSourceConnectionViewSet)
router.register("sources/ldap", LDAPSourceViewSet)
router.register("sources/saml", SAMLSourceViewSet)
router.register("sources/oauth", OAuthSourceViewSet)

View File

@ -74,6 +74,8 @@ class SourceViewSet(
for subclass in all_subclasses(self.queryset.model):
subclass: Source
component = ""
if len(subclass.__subclasses__()) > 0:
continue
if subclass._meta.abstract:
component = subclass.__bases__[0]().component
else:

View File

@ -6,7 +6,7 @@ from django.db.models.query import QuerySet
from django.urls import reverse_lazy
from django.utils.http import urlencode
from django.utils.translation import gettext as _
from django_filters.filters import BooleanFilter, CharFilter
from django_filters.filters import BooleanFilter, CharFilter, ModelMultipleChoiceFilter
from django_filters.filterset import FilterSet
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, extend_schema, extend_schema_field
@ -149,6 +149,16 @@ class UsersFilter(FilterSet):
is_superuser = BooleanFilter(field_name="ak_groups", lookup_expr="is_superuser")
groups_by_name = ModelMultipleChoiceFilter(
field_name="ak_groups__name",
to_field_name="name",
queryset=Group.objects.all(),
)
groups_by_pk = ModelMultipleChoiceFilter(
field_name="ak_groups",
queryset=Group.objects.all(),
)
# pylint: disable=unused-argument
def filter_attributes(self, queryset, name, value):
"""Filter attributes by query args"""
@ -172,6 +182,8 @@ class UsersFilter(FilterSet):
"is_active",
"is_superuser",
"attributes",
"groups_by_name",
"groups_by_pk",
]

View File

@ -2,7 +2,7 @@
from typing import Optional
from aioredis.errors import ConnectionClosedError, ReplyError
from billiard.exceptions import WorkerLostError
from billiard.exceptions import SoftTimeLimitExceeded, WorkerLostError
from botocore.client import ClientError
from botocore.exceptions import BotoCoreError
from celery.exceptions import CeleryError
@ -45,6 +45,9 @@ class SentryIgnoredException(Exception):
def before_send(event: dict, hint: dict) -> Optional[dict]:
"""Check if error is database error, and ignore if so"""
# pylint: disable=no-name-in-module
from psycopg2.errors import Error
ignored_classes = (
# Inbuilt types
KeyboardInterrupt,
@ -52,6 +55,7 @@ def before_send(event: dict, hint: dict) -> Optional[dict]:
OSError,
PermissionError,
# Django Errors
Error,
ImproperlyConfigured,
OperationalError,
InternalError,
@ -73,6 +77,7 @@ def before_send(event: dict, hint: dict) -> Optional[dict]:
# celery errors
WorkerLostError,
CeleryError,
SoftTimeLimitExceeded,
# S3 errors
BotoCoreError,
ClientError,

View File

@ -1,6 +1,7 @@
"""OAuth Source Serializer"""
from django.urls.base import reverse_lazy
from drf_spectacular.utils import extend_schema, extend_schema_field
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, extend_schema, extend_schema_field
from rest_framework.decorators import action
from rest_framework.fields import BooleanField, CharField, SerializerMethodField
from rest_framework.request import Request
@ -12,7 +13,7 @@ from authentik.core.api.sources import SourceSerializer
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import PassiveSerializer
from authentik.sources.oauth.models import OAuthSource
from authentik.sources.oauth.types.manager import MANAGER
from authentik.sources.oauth.types.manager import MANAGER, SourceType
class SourceTypeSerializer(PassiveSerializer):
@ -100,11 +101,26 @@ class OAuthSourceViewSet(UsedByMixin, ModelViewSet):
]
ordering = ["name"]
@extend_schema(responses={200: SourceTypeSerializer(many=True)})
@extend_schema(
responses={200: SourceTypeSerializer(many=True)},
parameters=[
OpenApiParameter(
name="name",
location=OpenApiParameter.QUERY,
type=OpenApiTypes.STR,
)
],
)
@action(detail=False, pagination_class=None, filter_backends=[])
def source_types(self, request: Request) -> Response:
"""Get all creatable source types"""
"""Get all creatable source types. If ?name is set, only returns the type for <name>.
If <name> isn't found, returns the default type."""
data = []
if "name" in request.query_params:
source_type = MANAGER.find_type(request.query_params.get("name"))
if source_type.__class__ != SourceType:
data.append(SourceTypeSerializer(source_type).data)
else:
for source_type in MANAGER.get():
data.append(SourceTypeSerializer(source_type).data)
return Response(data)

View File

@ -0,0 +1,33 @@
# Generated by Django 3.2.5 on 2021-08-21 13:41
from django.apps.registry import Apps
from django.db import migrations
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
def update_provider_types(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
OAuthSource = apps.get_model("authentik_sources_oauth", "oauthsource")
db_alias = schema_editor.connection.alias
for source in OAuthSource.objects.using(db_alias).all():
changed = False
if source.provider_type == "azure-ad":
source.provider_type = "azuread"
changed = True
if source.provider_type == "openid-connect":
source.provider_type = "openidconnect"
changed = True
if changed:
source.save()
class Migration(migrations.Migration):
dependencies = [
("authentik_sources_oauth", "0004_auto_20210417_1900"),
]
operations = [
migrations.RunPython(update_provider_types),
]

View File

@ -0,0 +1,46 @@
"""azure ad Type tests"""
from django.test import TestCase
from authentik.sources.oauth.models import OAuthSource
from authentik.sources.oauth.types.azure_ad import AzureADOAuthCallback
# https://docs.microsoft.com/en-us/graph/api/user-get?view=graph-rest-1.0&tabs=http#response-2
AAD_USER = {
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"@odata.id": (
"https://graph.microsoft.com/v2/7ce9b89e-646a-41d2-9fa6-8371c6a8423d/"
"directoryObjects/018b0aff-8aff-473e-bf9c-b50e27f52208/Microsoft.DirectoryServices.User"
),
"businessPhones": [],
"displayName": "foo bar",
"givenName": "foo",
"jobTitle": None,
"mail": "foo@beryju.org",
"mobilePhone": None,
"officeLocation": None,
"preferredLanguage": None,
"surname": "bar",
"userPrincipalName": "foo@beryju.org",
"id": "018b0aff-8aff-473e-bf9c-b50e27f52208",
}
class TestTypeAzureAD(TestCase):
"""OAuth Source tests"""
def setUp(self):
self.source = OAuthSource.objects.create(
name="test",
slug="test",
provider_type="openidconnect",
authorization_url="",
profile_url="",
consumer_key="",
)
def test_enroll_context(self):
"""Test azure_ad Enrollment context"""
ak_context = AzureADOAuthCallback().get_user_enroll_context(AAD_USER)
self.assertEqual(ak_context["username"], AAD_USER["displayName"])
self.assertEqual(ak_context["email"], AAD_USER["mail"])
self.assertEqual(ak_context["name"], AAD_USER["displayName"])

View File

@ -25,7 +25,7 @@ class TestTypeDiscord(TestCase):
self.source = OAuthSource.objects.create(
name="test",
slug="test",
provider_type="openid-connect",
provider_type="openidconnect",
authorization_url="",
profile_url="",
consumer_key="",

View File

@ -55,7 +55,7 @@ class TestTypeGitHub(TestCase):
self.source = OAuthSource.objects.create(
name="test",
slug="test",
provider_type="openid-connect",
provider_type="openidconnect",
authorization_url="",
profile_url="",
consumer_key="",

View File

@ -96,7 +96,7 @@ class TestTypeGitHub(TestCase):
self.source = OAuthSource.objects.create(
name="test",
slug="test",
provider_type="openid-connect",
provider_type="openidconnect",
authorization_url="",
profile_url="",
consumer_key="",

View File

@ -13,7 +13,7 @@ class TestOAuthSource(TestCase):
self.source = OAuthSource.objects.create(
name="test",
slug="test",
provider_type="openid-connect",
provider_type="openidconnect",
authorization_url="",
profile_url="",
consumer_key="",
@ -37,7 +37,7 @@ class TestOAuthSource(TestCase):
data={
"name": "foo",
"slug": "bar",
"provider_type": "openid-connect",
"provider_type": "openidconnect",
"consumer_key": "foo",
"consumer_secret": "foo",
}

View File

@ -8,10 +8,20 @@ from structlog.stdlib import get_logger
from authentik.sources.oauth.clients.oauth2 import OAuth2Client
from authentik.sources.oauth.types.manager import MANAGER, SourceType
from authentik.sources.oauth.views.callback import OAuthCallback
from authentik.sources.oauth.views.redirect import OAuthRedirect
LOGGER = get_logger()
class AzureADOAuthRedirect(OAuthRedirect):
"""Azure AD OAuth2 Redirect"""
def get_additional_parameters(self, source): # pragma: no cover
return {
"scope": "openid https://graph.microsoft.com/User.Read",
}
class AzureADClient(OAuth2Client):
"""Azure AD Oauth client, azure ad doesn't like the ?access_token that is sent by default"""
@ -42,7 +52,7 @@ class AzureADOAuthCallback(OAuthCallback):
def get_user_id(self, info: dict[str, Any]) -> Optional[str]:
try:
return str(UUID(info.get("objectId")).int)
return str(UUID(info.get("id")).int)
except TypeError:
return None
@ -63,11 +73,12 @@ class AzureADType(SourceType):
"""Azure AD Type definition"""
callback_view = AzureADOAuthCallback
redirect_view = AzureADOAuthRedirect
name = "Azure AD"
slug = "azure-ad"
slug = "azuread"
urls_customizable = True
authorization_url = "https://login.microsoftonline.com/common/oauth2/authorize"
access_token_url = "https://login.microsoftonline.com/common/oauth2/token" # nosec
profile_url = "https://graph.windows.net/myorganization/me?api-version=1.6"
authorization_url = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize"
access_token_url = "https://login.microsoftonline.com/common/oauth2/v2.0/token" # nosec
profile_url = "https://graph.microsoft.com/v1.0/me"

View File

@ -40,6 +40,6 @@ class OpenIDConnectType(SourceType):
callback_view = OpenIDConnectOAuth2Callback
redirect_view = OpenIDConnectOAuthRedirect
name = "OpenID Connect"
slug = "openid-connect"
slug = "openidconnect"
urls_customizable = True

View File

View File

@ -0,0 +1,41 @@
"""Plex Source connection Serializer"""
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import mixins
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.viewsets import GenericViewSet
from authentik.api.authorization import OwnerFilter, OwnerPermissions
from authentik.core.api.sources import SourceSerializer
from authentik.core.api.used_by import UsedByMixin
from authentik.sources.plex.models import PlexSourceConnection
class PlexSourceConnectionSerializer(SourceSerializer):
"""Plex Source connection Serializer"""
class Meta:
model = PlexSourceConnection
fields = [
"pk",
"user",
"source",
"identifier",
"plex_token",
]
class PlexSourceConnectionViewSet(
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
UsedByMixin,
mixins.ListModelMixin,
GenericViewSet,
):
"""Plex Source connection Serializer"""
queryset = PlexSourceConnection.objects.all()
serializer_class = PlexSourceConnectionSerializer
filterset_fields = ["source__slug"]
permission_classes = [OwnerPermissions]
filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter]

View File

@ -1,4 +1,6 @@
"""Plex source"""
from typing import Optional
from django.contrib.postgres.fields import ArrayField
from django.db import models
from django.templatetags.static import static
@ -7,7 +9,7 @@ from rest_framework.fields import CharField
from rest_framework.serializers import BaseSerializer
from authentik.core.models import Source, UserSourceConnection
from authentik.core.types import UILoginButton
from authentik.core.types import UILoginButton, UserSettingSerializer
from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes
from authentik.providers.oauth2.generators import generate_client_id
@ -56,7 +58,7 @@ class PlexSource(Source):
@property
def serializer(self) -> BaseSerializer:
from authentik.sources.plex.api import PlexSourceSerializer
from authentik.sources.plex.api.source import PlexSourceSerializer
return PlexSourceSerializer
@ -75,6 +77,15 @@ class PlexSource(Source):
name=self.name,
)
@property
def ui_user_settings(self) -> Optional[UserSettingSerializer]:
return UserSettingSerializer(
data={
"title": f"Plex {self.name}",
"component": "ak-user-settings-source-plex",
}
)
class Meta:
verbose_name = _("Plex Source")

View File

@ -27,7 +27,7 @@ def create_default_password_change(apps: Apps, schema_editor: BaseDatabaseSchema
)
prompt_stage, _ = PromptStage.objects.using(db_alias).update_or_create(
name="Change your password",
name="default-password-change-prompt",
)
password_prompt, _ = Prompt.objects.using(db_alias).update_or_create(
field_key="password",

View File

@ -0,0 +1,27 @@
# Generated by Django 3.2.5 on 2021-08-21 13:12
from django.apps.registry import Apps
from django.db import migrations
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
def rename_default_prompt_stage(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
PromptStage = apps.get_model("authentik_stages_prompt", "PromptStage")
db_alias = schema_editor.connection.alias
stages = PromptStage.objects.using(db_alias).filter(name="Change your password")
if not stages.exists():
return
stage = stages.first()
stage.name = "default-password-change-prompt"
stage.save()
class Migration(migrations.Migration):
dependencies = [
("authentik_stages_password", "0005_auto_20210402_2221"),
]
operations = [
migrations.RunPython(rename_default_prompt_stage),
]

View File

@ -397,6 +397,7 @@ stages:
inputs:
script: bash <(curl -s https://codecov.io/bash)
- task: CmdLine@2
continueOnError: true
inputs:
script: |
npm install -g @zeus-ci/cli

View File

@ -21,7 +21,7 @@ services:
networks:
- internal
server:
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.7.3}
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.8.1-rc1}
restart: unless-stopped
command: server
environment:
@ -44,7 +44,7 @@ services:
- "0.0.0.0:9000:9000"
- "0.0.0.0:9443:9443"
worker:
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.7.3}
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2021.8.1-rc1}
restart: unless-stopped
command: worker
networks:

4
go.mod
View File

@ -7,11 +7,11 @@ require (
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/getsentry/sentry-go v0.11.0
github.com/go-ldap/ldap/v3 v3.4.0
github.com/go-ldap/ldap/v3 v3.4.1
github.com/go-openapi/analysis v0.20.1 // indirect
github.com/go-openapi/errors v0.20.0 // indirect
github.com/go-openapi/runtime v0.19.30
github.com/go-openapi/strfmt v0.20.1
github.com/go-openapi/strfmt v0.20.2
github.com/go-openapi/swag v0.19.15 // indirect
github.com/go-openapi/validate v0.20.2 // indirect
github.com/go-redis/redis/v7 v7.4.0 // indirect

8
go.sum
View File

@ -150,8 +150,8 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-ldap/ldap/v3 v3.4.0 h1:wCttA0dcqAOygfOabqYhQPXKGG9ws8az3FBM8+GAhDs=
github.com/go-ldap/ldap/v3 v3.4.0/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
github.com/go-ldap/ldap/v3 v3.4.1 h1:fU/0xli6HY02ocbMuozHAYsaHLcnkLjvho2r5a34BUU=
github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
@ -227,8 +227,8 @@ github.com/go-openapi/strfmt v0.19.4/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk
github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk=
github.com/go-openapi/strfmt v0.19.11/go.mod h1:UukAYgTaQfqJuAFlNxxMWNvMYiwiXtLsF2VwmoFtbtc=
github.com/go-openapi/strfmt v0.20.0/go.mod h1:UukAYgTaQfqJuAFlNxxMWNvMYiwiXtLsF2VwmoFtbtc=
github.com/go-openapi/strfmt v0.20.1 h1:1VgxvehFne1mbChGeCmZ5pc0LxUf6yaACVSIYAR91Xc=
github.com/go-openapi/strfmt v0.20.1/go.mod h1:43urheQI9dNtE5lTZQfuFJvjYJKPrxicATpEfZwHUNk=
github.com/go-openapi/strfmt v0.20.2 h1:6XZL+fF4VZYFxKQGLAUB358hOrRh/wS51uWEtlONADE=
github.com/go-openapi/strfmt v0.20.2/go.mod h1:43urheQI9dNtE5lTZQfuFJvjYJKPrxicATpEfZwHUNk=
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=

View File

@ -17,4 +17,4 @@ func OutpostUserAgent() string {
return fmt.Sprintf("authentik-outpost@%s (%s)", VERSION, BUILD())
}
const VERSION = "2021.7.3"
const VERSION = "2021.8.1-rc1"

View File

@ -26,10 +26,12 @@ const ConfigErrorReportingEnvironment = "error_reporting_environment"
type APIController struct {
Client *api.APIClient
Outpost api.Outpost
token string
GlobalConfig api.Config
Server Outpost
token string
logger *log.Entry
reloadOffset time.Duration
@ -59,16 +61,26 @@ func NewAPIController(akURL url.URL, token string) *APIController {
outposts, _, err := apiClient.OutpostsApi.OutpostsInstancesList(context.Background()).Execute()
if err != nil {
log.WithError(err).Error("Failed to fetch configuration")
log.WithError(err).Error("Failed to fetch outpost configuration")
return nil
}
outpost := outposts.Results[0]
doGlobalSetup(outpost.Config)
log.WithField("name", outpost.Name).Debug("Fetched outpost configuration")
akConfig, _, err := apiClient.RootApi.RootConfigRetrieve(context.Background()).Execute()
if err != nil {
log.WithError(err).Error("Failed to fetch global configuration")
return nil
}
log.Debug("Fetched global configuration")
ac := &APIController{
Client: apiClient,
token: token,
GlobalConfig: akConfig,
token: token,
logger: log,
reloadOffset: time.Duration(rand.Intn(10)) * time.Second,
@ -112,5 +124,9 @@ func (a *APIController) StartBackgorundTasks() error {
a.logger.Debug("Starting Interval updater...")
a.startIntervalUpdater()
}()
go func() {
a.logger.Debug("Starting periodical timer...")
a.startPeriodicalTasks()
}()
return nil
}

View File

@ -39,7 +39,7 @@ func (ac *APIController) initWS(akURL url.URL, outpostUUID strfmt.UUID) {
}
ws.Dial(fmt.Sprintf(pathTemplate, scheme, akURL.Host, outpostUUID.String()), header)
ac.logger.WithField("logger", "authentik.outpost.ak-ws").WithField("outpost", outpostUUID.String()).Debug("connecting to authentik")
ac.logger.WithField("logger", "authentik.outpost.ak-ws").WithField("outpost", outpostUUID.String()).Debug("Connecting to authentik")
ac.wsConn = ws
// Send hello message with our version

View File

@ -3,4 +3,5 @@ package ak
type Outpost interface {
Start() error
Refresh() error
TimerFlowCacheExpiry()
}

View File

@ -0,0 +1,15 @@
package ak
import (
"time"
)
func (a *APIController) startPeriodicalTasks() {
go a.Server.TimerFlowCacheExpiry()
go func() {
for range time.Tick(time.Duration(a.GlobalConfig.CacheTimeoutFlows) * time.Second) {
a.logger.WithField("timer", "cache-timeout").Debug("Running periodical tasks")
a.Server.TimerFlowCacheExpiry()
}
}()
}

View File

@ -118,6 +118,15 @@ func (fe *FlowExecutor) getAnswer(stage StageComponent) string {
return ""
}
// WarmUp Ensure authentik's flow cache is warmed up
func (fe *FlowExecutor) WarmUp() error {
defer fe.sp.Finish()
gcsp := sentry.StartSpan(fe.Context, "authentik.outposts.flow_executor.get_challenge")
req := fe.api.FlowsApi.FlowsExecutorGet(gcsp.Context(), fe.flowSlug).Query(fe.Params.Encode())
_, _, err := req.Execute()
return err
}
func (fe *FlowExecutor) Execute() (bool, error) {
return fe.solveFlowChallenge(1)
}

View File

@ -15,6 +15,12 @@ import (
log "github.com/sirupsen/logrus"
)
const (
UsersOU = "users"
GroupsOU = "groups"
VirtualGroupsOU = "virtual-groups"
)
func (ls *LDAPServer) Refresh() error {
outposts, _, err := ls.ac.Client.OutpostsApi.OutpostsLdapList(context.Background()).Execute()
if err != nil {
@ -25,11 +31,13 @@ func (ls *LDAPServer) Refresh() error {
}
providers := make([]*ProviderInstance, len(outposts.Results))
for idx, provider := range outposts.Results {
userDN := strings.ToLower(fmt.Sprintf("ou=users,%s", *provider.BaseDn))
groupDN := strings.ToLower(fmt.Sprintf("ou=groups,%s", *provider.BaseDn))
userDN := strings.ToLower(fmt.Sprintf("ou=%s,%s", UsersOU, *provider.BaseDn))
groupDN := strings.ToLower(fmt.Sprintf("ou=%s,%s", GroupsOU, *provider.BaseDn))
virtualGroupDN := strings.ToLower(fmt.Sprintf("ou=%s,%s", VirtualGroupsOU, *provider.BaseDn))
logger := log.WithField("logger", "authentik.outpost.ldap").WithField("provider", provider.Name)
providers[idx] = &ProviderInstance{
BaseDN: *provider.BaseDn,
VirtualGroupDN: virtualGroupDN,
GroupDN: groupDN,
UserDN: userDN,
appSlug: provider.ApplicationSlug,

View File

@ -48,3 +48,10 @@ func (ls *LDAPServer) Bind(bindDN string, bindPW string, conn net.Conn) (ldap.LD
req.log.WithField("request", "bind").Warning("No provider found for request")
return ldap.LDAPResultOperationsError, nil
}
func (ls *LDAPServer) TimerFlowCacheExpiry() {
for _, p := range ls.providers {
ls.log.WithField("flow", p.flowSlug).Debug("Pre-heating flow cache")
p.TimerFlowCacheExpiry()
}
}

View File

@ -118,3 +118,14 @@ func (pi *ProviderInstance) delayDeleteUserInfo(dn string) {
}
}()
}
func (pi *ProviderInstance) TimerFlowCacheExpiry() {
fe := outpost.NewFlowExecutor(context.Background(), pi.flowSlug, pi.s.ac.Client.GetConfig(), log.Fields{})
fe.Params.Add("goauthentik.io/outpost/ldap", "true")
fe.Params.Add("goauthentik.io/outpost/ldap-warmup", "true")
err := fe.WarmUp()
if err != nil {
pi.log.WithError(err).Warning("failed to warm up flow cache")
}
}

View File

@ -13,10 +13,10 @@ import (
func (pi *ProviderInstance) SearchMe(req SearchRequest, f UserFlags) (ldap.ServerSearchResult, error) {
if f.UserInfo == nil {
u, _, err := pi.s.ac.Client.CoreApi.CoreUsersRetrieve(req.ctx, f.UserInfo.Pk).Execute()
u, _, err := pi.s.ac.Client.CoreApi.CoreUsersRetrieve(req.ctx, f.UserPk).Execute()
if err != nil {
req.log.WithError(err).Warning("Failed to get user info")
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Failed to get userinfo")
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("failed to get userinfo")
}
f.UserInfo = &u
}
@ -59,6 +59,10 @@ func (pi *ProviderInstance) Search(req SearchRequest) (ldap.ServerSearchResult,
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: error parsing filter: %s", req.Filter)
}
// Create a custom client to set additional headers
c := api.NewAPIClient(pi.s.ac.Client.GetConfig())
c.GetConfig().AddDefaultHeader("X-authentik-outpost-ldap-query", req.Filter)
switch filterEntity {
default:
return ldap.ServerSearchResult{ResultCode: ldap.LDAPResultOperationsError}, fmt.Errorf("Search Error: unhandled filter type: %s [%s]", filterEntity, req.Filter)
@ -72,7 +76,12 @@ func (pi *ProviderInstance) Search(req SearchRequest) (ldap.ServerSearchResult,
go func() {
defer wg.Done()
gapisp := sentry.StartSpan(req.ctx, "authentik.providers.ldap.search.api_group")
groups, _, err := parseFilterForGroup(pi.s.ac.Client.CoreApi.CoreGroupsList(gapisp.Context()), parsedFilter).Execute()
searchReq, skip := parseFilterForGroup(c.CoreApi.CoreGroupsList(gapisp.Context()), parsedFilter, false)
if skip {
pi.log.Trace("Skip backend request")
return
}
groups, _, err := searchReq.Execute()
gapisp.Finish()
if err != nil {
req.log.WithError(err).Warning("failed to get groups")
@ -88,10 +97,15 @@ func (pi *ProviderInstance) Search(req SearchRequest) (ldap.ServerSearchResult,
go func() {
defer wg.Done()
uapisp := sentry.StartSpan(req.ctx, "authentik.providers.ldap.search.api_user")
users, _, err := parseFilterForUser(pi.s.ac.Client.CoreApi.CoreUsersList(uapisp.Context()), parsedFilter).Execute()
searchReq, skip := parseFilterForUser(c.CoreApi.CoreUsersList(uapisp.Context()), parsedFilter, false)
if skip {
pi.log.Trace("Skip backend request")
return
}
users, _, err := searchReq.Execute()
uapisp.Finish()
if err != nil {
req.log.WithError(err).Warning("failed to get groups")
req.log.WithError(err).Warning("failed to get users")
return
}
@ -103,7 +117,12 @@ func (pi *ProviderInstance) Search(req SearchRequest) (ldap.ServerSearchResult,
entries = append(gEntries, uEntries...)
case UserObjectClass, "":
uapisp := sentry.StartSpan(req.ctx, "authentik.providers.ldap.search.api_user")
users, _, err := parseFilterForUser(pi.s.ac.Client.CoreApi.CoreUsersList(uapisp.Context()), parsedFilter).Execute()
searchReq, skip := parseFilterForUser(c.CoreApi.CoreUsersList(uapisp.Context()), parsedFilter, false)
if skip {
pi.log.Trace("Skip backend request")
return ldap.ServerSearchResult{Entries: entries, Referrals: []string{}, Controls: []ldap.Control{}, ResultCode: ldap.LDAPResultSuccess}, nil
}
users, _, err := searchReq.Execute()
uapisp.Finish()
if err != nil {

View File

@ -7,51 +7,62 @@ import (
"goauthentik.io/api"
)
func parseFilterForGroup(req api.ApiCoreGroupsListRequest, f *ber.Packet) api.ApiCoreGroupsListRequest {
func parseFilterForGroup(req api.ApiCoreGroupsListRequest, f *ber.Packet, skip bool) (api.ApiCoreGroupsListRequest, bool) {
switch f.Tag {
case ldap.FilterEqualityMatch:
return parseFilterForGroupSingle(req, f)
case ldap.FilterAnd:
for _, child := range f.Children {
req = parseFilterForGroup(req, child)
r, s := parseFilterForGroup(req, child, skip)
skip = skip || s
req = r
}
return req
return req, skip
}
return req
return req, skip
}
func parseFilterForGroupSingle(req api.ApiCoreGroupsListRequest, f *ber.Packet) api.ApiCoreGroupsListRequest {
func parseFilterForGroupSingle(req api.ApiCoreGroupsListRequest, f *ber.Packet) (api.ApiCoreGroupsListRequest, bool) {
// We can only handle key = value pairs here
if len(f.Children) < 2 {
return req
return req, false
}
k := f.Children[0].Value
// Ensure key is string
if _, ok := k.(string); !ok {
return req
return req, false
}
v := f.Children[1].Value
// Null values are ignored
if v == nil {
return req
return req, false
}
// Switch on type of the value, then check the key
switch vv := v.(type) {
case string:
switch k {
case "cn":
return req.Name(vv)
return req.Name(vv), false
case "member":
fallthrough
case "memberOf":
userDN, err := goldap.ParseDN(vv)
if err != nil {
return req
return req.MembersByUsername([]string{vv}), false
}
username := userDN.RDNs[0].Attributes[0].Value
return req.MembersByUsername([]string{username})
// If the DN's first ou is virtual-groups, ignore this filter
if len(userDN.RDNs) > 1 {
if userDN.RDNs[1].Attributes[0].Value == VirtualGroupsOU || userDN.RDNs[1].Attributes[0].Value == GroupsOU {
// Since we know we're not filtering anything, skip this request
return req, true
}
}
return req.MembersByUsername([]string{username}), false
}
// TODO: Support int
default:
return req
return req, false
}
return req
return req, false
}

View File

@ -1,54 +1,73 @@
package ldap
import (
goldap "github.com/go-ldap/ldap/v3"
ber "github.com/nmcclain/asn1-ber"
"github.com/nmcclain/ldap"
"goauthentik.io/api"
)
func parseFilterForUser(req api.ApiCoreUsersListRequest, f *ber.Packet) api.ApiCoreUsersListRequest {
func parseFilterForUser(req api.ApiCoreUsersListRequest, f *ber.Packet, skip bool) (api.ApiCoreUsersListRequest, bool) {
switch f.Tag {
case ldap.FilterEqualityMatch:
return parseFilterForUserSingle(req, f)
case ldap.FilterAnd:
for _, child := range f.Children {
req = parseFilterForUser(req, child)
r, s := parseFilterForUser(req, child, skip)
skip = skip || s
req = r
}
return req
return req, skip
}
return req
return req, skip
}
func parseFilterForUserSingle(req api.ApiCoreUsersListRequest, f *ber.Packet) api.ApiCoreUsersListRequest {
func parseFilterForUserSingle(req api.ApiCoreUsersListRequest, f *ber.Packet) (api.ApiCoreUsersListRequest, bool) {
// We can only handle key = value pairs here
if len(f.Children) < 2 {
return req
return req, false
}
k := f.Children[0].Value
// Ensure key is string
if _, ok := k.(string); !ok {
return req
return req, false
}
v := f.Children[1].Value
// Null values are ignored
if v == nil {
return req
return req, false
}
// Switch on type of the value, then check the key
switch vv := v.(type) {
case string:
switch k {
case "cn":
return req.Username(vv)
return req.Username(vv), false
case "name":
case "displayName":
return req.Name(vv)
return req.Name(vv), false
case "mail":
return req.Email(vv)
return req.Email(vv), false
case "member":
fallthrough
case "memberOf":
groupDN, err := goldap.ParseDN(vv)
if err != nil {
return req.GroupsByName([]string{vv}), false
}
name := groupDN.RDNs[0].Attributes[0].Value
// If the DN's first ou is virtual-groups, ignore this filter
if len(groupDN.RDNs) > 1 {
if groupDN.RDNs[1].Attributes[0].Value == UsersOU || groupDN.RDNs[1].Attributes[0].Value == VirtualGroupsOU {
// Since we know we're not filtering anything, skip this request
return req, true
}
}
return req.GroupsByName([]string{name}), false
}
// TODO: Support int
default:
return req
return req, false
}
return req
return req, false
}

View File

@ -20,6 +20,8 @@ type ProviderInstance struct {
BaseDN string
UserDN string
VirtualGroupDN string
GroupDN string
appSlug string

View File

@ -95,7 +95,7 @@ func (pi *ProviderInstance) APIGroupToLDAPGroup(g api.Group) LDAPGroup {
func (pi *ProviderInstance) APIUserToLDAPGroup(u api.User) LDAPGroup {
return LDAPGroup{
dn: pi.GetGroupDN(u.Username),
dn: pi.GetVirtualGroupDN(u.Username),
cn: u.Username,
uid: u.Uid,
gidNumber: pi.GetUidNumber(u),
@ -114,6 +114,10 @@ func (pi *ProviderInstance) GetGroupDN(group string) string {
return fmt.Sprintf("cn=%s,%s", group, pi.GroupDN)
}
func (pi *ProviderInstance) GetVirtualGroupDN(group string) string {
return fmt.Sprintf("cn=%s,%s", group, pi.VirtualGroupDN)
}
func (pi *ProviderInstance) GetUidNumber(user api.User) string {
return strconv.FormatInt(int64(pi.uidStartNumber+user.Pk), 10)
}

View File

@ -60,6 +60,8 @@ func (s *Server) ServeHTTP() {
s.logger.Printf("closing %s", listener.Addr())
}
func (s *Server) TimerFlowCacheExpiry() {}
func (s *Server) Handler(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/akprox/ping" {
w.WriteHeader(204)

View File

@ -14,7 +14,7 @@ RUN docker-entrypoint.sh generate \
rm -f /local/api/go.mod /local/api/go.sum
# Stage 2: Build
FROM golang:1.16.7 AS builder
FROM golang:1.17.0 AS builder
WORKDIR /go/src/goauthentik.io

View File

@ -14,7 +14,7 @@ RUN docker-entrypoint.sh generate \
rm -f /local/api/go.mod /local/api/go.sum
# Stage 2: Build
FROM golang:1.16.7 AS builder
FROM golang:1.17.0 AS builder
WORKDIR /go/src/goauthentik.io

View File

@ -1,7 +1,7 @@
openapi: 3.0.3
info:
title: authentik
version: 2021.7.3
version: 2021.8.1-rc1
description: Making authentication simple.
contact:
email: hello@beryju.org
@ -2914,6 +2914,23 @@ paths:
name: email
schema:
type: string
- in: query
name: groups_by_name
schema:
type: array
items:
type: string
explode: true
style: form
- in: query
name: groups_by_pk
schema:
type: array
items:
type: string
format: uuid
explode: true
style: form
- in: query
name: is_active
schema:
@ -13178,7 +13195,14 @@ paths:
/api/v2beta/sources/oauth/source_types/:
get:
operationId: sources_oauth_source_types_list
description: Get all creatable source types
description: |-
Get all creatable source types. If ?name is set, only returns the type for <name>.
If <name> isn't found, returns the default type.
parameters:
- in: query
name: name
schema:
type: string
tags:
- sources
security:
@ -13197,208 +13221,6 @@ paths:
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
/api/v2beta/sources/oauth_user_connections/:
get:
operationId: sources_oauth_user_connections_list
description: Source Viewset
parameters:
- name: ordering
required: false
in: query
description: Which field to use when ordering the results.
schema:
type: string
- name: page
required: false
in: query
description: A page number within the paginated result set.
schema:
type: integer
- name: page_size
required: false
in: query
description: Number of results to return per page.
schema:
type: integer
- name: search
required: false
in: query
description: A search term.
schema:
type: string
- in: query
name: source__slug
schema:
type: string
tags:
- sources
security:
- authentik: []
- cookieAuth: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PaginatedUserOAuthSourceConnectionList'
description: ''
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
/api/v2beta/sources/oauth_user_connections/{id}/:
get:
operationId: sources_oauth_user_connections_retrieve
description: Source Viewset
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this User OAuth Source Connection.
required: true
tags:
- sources
security:
- authentik: []
- cookieAuth: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/UserOAuthSourceConnection'
description: ''
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
put:
operationId: sources_oauth_user_connections_update
description: Source Viewset
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this User OAuth Source Connection.
required: true
tags:
- sources
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UserOAuthSourceConnectionRequest'
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/UserOAuthSourceConnectionRequest'
multipart/form-data:
schema:
$ref: '#/components/schemas/UserOAuthSourceConnectionRequest'
required: true
security:
- authentik: []
- cookieAuth: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/UserOAuthSourceConnection'
description: ''
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
patch:
operationId: sources_oauth_user_connections_partial_update
description: Source Viewset
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this User OAuth Source Connection.
required: true
tags:
- sources
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PatchedUserOAuthSourceConnectionRequest'
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/PatchedUserOAuthSourceConnectionRequest'
multipart/form-data:
schema:
$ref: '#/components/schemas/PatchedUserOAuthSourceConnectionRequest'
security:
- authentik: []
- cookieAuth: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/UserOAuthSourceConnection'
description: ''
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
delete:
operationId: sources_oauth_user_connections_destroy
description: Source Viewset
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this User OAuth Source Connection.
required: true
tags:
- sources
security:
- authentik: []
- cookieAuth: []
responses:
'204':
description: No response body
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
/api/v2beta/sources/oauth_user_connections/{id}/used_by/:
get:
operationId: sources_oauth_user_connections_used_by_list
description: Get a list of all objects that use this object
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this User OAuth Source Connection.
required: true
tags:
- sources
security:
- authentik: []
- cookieAuth: []
responses:
'200':
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/UsedBy'
description: ''
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
/api/v2beta/sources/plex/:
get:
operationId: sources_plex_list
@ -14110,6 +13932,410 @@ paths:
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
/api/v2beta/sources/user_connections/oauth/:
get:
operationId: sources_user_connections_oauth_list
description: Source Viewset
parameters:
- name: ordering
required: false
in: query
description: Which field to use when ordering the results.
schema:
type: string
- name: page
required: false
in: query
description: A page number within the paginated result set.
schema:
type: integer
- name: page_size
required: false
in: query
description: Number of results to return per page.
schema:
type: integer
- name: search
required: false
in: query
description: A search term.
schema:
type: string
- in: query
name: source__slug
schema:
type: string
tags:
- sources
security:
- authentik: []
- cookieAuth: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PaginatedUserOAuthSourceConnectionList'
description: ''
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
/api/v2beta/sources/user_connections/oauth/{id}/:
get:
operationId: sources_user_connections_oauth_retrieve
description: Source Viewset
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this User OAuth Source Connection.
required: true
tags:
- sources
security:
- authentik: []
- cookieAuth: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/UserOAuthSourceConnection'
description: ''
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
put:
operationId: sources_user_connections_oauth_update
description: Source Viewset
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this User OAuth Source Connection.
required: true
tags:
- sources
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UserOAuthSourceConnectionRequest'
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/UserOAuthSourceConnectionRequest'
multipart/form-data:
schema:
$ref: '#/components/schemas/UserOAuthSourceConnectionRequest'
required: true
security:
- authentik: []
- cookieAuth: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/UserOAuthSourceConnection'
description: ''
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
patch:
operationId: sources_user_connections_oauth_partial_update
description: Source Viewset
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this User OAuth Source Connection.
required: true
tags:
- sources
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PatchedUserOAuthSourceConnectionRequest'
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/PatchedUserOAuthSourceConnectionRequest'
multipart/form-data:
schema:
$ref: '#/components/schemas/PatchedUserOAuthSourceConnectionRequest'
security:
- authentik: []
- cookieAuth: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/UserOAuthSourceConnection'
description: ''
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
delete:
operationId: sources_user_connections_oauth_destroy
description: Source Viewset
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this User OAuth Source Connection.
required: true
tags:
- sources
security:
- authentik: []
- cookieAuth: []
responses:
'204':
description: No response body
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
/api/v2beta/sources/user_connections/oauth/{id}/used_by/:
get:
operationId: sources_user_connections_oauth_used_by_list
description: Get a list of all objects that use this object
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this User OAuth Source Connection.
required: true
tags:
- sources
security:
- authentik: []
- cookieAuth: []
responses:
'200':
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/UsedBy'
description: ''
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
/api/v2beta/sources/user_connections/plex/:
get:
operationId: sources_user_connections_plex_list
description: Plex Source connection Serializer
parameters:
- name: ordering
required: false
in: query
description: Which field to use when ordering the results.
schema:
type: string
- name: page
required: false
in: query
description: A page number within the paginated result set.
schema:
type: integer
- name: page_size
required: false
in: query
description: Number of results to return per page.
schema:
type: integer
- name: search
required: false
in: query
description: A search term.
schema:
type: string
- in: query
name: source__slug
schema:
type: string
tags:
- sources
security:
- authentik: []
- cookieAuth: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PaginatedPlexSourceConnectionList'
description: ''
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
/api/v2beta/sources/user_connections/plex/{id}/:
get:
operationId: sources_user_connections_plex_retrieve
description: Plex Source connection Serializer
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this User Plex Source Connection.
required: true
tags:
- sources
security:
- authentik: []
- cookieAuth: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PlexSourceConnection'
description: ''
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
put:
operationId: sources_user_connections_plex_update
description: Plex Source connection Serializer
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this User Plex Source Connection.
required: true
tags:
- sources
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PlexSourceConnectionRequest'
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/PlexSourceConnectionRequest'
multipart/form-data:
schema:
$ref: '#/components/schemas/PlexSourceConnectionRequest'
required: true
security:
- authentik: []
- cookieAuth: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PlexSourceConnection'
description: ''
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
patch:
operationId: sources_user_connections_plex_partial_update
description: Plex Source connection Serializer
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this User Plex Source Connection.
required: true
tags:
- sources
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PatchedPlexSourceConnectionRequest'
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/PatchedPlexSourceConnectionRequest'
multipart/form-data:
schema:
$ref: '#/components/schemas/PatchedPlexSourceConnectionRequest'
security:
- authentik: []
- cookieAuth: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PlexSourceConnection'
description: ''
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
delete:
operationId: sources_user_connections_plex_destroy
description: Plex Source connection Serializer
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this User Plex Source Connection.
required: true
tags:
- sources
security:
- authentik: []
- cookieAuth: []
responses:
'204':
description: No response body
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
/api/v2beta/sources/user_connections/plex/{id}/used_by/:
get:
operationId: sources_user_connections_plex_used_by_list
description: Get a list of all objects that use this object
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this User Plex Source Connection.
required: true
tags:
- sources
security:
- authentik: []
- cookieAuth: []
responses:
'200':
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/UsedBy'
description: ''
'400':
$ref: '#/components/schemas/ValidationError'
'403':
$ref: '#/components/schemas/GenericError'
/api/v2beta/stages/all/:
get:
operationId: stages_all_list
@ -20423,7 +20649,19 @@ components:
type: array
items:
$ref: '#/components/schemas/CapabilitiesEnum'
cache_timeout:
type: integer
cache_timeout_flows:
type: integer
cache_timeout_policies:
type: integer
cache_timeout_reputation:
type: integer
required:
- cache_timeout
- cache_timeout_flows
- cache_timeout_policies
- cache_timeout_reputation
- capabilities
- error_reporting_enabled
- error_reporting_environment
@ -24767,6 +25005,41 @@ components:
required:
- pagination
- results
PaginatedPlexSourceConnectionList:
type: object
properties:
pagination:
type: object
properties:
next:
type: number
previous:
type: number
count:
type: number
current:
type: number
total_pages:
type: number
start_index:
type: number
end_index:
type: number
required:
- next
- previous
- count
- current
- total_pages
- start_index
- end_index
results:
type: array
items:
$ref: '#/components/schemas/PlexSourceConnection'
required:
- pagination
- results
PaginatedPlexSourceList:
type: object
properties:
@ -27099,6 +27372,19 @@ components:
minimum: -2147483648
description: How many attempts a user has before the flow is canceled. To
lock the user out, use a reputation policy and a user_write stage.
PatchedPlexSourceConnectionRequest:
type: object
description: Plex Source connection Serializer
properties:
user:
type: integer
source:
type: string
format: uuid
identifier:
type: string
plex_token:
type: string
PatchedPlexSourceRequest:
type: object
description: Plex Source Serializer
@ -27775,6 +28061,47 @@ components:
- slug
- verbose_name
- verbose_name_plural
PlexSourceConnection:
type: object
description: Plex Source connection Serializer
properties:
pk:
type: integer
readOnly: true
title: ID
user:
type: integer
source:
type: string
format: uuid
identifier:
type: string
plex_token:
type: string
required:
- identifier
- pk
- plex_token
- source
- user
PlexSourceConnectionRequest:
type: object
description: Plex Source connection Serializer
properties:
user:
type: integer
source:
type: string
format: uuid
identifier:
type: string
plex_token:
type: string
required:
- identifier
- plex_token
- source
- user
PlexSourceRequest:
type: object
description: Plex Source Serializer

View File

@ -118,7 +118,7 @@ class TestSourceOAuth2(SeleniumTestCase):
slug="dex",
authentication_flow=authentication_flow,
enrollment_flow=enrollment_flow,
provider_type="openid-connect",
provider_type="openidconnect",
authorization_url="http://127.0.0.1:5556/dex/auth",
access_token_url="http://127.0.0.1:5556/dex/token",
profile_url="http://127.0.0.1:5556/dex/userinfo",

View File

Before

Width:  |  Height:  |  Size: 284 B

After

Width:  |  Height:  |  Size: 284 B

View File

Before

Width:  |  Height:  |  Size: 878 B

After

Width:  |  Height:  |  Size: 878 B

4430
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -46,7 +46,7 @@
"@babel/preset-env": "^7.15.0",
"@babel/preset-typescript": "^7.15.0",
"@fortawesome/fontawesome-free": "^5.15.4",
"@goauthentik/api": "^1629055619.0.0",
"@goauthentik/api": "^1629704307.0.0",
"@lingui/cli": "^3.10.2",
"@lingui/core": "^3.10.4",
"@lingui/macro": "^3.10.2",
@ -61,14 +61,14 @@
"@types/chart.js": "^2.9.34",
"@types/codemirror": "5.60.2",
"@types/grecaptcha": "^3.0.3",
"@typescript-eslint/eslint-plugin": "^4.29.1",
"@typescript-eslint/parser": "^4.29.1",
"@typescript-eslint/eslint-plugin": "^4.29.2",
"@typescript-eslint/parser": "^4.29.2",
"@webcomponents/webcomponentsjs": "^2.6.0",
"babel-plugin-macros": "^3.1.0",
"base64-js": "^1.5.1",
"chart.js": "^3.5.0",
"chart.js": "^3.5.1",
"chartjs-adapter-moment": "^1.0.0",
"codemirror": "^5.62.2",
"codemirror": "^5.62.3",
"construct-style-sheets-polyfill": "^2.4.16",
"eslint": "^7.32.0",
"eslint-config-google": "^0.14.0",

View File

@ -32,7 +32,7 @@ export function configureSentry(canDoPpi: boolean = false): Promise<Config> {
return null;
}
}
if (hint.originalException instanceof Response) {
if (hint.originalException instanceof Response || hint.originalException instanceof DOMException) {
return null;
}
if (event.exception) {

View File

@ -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 = "2021.7.3";
export const VERSION = "2021.8.1-rc1";
export const PAGE_SIZE = 20;
export const TITLE_DEFAULT = "authentik";
export const ROUTE_SEPARATOR = ";";

View File

@ -1,9 +1,20 @@
import { css, CSSResult, customElement, html, LitElement, TemplateResult } from "lit-element";
import {
css,
CSSResult,
customElement,
html,
LitElement,
property,
TemplateResult,
} from "lit-element";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { PFSize } from "./Spinner";
@customElement("ak-loading-overlay")
export class LoadingOverlay extends LitElement {
@property({ type: Boolean })
topMost = false;
static get styles(): CSSResult[] {
return [
PFBase,
@ -18,6 +29,9 @@ export class LoadingOverlay extends LitElement {
background-color: var(--pf-global--BackgroundColor--dark-transparent-100);
z-index: 1;
}
:host([topMost]) {
z-index: 999;
}
`,
];
}

View File

@ -46,6 +46,9 @@ export class ModalButton extends LitElement {
@property({ type: Boolean })
open = false;
@property({ type: Boolean })
locked = false;
handlerBound = false;
static get styles(): CSSResult[] {
@ -63,6 +66,11 @@ export class ModalButton extends LitElement {
PFContent,
AKGlobal,
MODAL_BUTTON_STYLES,
css`
.locked {
overflow-y: hidden !important;
}
`,
];
}
@ -108,7 +116,11 @@ export class ModalButton extends LitElement {
renderModal(): TemplateResult {
return html`<div class="pf-c-backdrop">
<div class="pf-l-bullseye">
<div class="pf-c-modal-box ${this.size}" role="dialog" aria-modal="true">
<div
class="pf-c-modal-box ${this.size} ${this.locked ? "locked" : ""}"
role="dialog"
aria-modal="true"
>
<button
@click=${() => (this.open = false)}
class="pf-c-button pf-m-plain"

View File

@ -5,6 +5,7 @@ import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
import AKGlobal from "../../authentik.css";
import { t } from "@lingui/macro";
import { FormGroup } from "./FormGroup";
@customElement("ak-form-element-horizontal")
export class HorizontalFormElement extends LitElement {
@ -43,8 +44,20 @@ export class HorizontalFormElement extends LitElement {
@property()
errorMessage = "";
_invalid = false;
@property({ type: Boolean })
invalid = false;
set invalid(v: boolean) {
this._invalid = v;
// check if we're in a form group, and expand that form group
const parent = this.parentElement?.parentElement;
if (parent && "expanded" in parent) {
(parent as FormGroup).expanded = true;
}
}
get invalid(): boolean {
return this._invalid;
}
@property()
name = "";

View File

@ -30,6 +30,7 @@ export class ModalForm extends ModalButton {
form?.resetForm();
}
this.loading = false;
this.locked = false;
this.dispatchEvent(
new CustomEvent(EVENT_REFRESH, {
bubbles: true,
@ -39,12 +40,15 @@ export class ModalForm extends ModalButton {
})
.catch((exc) => {
this.loading = false;
this.locked = false;
throw exc;
});
}
renderModalInner(): TemplateResult {
return html`${this.loading ? html`<ak-loading-overlay></ak-loading-overlay>` : html``}
return html`${this.loading
? html`<ak-loading-overlay ?topMost=${true}></ak-loading-overlay>`
: html``}
<section class="pf-c-page__main-section pf-m-light">
<div class="pf-c-content">
<h1 class="pf-c-title pf-m-2xl">
@ -59,6 +63,7 @@ export class ModalForm extends ModalButton {
<ak-spinner-button
.callAction=${() => {
this.loading = true;
this.locked = true;
return this.confirm();
}}
class="pf-m-primary"

View File

@ -233,7 +233,6 @@ msgstr "App"
#: src/elements/user/UserConsentList.ts
#: src/pages/admin-overview/TopApplicationsTable.ts
#: src/pages/applications/ApplicationListPage.ts
#: src/pages/providers/ProviderListPage.ts
msgid "Application"
msgstr "Application"
@ -254,6 +253,10 @@ msgstr "Application requires following permissions:"
msgid "Application's display Name."
msgstr "Application's display Name."
#: src/pages/applications/ApplicationListPage.ts
msgid "Application(s)"
msgstr "Application(s)"
#: src/interfaces/AdminInterface.ts
#: src/pages/LibraryPage.ts
#: src/pages/applications/ApplicationListPage.ts
@ -284,7 +287,7 @@ msgstr ""
msgid "Are you sure you want to delete {0} {1}?"
msgstr "Are you sure you want to delete {0} {1}?"
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
msgid "Are you sure you want to delete {0} {objName} ?"
msgstr "Are you sure you want to delete {0} {objName} ?"
@ -363,9 +366,13 @@ msgstr "Authenticator"
msgid "Authorization"
msgstr "Authorization"
#:
#~ msgid "Authorization Code"
#~ msgstr "Authorization Code"
#: src/elements/oauth/UserCodeList.ts
msgid "Authorization Code"
msgstr "Authorization Code"
msgid "Authorization Code(s)"
msgstr "Authorization Code(s)"
#: src/pages/sources/oauth/OAuthSourceForm.ts
#: src/pages/sources/oauth/OAuthSourceViewPage.ts
@ -518,7 +525,7 @@ msgstr "Can be in the format of 'unix://' when connecting to a local docker daem
#: src/elements/forms/ConfirmationForm.ts
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
#: src/elements/forms/ModalForm.ts
#: src/pages/groups/MemberSelectModal.ts
#: src/pages/users/GroupSelectModal.ts
@ -552,9 +559,13 @@ msgstr "Certificate Subjet"
msgid "Certificate used to sign outgoing Responses going to the Service Provider."
msgstr "Certificate used to sign outgoing Responses going to the Service Provider."
#:
#~ msgid "Certificate-Key Pair"
#~ msgstr "Certificate-Key Pair"
#: src/pages/crypto/CertificateKeyPairListPage.ts
msgid "Certificate-Key Pair"
msgstr "Certificate-Key Pair"
msgid "Certificate-Key Pair(s)"
msgstr "Certificate-Key Pair(s)"
#: src/pages/crypto/CertificateKeyPairListPage.ts
msgid "Certificate-Key Pairs"
@ -792,6 +803,7 @@ msgid "Connect"
msgstr "Connect"
#: src/pages/user-settings/settings/SourceSettingsOAuth.ts
#: src/pages/user-settings/settings/SourceSettingsPlex.ts
msgid "Connected."
msgstr "Connected."
@ -804,9 +816,9 @@ msgstr "Connection error, reconnecting..."
msgid "Connection settings"
msgstr "Connection settings"
#: src/elements/user/UserConsentList.ts
msgid "Consent"
msgstr "Consent"
#:
#~ msgid "Consent"
#~ msgstr "Consent"
#: src/pages/stages/consent/ConsentStageForm.ts
msgid "Consent expires in"
@ -820,6 +832,10 @@ msgstr "Consent expires."
msgid "Consent given last indefinitely"
msgstr "Consent given last indefinitely"
#: src/elements/user/UserConsentList.ts
msgid "Consent(s)"
msgstr "Consent(s)"
#: src/pages/sources/ldap/LDAPSourceForm.ts
msgid "Consider Objects matching this filter to be Groups."
msgstr "Consider Objects matching this filter to be Groups."
@ -1091,17 +1107,21 @@ msgid "Define how notifications are sent to users, like Email or Webhook."
msgstr "Define how notifications are sent to users, like Email or Webhook."
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
#: src/elements/oauth/UserCodeList.ts
#: src/elements/oauth/UserRefreshList.ts
#: src/elements/user/SessionList.ts
#: src/elements/user/UserConsentList.ts
#: src/pages/applications/ApplicationListPage.ts
#: src/pages/crypto/CertificateKeyPairListPage.ts
#: src/pages/events/RuleListPage.ts
#: src/pages/events/TransportListPage.ts
#: src/pages/flows/BoundStagesList.ts
#: src/pages/flows/FlowListPage.ts
#: src/pages/groups/GroupListPage.ts
#: src/pages/outposts/OutpostListPage.ts
#: src/pages/outposts/ServiceConnectionListPage.ts
#: src/pages/policies/BoundPoliciesList.ts
#: src/pages/policies/PolicyListPage.ts
#: src/pages/policies/reputation/IPReputationListPage.ts
#: src/pages/policies/reputation/UserReputationListPage.ts
@ -1123,22 +1143,22 @@ msgstr "Delete"
#~ msgid "Delete Authorization Code"
#~ msgstr "Delete Authorization Code"
#: src/pages/flows/BoundStagesList.ts
#: src/pages/policies/BoundPoliciesList.ts
msgid "Delete Binding"
msgstr "Delete Binding"
#:
#:
#~ msgid "Delete Binding"
#~ msgstr "Delete Binding"
#: src/elements/user/UserConsentList.ts
msgid "Delete Consent"
msgstr "Delete Consent"
#:
#~ msgid "Delete Consent"
#~ msgstr "Delete Consent"
#:
#~ msgid "Delete Refresh Code"
#~ msgstr "Delete Refresh Code"
#: src/elements/user/SessionList.ts
msgid "Delete Session"
msgstr "Delete Session"
#:
#~ msgid "Delete Session"
#~ msgstr "Delete Session"
#: src/pages/user-settings/UserSelfForm.ts
msgid "Delete account"
@ -1165,7 +1185,7 @@ msgstr ""
"confirmation. Use a consent stage to ensure the user is aware of their actions."
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
msgid "Delete {0}"
msgstr "Delete {0}"
@ -1252,6 +1272,7 @@ msgid "Disabled"
msgstr "Disabled"
#: src/pages/user-settings/settings/SourceSettingsOAuth.ts
#: src/pages/user-settings/settings/SourceSettingsPlex.ts
msgid "Disconnect"
msgstr "Disconnect"
@ -1278,6 +1299,10 @@ msgstr "Download Certificate"
msgid "Download Private key"
msgstr "Download Private key"
#: src/pages/providers/ldap/LDAPProviderForm.ts
msgid "Due to protocol limitations, this certificate is only used when the outpost has a single provider."
msgstr "Due to protocol limitations, this certificate is only used when the outpost has a single provider."
#: src/pages/stages/dummy/DummyStageForm.ts
msgid "Dummy stage used for testing. Shows a simple continue button and always passes."
msgstr "Dummy stage used for testing. Shows a simple continue button and always passes."
@ -1536,6 +1561,7 @@ msgstr "Expires?"
msgid "Expiring"
msgstr "Expiring"
#: src/pages/crypto/CertificateKeyPairListPage.ts
#: src/pages/stages/invitation/InvitationListPage.ts
msgid "Expiry"
msgstr "Expiry"
@ -1607,7 +1633,7 @@ msgid "Failed to delete policy cache"
msgstr "Failed to delete policy cache"
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
msgid "Failed to delete {0}: {1}"
msgstr "Failed to delete {0}: {1}"
@ -1653,7 +1679,6 @@ msgid "Fields a user can identify themselves with. If no fields are selected, th
msgstr "Fields a user can identify themselves with. If no fields are selected, the user will only be able to use sources."
#: src/pages/flows/FlowImportForm.ts
#: src/pages/flows/FlowListPage.ts
msgid "Flow"
msgstr "Flow"
@ -1712,6 +1737,10 @@ msgstr "Flow used to logout. If left empty, the first applicable flow sorted by
msgid "Flow used when authorizing this provider."
msgstr "Flow used when authorizing this provider."
#: src/pages/flows/FlowListPage.ts
msgid "Flow(s)"
msgstr "Flow(s)"
#: src/interfaces/AdminInterface.ts
#: src/interfaces/AdminInterface.ts
#: src/pages/admin-overview/AdminOverviewPage.ts
@ -1794,7 +1823,6 @@ msgid "Go to previous page"
msgstr "Go to previous page"
#: src/pages/events/RuleForm.ts
#: src/pages/groups/GroupListPage.ts
#: src/pages/policies/PolicyBindingForm.ts
#: src/pages/policies/PolicyBindingForm.ts
#: src/pages/providers/ldap/LDAPProviderForm.ts
@ -1821,6 +1849,10 @@ msgstr "Group users together and give them permissions based on the membership."
msgid "Group {0}"
msgstr "Group {0}"
#: src/pages/groups/GroupListPage.ts
msgid "Group(s)"
msgstr "Group(s)"
#: src/interfaces/AdminInterface.ts
#: src/pages/admin-overview/AdminOverviewPage.ts
#: src/pages/groups/GroupListPage.ts
@ -1890,6 +1922,7 @@ msgstr "How many attempts a user has before the flow is canceled. To lock the us
#: src/elements/forms/DeleteBulkForm.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/users/UserListPage.ts
msgid "ID"
msgstr "ID"
@ -1940,6 +1973,10 @@ msgstr "If enabled, use the local connection. Required Docker socket/Kubernetes
msgid "If left empty, authentik will try to extract the launch URL based on the selected provider."
msgstr "If left empty, authentik will try to extract the launch URL based on the selected provider."
#: src/pages/providers/ldap/LDAPProviderForm.ts
msgid "If multiple providers share an outpost, a self-signed certificate is used."
msgstr "If multiple providers share an outpost, a self-signed certificate is used."
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
msgid "If no explicit redirect URIs are specified, any redirect URI is allowed."
msgstr "If no explicit redirect URIs are specified, any redirect URI is allowed."
@ -2038,14 +2075,18 @@ msgstr "Invalidation"
msgid "Invalidation flow"
msgstr "Invalidation flow"
#: src/pages/stages/invitation/InvitationListPage.ts
msgid "Invitation"
msgstr "Invitation"
#:
#~ msgid "Invitation"
#~ msgstr "Invitation"
#: src/pages/events/utils.ts
msgid "Invitation used"
msgstr "Invitation used"
#: src/pages/stages/invitation/InvitationListPage.ts
msgid "Invitation(s)"
msgstr "Invitation(s)"
#: src/interfaces/AdminInterface.ts
#: src/pages/stages/invitation/InvitationListPage.ts
msgid "Invitations"
@ -2233,7 +2274,6 @@ msgstr "Loading"
#: src/pages/sources/ldap/LDAPSourceForm.ts
#: src/pages/sources/oauth/OAuthSourceForm.ts
#: src/pages/sources/oauth/OAuthSourceForm.ts
#: src/pages/sources/oauth/OAuthSourceForm.ts
#: src/pages/sources/plex/PlexSourceForm.ts
#: src/pages/sources/plex/PlexSourceForm.ts
#: src/pages/sources/saml/SAMLSourceForm.ts
@ -2421,6 +2461,7 @@ msgstr "My Applications"
#: src/pages/applications/ApplicationListPage.ts
#: src/pages/crypto/CertificateKeyPairForm.ts
#: src/pages/crypto/CertificateKeyPairListPage.ts
#: src/pages/crypto/CertificateKeyPairListPage.ts
#: src/pages/events/EventInfo.ts
#: src/pages/events/RuleForm.ts
#: src/pages/events/RuleListPage.ts
@ -2607,6 +2648,7 @@ msgid "Not configured action"
msgstr "Not configured action"
#: src/pages/user-settings/settings/SourceSettingsOAuth.ts
#: src/pages/user-settings/settings/SourceSettingsPlex.ts
msgid "Not connected."
msgstr "Not connected."
@ -2647,17 +2689,25 @@ msgstr "Notification Rules"
msgid "Notification Transports"
msgstr "Notification Transports"
#:
#~ msgid "Notification rule"
#~ msgstr "Notification rule"
#: src/pages/events/RuleListPage.ts
msgid "Notification rule"
msgstr "Notification rule"
msgid "Notification rule(s)"
msgstr "Notification rule(s)"
#: src/pages/events/TransportListPage.ts
msgid "Notification transports(s)"
msgstr "Notification transports(s)"
#: src/elements/notifications/NotificationDrawer.ts
msgid "Notifications"
msgstr "Notifications"
#: src/pages/events/TransportListPage.ts
msgid "Notifications Transport"
msgstr "Notifications Transport"
#:
#~ msgid "Notifications Transport"
#~ msgstr "Notifications Transport"
#: src/pages/stages/prompt/PromptForm.ts
msgid "Number"
@ -2771,9 +2821,9 @@ msgstr "Other global settings"
msgid "Outdated outposts"
msgstr "Outdated outposts"
#: src/pages/outposts/OutpostListPage.ts
msgid "Outpost"
msgstr "Outpost"
#:
#~ msgid "Outpost"
#~ msgstr "Outpost"
#: src/pages/outposts/OutpostDeploymentModal.ts
msgid "Outpost Deployment Info"
@ -2783,14 +2833,22 @@ msgstr "Outpost Deployment Info"
#~ msgid "Outpost Service-connection"
#~ msgstr "Outpost Service-connection"
#:
#~ msgid "Outpost integration"
#~ msgstr "Outpost integration"
#: src/pages/outposts/ServiceConnectionListPage.ts
msgid "Outpost integration"
msgstr "Outpost integration"
msgid "Outpost integration(s)"
msgstr "Outpost integration(s)"
#: src/pages/admin-overview/AdminOverviewPage.ts
msgid "Outpost status"
msgstr "Outpost status"
#: src/pages/outposts/OutpostListPage.ts
msgid "Outpost(s)"
msgstr "Outpost(s)"
#: src/interfaces/AdminInterface.ts
#: src/interfaces/AdminInterface.ts
#: src/pages/outposts/OutpostListPage.ts
@ -2884,7 +2942,6 @@ msgstr "Policies"
#: src/pages/policies/PolicyBindingForm.ts
#: src/pages/policies/PolicyBindingForm.ts
#: src/pages/policies/PolicyBindingForm.ts
#: src/pages/policies/PolicyListPage.ts
msgid "Policy"
msgstr "Policy"
@ -2893,6 +2950,10 @@ msgstr "Policy"
msgid "Policy / Group / User Bindings"
msgstr "Policy / Group / User Bindings"
#: src/pages/policies/PolicyListPage.ts
msgid "Policy / Policies"
msgstr "Policy / Policies"
#: src/pages/policies/BoundPoliciesList.ts
msgid "Policy / User / Group"
msgstr "Policy / User / Group"
@ -2903,9 +2964,13 @@ msgstr "Policy / User / Group"
msgid "Policy Bindings"
msgstr "Policy Bindings"
#:
#~ msgid "Policy binding"
#~ msgstr "Policy binding"
#: src/pages/policies/BoundPoliciesList.ts
msgid "Policy binding"
msgstr "Policy binding"
msgid "Policy binding(s)"
msgstr "Policy binding(s)"
#: src/pages/applications/ApplicationForm.ts
#: src/pages/applications/ApplicationViewPage.ts
@ -2973,27 +3038,35 @@ msgstr "Private key, acquired from https://www.google.com/recaptcha/intro/v3.htm
msgid "Profile URL"
msgstr "Profile URL"
#: src/pages/stages/prompt/PromptListPage.ts
msgid "Prompt"
msgstr "Prompt"
#:
#~ msgid "Prompt"
#~ msgstr "Prompt"
#: src/pages/stages/consent/ConsentStageForm.ts
msgid "Prompt for the user's consent. The consent can either be permanent or expire in a defined amount of time."
msgstr "Prompt for the user's consent. The consent can either be permanent or expire in a defined amount of time."
#: src/pages/stages/prompt/PromptListPage.ts
msgid "Prompt(s)"
msgstr "Prompt(s)"
#: src/interfaces/AdminInterface.ts
#: src/pages/stages/prompt/PromptListPage.ts
msgid "Prompts"
msgstr "Prompts"
#: src/pages/property-mappings/PropertyMappingListPage.ts
msgid "Property Mapping"
msgstr "Property Mapping"
#:
#~ msgid "Property Mapping"
#~ msgstr "Property Mapping"
#: src/pages/events/utils.ts
msgid "Property Mapping exception"
msgstr "Property Mapping exception"
#: src/pages/property-mappings/PropertyMappingListPage.ts
msgid "Property Mapping(s)"
msgstr "Property Mapping(s)"
#: src/interfaces/AdminInterface.ts
#: src/pages/property-mappings/PropertyMappingListPage.ts
msgid "Property Mappings"
@ -3033,7 +3106,6 @@ msgstr "Provide support for protocols like SAML and OAuth to assigned applicatio
#: src/pages/applications/ApplicationForm.ts
#: src/pages/applications/ApplicationListPage.ts
#: src/pages/applications/ApplicationViewPage.ts
#: src/pages/providers/ProviderListPage.ts
msgid "Provider"
msgstr "Provider"
@ -3042,9 +3114,13 @@ msgstr "Provider"
msgid "Provider Type"
msgstr "Provider Type"
#: src/pages/sources/oauth/OAuthSourceForm.ts
msgid "Provider type"
msgstr "Provider type"
#:
#~ msgid "Provider type"
#~ msgstr "Provider type"
#: src/pages/providers/ProviderListPage.ts
msgid "Provider(s)"
msgstr "Provider(s)"
#: src/interfaces/AdminInterface.ts
#: src/pages/outposts/OutpostForm.ts
@ -3168,9 +3244,13 @@ msgstr "Redirect binding"
msgid "Refresh"
msgstr "Refresh"
#:
#~ msgid "Refresh Code"
#~ msgstr "Refresh Code"
#: src/elements/oauth/UserRefreshList.ts
msgid "Refresh Code"
msgstr "Refresh Code"
msgid "Refresh Code(s)"
msgstr "Refresh Code(s)"
#: src/flows/stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage.ts
msgid "Register device"
@ -3468,9 +3548,9 @@ msgstr "Server URI"
msgid "Server and client are further than 5 seconds apart."
msgstr "Server and client are further than 5 seconds apart."
#: src/pages/providers/ldap/LDAPProviderForm.ts
msgid "Server name for which this provider's certificate is valid for."
msgstr "Server name for which this provider's certificate is valid for."
#:
#~ msgid "Server name for which this provider's certificate is valid for."
#~ msgstr "Server name for which this provider's certificate is valid for."
#: src/flows/stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage.ts
msgid "Server validation of credential failed: {err}"
@ -3489,9 +3569,9 @@ msgstr "Service Provider Binding"
#~ msgid "Service connection"
#~ msgstr "Service connection"
#: src/elements/user/SessionList.ts
msgid "Session"
msgstr "Session"
#:
#~ msgid "Session"
#~ msgstr "Session"
#: src/pages/stages/user_login/UserLoginStageForm.ts
msgid "Session duration"
@ -3505,6 +3585,10 @@ msgstr "Session not valid on or after current time + this value (Format: hours=1
msgid "Session valid not on or after"
msgstr "Session valid not on or after"
#: src/elements/user/SessionList.ts
msgid "Session(s)"
msgstr "Session(s)"
#: src/pages/users/UserViewPage.ts
msgid "Sessions"
msgstr "Sessions"
@ -3585,18 +3669,23 @@ msgstr "Slug"
msgid "Something went wrong! Please try again later."
msgstr "Something went wrong! Please try again later."
#: src/pages/sources/SourcesListPage.ts
msgid "Source"
msgstr "Source"
#:
#~ msgid "Source"
#~ msgstr "Source"
#: src/pages/events/utils.ts
msgid "Source linked"
msgstr "Source linked"
#: src/pages/user-settings/settings/SourceSettingsOAuth.ts
#: src/pages/user-settings/settings/SourceSettingsPlex.ts
msgid "Source {0}"
msgstr "Source {0}"
#: src/pages/sources/SourcesListPage.ts
msgid "Source(s)"
msgstr "Source(s)"
#: src/interfaces/AdminInterface.ts
#: src/pages/sources/SourcesListPage.ts
#: src/pages/stages/identification/IdentificationStageForm.ts
@ -3619,9 +3708,13 @@ msgstr "Stage Bindings"
msgid "Stage Configuration"
msgstr "Stage Configuration"
#:
#~ msgid "Stage binding"
#~ msgstr "Stage binding"
#: src/pages/flows/BoundStagesList.ts
msgid "Stage binding"
msgstr "Stage binding"
msgid "Stage binding(s)"
msgstr "Stage binding(s)"
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
msgid "Stage used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again."
@ -3647,6 +3740,10 @@ msgstr "Stage used to configure a static authenticator (i.e. static tokens). Thi
msgid "Stage used to validate any authenticator. This stage should be used during authentication or authorization flows."
msgstr "Stage used to validate any authenticator. This stage should be used during authentication or authorization flows."
#: src/pages/stages/StageListPage.ts
msgid "Stage(s)"
msgstr "Stage(s)"
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
@ -3854,7 +3951,7 @@ msgid "Successfully created user."
msgstr "Successfully created user."
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
msgid "Successfully deleted {0} {1}"
msgstr "Successfully deleted {0} {1}"
@ -4078,9 +4175,9 @@ msgstr "System task execution"
msgid "TLS Authentication Certificate"
msgstr "TLS Authentication Certificate"
#: src/pages/providers/ldap/LDAPProviderForm.ts
msgid "TLS Server name"
msgstr "TLS Server name"
#:
#~ msgid "TLS Server name"
#~ msgstr "TLS Server name"
#: src/pages/outposts/ServiceConnectionDockerForm.ts
msgid "TLS Verification Certificate"
@ -4107,10 +4204,13 @@ msgid "Template"
msgstr "Template"
#: src/pages/events/EventListPage.ts
#: src/pages/tenants/TenantListPage.ts
msgid "Tenant"
msgstr "Tenant"
#: src/pages/tenants/TenantListPage.ts
msgid "Tenant(s)"
msgstr "Tenant(s)"
#: src/interfaces/AdminInterface.ts
#: src/pages/tenants/TenantListPage.ts
msgid "Tenants"
@ -4147,11 +4247,11 @@ msgstr "The external URL you'll access the application at. Include any non-stand
msgid "The external URL you'll authenticate at. Can be the same domain as authentik."
msgstr "The external URL you'll authenticate at. Can be the same domain as authentik."
#: src/elements/forms/DeleteBulkForm.ts
msgid "The following objects use {0}:"
msgstr "The following objects use {0}:"
#:
#~ msgid "The following objects use {0}:"
#~ msgstr "The following objects use {0}:"
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
msgid "The following objects use {objName}"
msgstr "The following objects use {objName}"
@ -4258,10 +4358,10 @@ msgstr "To"
msgid "To use SSL instead, use 'ldaps://' and disable this option."
msgstr "To use SSL instead, use 'ldaps://' and disable this option."
#: src/pages/tokens/TokenListPage.ts
#: src/pages/user-settings/tokens/UserTokenList.ts
msgid "Token"
msgstr "Token"
#:
#:
#~ msgid "Token"
#~ msgstr "Token"
#: src/pages/providers/oauth2/OAuth2ProviderViewPage.ts
#: src/pages/sources/oauth/OAuthSourceViewPage.ts
@ -4280,6 +4380,11 @@ msgstr "Token expiry"
msgid "Token validity"
msgstr "Token validity"
#: src/pages/tokens/TokenListPage.ts
#: src/pages/user-settings/tokens/UserTokenList.ts
msgid "Token(s)"
msgstr "Token(s)"
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
#: src/interfaces/AdminInterface.ts
#: src/pages/tokens/TokenListPage.ts
@ -4703,6 +4808,7 @@ msgstr "Userinfo URL"
#: src/pages/stages/identification/IdentificationStageForm.ts
#: src/pages/user-settings/UserSelfForm.ts
#: src/pages/users/UserForm.ts
#: src/pages/users/UserListPage.ts
#: src/pages/users/UserViewPage.ts
msgid "Username"
msgstr "Username"
@ -4924,7 +5030,7 @@ msgstr "authentik Builtin Database"
msgid "authentik LDAP Backend"
msgstr "authentik LDAP Backend"
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
msgid "connecting object will be deleted"
msgstr "connecting object will be deleted"
@ -4937,17 +5043,17 @@ msgid "no tabs defined"
msgstr "no tabs defined"
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
msgid "object will be DELETED"
msgstr "object will be DELETED"
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
msgid "reference will be reset to default value"
msgstr "reference will be reset to default value"
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
msgid "reference will be set to an empty value"
msgstr "reference will be set to an empty value"
@ -4965,7 +5071,7 @@ msgid "{0} ({1})"
msgstr "{0} ({1})"
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
msgid "{0} ({consequence})"
msgstr "{0} ({consequence})"

View File

@ -233,7 +233,6 @@ msgstr ""
#: src/elements/user/UserConsentList.ts
#: src/pages/admin-overview/TopApplicationsTable.ts
#: src/pages/applications/ApplicationListPage.ts
#: src/pages/providers/ProviderListPage.ts
msgid "Application"
msgstr ""
@ -254,6 +253,10 @@ msgstr ""
msgid "Application's display Name."
msgstr ""
#: src/pages/applications/ApplicationListPage.ts
msgid "Application(s)"
msgstr ""
#: src/interfaces/AdminInterface.ts
#: src/pages/LibraryPage.ts
#: src/pages/applications/ApplicationListPage.ts
@ -280,7 +283,7 @@ msgstr ""
msgid "Are you sure you want to delete {0} {1}?"
msgstr ""
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
msgid "Are you sure you want to delete {0} {objName} ?"
msgstr ""
@ -359,8 +362,12 @@ msgstr ""
msgid "Authorization"
msgstr ""
#:
#~ msgid "Authorization Code"
#~ msgstr ""
#: src/elements/oauth/UserCodeList.ts
msgid "Authorization Code"
msgid "Authorization Code(s)"
msgstr ""
#: src/pages/sources/oauth/OAuthSourceForm.ts
@ -514,7 +521,7 @@ msgstr ""
#: src/elements/forms/ConfirmationForm.ts
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
#: src/elements/forms/ModalForm.ts
#: src/pages/groups/MemberSelectModal.ts
#: src/pages/users/GroupSelectModal.ts
@ -548,8 +555,12 @@ msgstr ""
msgid "Certificate used to sign outgoing Responses going to the Service Provider."
msgstr ""
#:
#~ msgid "Certificate-Key Pair"
#~ msgstr ""
#: src/pages/crypto/CertificateKeyPairListPage.ts
msgid "Certificate-Key Pair"
msgid "Certificate-Key Pair(s)"
msgstr ""
#: src/pages/crypto/CertificateKeyPairListPage.ts
@ -786,6 +797,7 @@ msgid "Connect"
msgstr ""
#: src/pages/user-settings/settings/SourceSettingsOAuth.ts
#: src/pages/user-settings/settings/SourceSettingsPlex.ts
msgid "Connected."
msgstr ""
@ -798,9 +810,9 @@ msgstr ""
msgid "Connection settings"
msgstr ""
#: src/elements/user/UserConsentList.ts
msgid "Consent"
msgstr ""
#:
#~ msgid "Consent"
#~ msgstr ""
#: src/pages/stages/consent/ConsentStageForm.ts
msgid "Consent expires in"
@ -814,6 +826,10 @@ msgstr ""
msgid "Consent given last indefinitely"
msgstr ""
#: src/elements/user/UserConsentList.ts
msgid "Consent(s)"
msgstr ""
#: src/pages/sources/ldap/LDAPSourceForm.ts
msgid "Consider Objects matching this filter to be Groups."
msgstr ""
@ -1085,17 +1101,21 @@ msgid "Define how notifications are sent to users, like Email or Webhook."
msgstr ""
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
#: src/elements/oauth/UserCodeList.ts
#: src/elements/oauth/UserRefreshList.ts
#: src/elements/user/SessionList.ts
#: src/elements/user/UserConsentList.ts
#: src/pages/applications/ApplicationListPage.ts
#: src/pages/crypto/CertificateKeyPairListPage.ts
#: src/pages/events/RuleListPage.ts
#: src/pages/events/TransportListPage.ts
#: src/pages/flows/BoundStagesList.ts
#: src/pages/flows/FlowListPage.ts
#: src/pages/groups/GroupListPage.ts
#: src/pages/outposts/OutpostListPage.ts
#: src/pages/outposts/ServiceConnectionListPage.ts
#: src/pages/policies/BoundPoliciesList.ts
#: src/pages/policies/PolicyListPage.ts
#: src/pages/policies/reputation/IPReputationListPage.ts
#: src/pages/policies/reputation/UserReputationListPage.ts
@ -1117,22 +1137,22 @@ msgstr ""
#~ msgid "Delete Authorization Code"
#~ msgstr ""
#: src/pages/flows/BoundStagesList.ts
#: src/pages/policies/BoundPoliciesList.ts
msgid "Delete Binding"
msgstr ""
#:
#:
#~ msgid "Delete Binding"
#~ msgstr ""
#: src/elements/user/UserConsentList.ts
msgid "Delete Consent"
msgstr ""
#:
#~ msgid "Delete Consent"
#~ msgstr ""
#:
#~ msgid "Delete Refresh Code"
#~ msgstr ""
#: src/elements/user/SessionList.ts
msgid "Delete Session"
msgstr ""
#:
#~ msgid "Delete Session"
#~ msgstr ""
#: src/pages/user-settings/UserSelfForm.ts
msgid "Delete account"
@ -1157,7 +1177,7 @@ msgid ""
msgstr ""
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
msgid "Delete {0}"
msgstr ""
@ -1244,6 +1264,7 @@ msgid "Disabled"
msgstr ""
#: src/pages/user-settings/settings/SourceSettingsOAuth.ts
#: src/pages/user-settings/settings/SourceSettingsPlex.ts
msgid "Disconnect"
msgstr ""
@ -1270,6 +1291,10 @@ msgstr ""
msgid "Download Private key"
msgstr ""
#: src/pages/providers/ldap/LDAPProviderForm.ts
msgid "Due to protocol limitations, this certificate is only used when the outpost has a single provider."
msgstr ""
#: src/pages/stages/dummy/DummyStageForm.ts
msgid "Dummy stage used for testing. Shows a simple continue button and always passes."
msgstr ""
@ -1528,6 +1553,7 @@ msgstr ""
msgid "Expiring"
msgstr ""
#: src/pages/crypto/CertificateKeyPairListPage.ts
#: src/pages/stages/invitation/InvitationListPage.ts
msgid "Expiry"
msgstr ""
@ -1599,7 +1625,7 @@ msgid "Failed to delete policy cache"
msgstr ""
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
msgid "Failed to delete {0}: {1}"
msgstr ""
@ -1645,7 +1671,6 @@ msgid "Fields a user can identify themselves with. If no fields are selected, th
msgstr ""
#: src/pages/flows/FlowImportForm.ts
#: src/pages/flows/FlowListPage.ts
msgid "Flow"
msgstr ""
@ -1704,6 +1729,10 @@ msgstr ""
msgid "Flow used when authorizing this provider."
msgstr ""
#: src/pages/flows/FlowListPage.ts
msgid "Flow(s)"
msgstr ""
#: src/interfaces/AdminInterface.ts
#: src/interfaces/AdminInterface.ts
#: src/pages/admin-overview/AdminOverviewPage.ts
@ -1786,7 +1815,6 @@ msgid "Go to previous page"
msgstr ""
#: src/pages/events/RuleForm.ts
#: src/pages/groups/GroupListPage.ts
#: src/pages/policies/PolicyBindingForm.ts
#: src/pages/policies/PolicyBindingForm.ts
#: src/pages/providers/ldap/LDAPProviderForm.ts
@ -1813,6 +1841,10 @@ msgstr ""
msgid "Group {0}"
msgstr ""
#: src/pages/groups/GroupListPage.ts
msgid "Group(s)"
msgstr ""
#: src/interfaces/AdminInterface.ts
#: src/pages/admin-overview/AdminOverviewPage.ts
#: src/pages/groups/GroupListPage.ts
@ -1882,6 +1914,7 @@ msgstr ""
#: src/elements/forms/DeleteBulkForm.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/users/UserListPage.ts
msgid "ID"
msgstr ""
@ -1932,6 +1965,10 @@ msgstr ""
msgid "If left empty, authentik will try to extract the launch URL based on the selected provider."
msgstr ""
#: src/pages/providers/ldap/LDAPProviderForm.ts
msgid "If multiple providers share an outpost, a self-signed certificate is used."
msgstr ""
#: src/pages/providers/oauth2/OAuth2ProviderForm.ts
msgid "If no explicit redirect URIs are specified, any redirect URI is allowed."
msgstr ""
@ -2030,14 +2067,18 @@ msgstr ""
msgid "Invalidation flow"
msgstr ""
#: src/pages/stages/invitation/InvitationListPage.ts
msgid "Invitation"
msgstr ""
#:
#~ msgid "Invitation"
#~ msgstr ""
#: src/pages/events/utils.ts
msgid "Invitation used"
msgstr ""
#: src/pages/stages/invitation/InvitationListPage.ts
msgid "Invitation(s)"
msgstr ""
#: src/interfaces/AdminInterface.ts
#: src/pages/stages/invitation/InvitationListPage.ts
msgid "Invitations"
@ -2225,7 +2266,6 @@ msgstr ""
#: src/pages/sources/ldap/LDAPSourceForm.ts
#: src/pages/sources/oauth/OAuthSourceForm.ts
#: src/pages/sources/oauth/OAuthSourceForm.ts
#: src/pages/sources/oauth/OAuthSourceForm.ts
#: src/pages/sources/plex/PlexSourceForm.ts
#: src/pages/sources/plex/PlexSourceForm.ts
#: src/pages/sources/saml/SAMLSourceForm.ts
@ -2413,6 +2453,7 @@ msgstr ""
#: src/pages/applications/ApplicationListPage.ts
#: src/pages/crypto/CertificateKeyPairForm.ts
#: src/pages/crypto/CertificateKeyPairListPage.ts
#: src/pages/crypto/CertificateKeyPairListPage.ts
#: src/pages/events/EventInfo.ts
#: src/pages/events/RuleForm.ts
#: src/pages/events/RuleListPage.ts
@ -2599,6 +2640,7 @@ msgid "Not configured action"
msgstr ""
#: src/pages/user-settings/settings/SourceSettingsOAuth.ts
#: src/pages/user-settings/settings/SourceSettingsPlex.ts
msgid "Not connected."
msgstr ""
@ -2639,17 +2681,25 @@ msgstr ""
msgid "Notification Transports"
msgstr ""
#:
#~ msgid "Notification rule"
#~ msgstr ""
#: src/pages/events/RuleListPage.ts
msgid "Notification rule"
msgid "Notification rule(s)"
msgstr ""
#: src/pages/events/TransportListPage.ts
msgid "Notification transports(s)"
msgstr ""
#: src/elements/notifications/NotificationDrawer.ts
msgid "Notifications"
msgstr ""
#: src/pages/events/TransportListPage.ts
msgid "Notifications Transport"
msgstr ""
#:
#~ msgid "Notifications Transport"
#~ msgstr ""
#: src/pages/stages/prompt/PromptForm.ts
msgid "Number"
@ -2763,9 +2813,9 @@ msgstr ""
msgid "Outdated outposts"
msgstr ""
#: src/pages/outposts/OutpostListPage.ts
msgid "Outpost"
msgstr ""
#:
#~ msgid "Outpost"
#~ msgstr ""
#: src/pages/outposts/OutpostDeploymentModal.ts
msgid "Outpost Deployment Info"
@ -2775,14 +2825,22 @@ msgstr ""
#~ msgid "Outpost Service-connection"
#~ msgstr ""
#:
#~ msgid "Outpost integration"
#~ msgstr ""
#: src/pages/outposts/ServiceConnectionListPage.ts
msgid "Outpost integration"
msgid "Outpost integration(s)"
msgstr ""
#: src/pages/admin-overview/AdminOverviewPage.ts
msgid "Outpost status"
msgstr ""
#: src/pages/outposts/OutpostListPage.ts
msgid "Outpost(s)"
msgstr ""
#: src/interfaces/AdminInterface.ts
#: src/interfaces/AdminInterface.ts
#: src/pages/outposts/OutpostListPage.ts
@ -2876,7 +2934,6 @@ msgstr ""
#: src/pages/policies/PolicyBindingForm.ts
#: src/pages/policies/PolicyBindingForm.ts
#: src/pages/policies/PolicyBindingForm.ts
#: src/pages/policies/PolicyListPage.ts
msgid "Policy"
msgstr ""
@ -2885,6 +2942,10 @@ msgstr ""
msgid "Policy / Group / User Bindings"
msgstr ""
#: src/pages/policies/PolicyListPage.ts
msgid "Policy / Policies"
msgstr ""
#: src/pages/policies/BoundPoliciesList.ts
msgid "Policy / User / Group"
msgstr ""
@ -2895,8 +2956,12 @@ msgstr ""
msgid "Policy Bindings"
msgstr ""
#:
#~ msgid "Policy binding"
#~ msgstr ""
#: src/pages/policies/BoundPoliciesList.ts
msgid "Policy binding"
msgid "Policy binding(s)"
msgstr ""
#: src/pages/applications/ApplicationForm.ts
@ -2965,27 +3030,35 @@ msgstr ""
msgid "Profile URL"
msgstr ""
#: src/pages/stages/prompt/PromptListPage.ts
msgid "Prompt"
msgstr ""
#:
#~ msgid "Prompt"
#~ msgstr ""
#: src/pages/stages/consent/ConsentStageForm.ts
msgid "Prompt for the user's consent. The consent can either be permanent or expire in a defined amount of time."
msgstr ""
#: src/pages/stages/prompt/PromptListPage.ts
msgid "Prompt(s)"
msgstr ""
#: src/interfaces/AdminInterface.ts
#: src/pages/stages/prompt/PromptListPage.ts
msgid "Prompts"
msgstr ""
#: src/pages/property-mappings/PropertyMappingListPage.ts
msgid "Property Mapping"
msgstr ""
#:
#~ msgid "Property Mapping"
#~ msgstr ""
#: src/pages/events/utils.ts
msgid "Property Mapping exception"
msgstr ""
#: src/pages/property-mappings/PropertyMappingListPage.ts
msgid "Property Mapping(s)"
msgstr ""
#: src/interfaces/AdminInterface.ts
#: src/pages/property-mappings/PropertyMappingListPage.ts
msgid "Property Mappings"
@ -3025,7 +3098,6 @@ msgstr ""
#: src/pages/applications/ApplicationForm.ts
#: src/pages/applications/ApplicationListPage.ts
#: src/pages/applications/ApplicationViewPage.ts
#: src/pages/providers/ProviderListPage.ts
msgid "Provider"
msgstr ""
@ -3034,8 +3106,12 @@ msgstr ""
msgid "Provider Type"
msgstr ""
#: src/pages/sources/oauth/OAuthSourceForm.ts
msgid "Provider type"
#:
#~ msgid "Provider type"
#~ msgstr ""
#: src/pages/providers/ProviderListPage.ts
msgid "Provider(s)"
msgstr ""
#: src/interfaces/AdminInterface.ts
@ -3160,8 +3236,12 @@ msgstr ""
msgid "Refresh"
msgstr ""
#:
#~ msgid "Refresh Code"
#~ msgstr ""
#: src/elements/oauth/UserRefreshList.ts
msgid "Refresh Code"
msgid "Refresh Code(s)"
msgstr ""
#: src/flows/stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage.ts
@ -3460,9 +3540,9 @@ msgstr ""
msgid "Server and client are further than 5 seconds apart."
msgstr ""
#: src/pages/providers/ldap/LDAPProviderForm.ts
msgid "Server name for which this provider's certificate is valid for."
msgstr ""
#:
#~ msgid "Server name for which this provider's certificate is valid for."
#~ msgstr ""
#: src/flows/stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage.ts
msgid "Server validation of credential failed: {err}"
@ -3481,9 +3561,9 @@ msgstr ""
#~ msgid "Service connection"
#~ msgstr ""
#: src/elements/user/SessionList.ts
msgid "Session"
msgstr ""
#:
#~ msgid "Session"
#~ msgstr ""
#: src/pages/stages/user_login/UserLoginStageForm.ts
msgid "Session duration"
@ -3497,6 +3577,10 @@ msgstr ""
msgid "Session valid not on or after"
msgstr ""
#: src/elements/user/SessionList.ts
msgid "Session(s)"
msgstr ""
#: src/pages/users/UserViewPage.ts
msgid "Sessions"
msgstr ""
@ -3577,18 +3661,23 @@ msgstr ""
msgid "Something went wrong! Please try again later."
msgstr ""
#: src/pages/sources/SourcesListPage.ts
msgid "Source"
msgstr ""
#:
#~ msgid "Source"
#~ msgstr ""
#: src/pages/events/utils.ts
msgid "Source linked"
msgstr ""
#: src/pages/user-settings/settings/SourceSettingsOAuth.ts
#: src/pages/user-settings/settings/SourceSettingsPlex.ts
msgid "Source {0}"
msgstr ""
#: src/pages/sources/SourcesListPage.ts
msgid "Source(s)"
msgstr ""
#: src/interfaces/AdminInterface.ts
#: src/pages/sources/SourcesListPage.ts
#: src/pages/stages/identification/IdentificationStageForm.ts
@ -3611,8 +3700,12 @@ msgstr ""
msgid "Stage Configuration"
msgstr ""
#:
#~ msgid "Stage binding"
#~ msgstr ""
#: src/pages/flows/BoundStagesList.ts
msgid "Stage binding"
msgid "Stage binding(s)"
msgstr ""
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
@ -3639,6 +3732,10 @@ msgstr ""
msgid "Stage used to validate any authenticator. This stage should be used during authentication or authorization flows."
msgstr ""
#: src/pages/stages/StageListPage.ts
msgid "Stage(s)"
msgstr ""
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
@ -3846,7 +3943,7 @@ msgid "Successfully created user."
msgstr ""
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
msgid "Successfully deleted {0} {1}"
msgstr ""
@ -4070,9 +4167,9 @@ msgstr ""
msgid "TLS Authentication Certificate"
msgstr ""
#: src/pages/providers/ldap/LDAPProviderForm.ts
msgid "TLS Server name"
msgstr ""
#:
#~ msgid "TLS Server name"
#~ msgstr ""
#: src/pages/outposts/ServiceConnectionDockerForm.ts
msgid "TLS Verification Certificate"
@ -4099,10 +4196,13 @@ msgid "Template"
msgstr ""
#: src/pages/events/EventListPage.ts
#: src/pages/tenants/TenantListPage.ts
msgid "Tenant"
msgstr ""
#: src/pages/tenants/TenantListPage.ts
msgid "Tenant(s)"
msgstr ""
#: src/interfaces/AdminInterface.ts
#: src/pages/tenants/TenantListPage.ts
msgid "Tenants"
@ -4139,11 +4239,11 @@ msgstr ""
msgid "The external URL you'll authenticate at. Can be the same domain as authentik."
msgstr ""
#: src/elements/forms/DeleteBulkForm.ts
msgid "The following objects use {0}:"
msgstr ""
#:
#~ msgid "The following objects use {0}:"
#~ msgstr ""
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
msgid "The following objects use {objName}"
msgstr ""
@ -4243,10 +4343,10 @@ msgstr ""
msgid "To use SSL instead, use 'ldaps://' and disable this option."
msgstr ""
#: src/pages/tokens/TokenListPage.ts
#: src/pages/user-settings/tokens/UserTokenList.ts
msgid "Token"
msgstr ""
#:
#:
#~ msgid "Token"
#~ msgstr ""
#: src/pages/providers/oauth2/OAuth2ProviderViewPage.ts
#: src/pages/sources/oauth/OAuthSourceViewPage.ts
@ -4265,6 +4365,11 @@ msgstr ""
msgid "Token validity"
msgstr ""
#: src/pages/tokens/TokenListPage.ts
#: src/pages/user-settings/tokens/UserTokenList.ts
msgid "Token(s)"
msgstr ""
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
#: src/interfaces/AdminInterface.ts
#: src/pages/tokens/TokenListPage.ts
@ -4688,6 +4793,7 @@ msgstr ""
#: src/pages/stages/identification/IdentificationStageForm.ts
#: src/pages/user-settings/UserSelfForm.ts
#: src/pages/users/UserForm.ts
#: src/pages/users/UserListPage.ts
#: src/pages/users/UserViewPage.ts
msgid "Username"
msgstr ""
@ -4907,7 +5013,7 @@ msgstr ""
msgid "authentik LDAP Backend"
msgstr ""
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
msgid "connecting object will be deleted"
msgstr ""
@ -4920,17 +5026,17 @@ msgid "no tabs defined"
msgstr ""
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
msgid "object will be DELETED"
msgstr ""
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
msgid "reference will be reset to default value"
msgstr ""
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
msgid "reference will be set to an empty value"
msgstr ""
@ -4948,7 +5054,7 @@ msgid "{0} ({1})"
msgstr ""
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteBulkForm.ts
#: src/elements/forms/DeleteForm.ts
msgid "{0} ({consequence})"
msgstr ""

View File

@ -40,6 +40,7 @@ export class LDAPProviderFormPage extends ModelForm<LDAPProvider, number> {
lDAPProviderRequest: data,
});
} else {
data.tlsServerName = "";
return new ProvidersApi(DEFAULT_CONFIG).providersLdapCreate({
lDAPProviderRequest: data,
});
@ -129,16 +130,6 @@ export class LDAPProviderFormPage extends ModelForm<LDAPProvider, number> {
${t`LDAP DN under which bind requests and search requests can be made.`}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`TLS Server name`} name="tlsServerName">
<input
type="text"
value="${first(this.instance?.tlsServerName, "")}"
class="pf-c-form-control"
/>
<p class="pf-c-form__helper-text">
${t`Server name for which this provider's certificate is valid for.`}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`Certificate`} name="certificate">
<select class="pf-c-form-control">
<option value="" ?selected=${this.instance?.certificate === undefined}>
@ -163,6 +154,12 @@ export class LDAPProviderFormPage extends ModelForm<LDAPProvider, number> {
html`<option>${t`Loading...`}</option>`,
)}
</select>
<p class="pf-c-form__helper-text">
${t`Due to protocol limitations, this certificate is only used when the outpost has a single provider.`}
</p>
<p class="pf-c-form__helper-text">
${t`If multiple providers share an outpost, a self-signed certificate is used.`}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${t`UID start number`}

View File

@ -5,6 +5,7 @@ import {
UserMatchingModeEnum,
OAuthSourceRequest,
FlowsInstancesListDesignationEnum,
SourceType,
} from "@goauthentik/api";
import { t } from "@lingui/macro";
import { customElement, property } from "lit-element";
@ -25,19 +26,30 @@ export class OAuthSourceForm extends ModelForm<OAuthSource, string> {
slug: pk,
})
.then((source) => {
this.showUrlOptions = first(source.type?.urlsCustomizable, false);
this.providerType = source.type;
return source;
});
}
_modelName?: string;
@property()
modelName?: string;
set modelName(v: string | undefined) {
this._modelName = v;
new SourcesApi(DEFAULT_CONFIG)
.sourcesOauthSourceTypesList({
name: v?.replace("oauthsource", ""),
})
.then((type) => {
this.providerType = type[0];
});
}
get modelName(): string | undefined {
return this._modelName;
}
@property({ type: Boolean })
showUrlOptions = false;
@property({ type: Boolean })
showRequestTokenURL = false;
@property({ attribute: false })
providerType?: SourceType;
getSuccessMessage(): string {
if (this.instance) {
@ -48,6 +60,7 @@ export class OAuthSourceForm extends ModelForm<OAuthSource, string> {
}
send = (data: OAuthSource): Promise<OAuthSource> => {
data.providerType = this.providerType?.slug || "";
if (this.instance?.slug) {
return new SourcesApi(DEFAULT_CONFIG).sourcesOauthPartialUpdate({
slug: this.instance.slug,
@ -61,7 +74,7 @@ export class OAuthSourceForm extends ModelForm<OAuthSource, string> {
};
renderUrlOptions(): TemplateResult {
if (!this.showUrlOptions) {
if (!this.providerType?.urlsCustomizable) {
return html``;
}
return html` <ak-form-group>
@ -74,7 +87,10 @@ export class OAuthSourceForm extends ModelForm<OAuthSource, string> {
>
<input
type="text"
value="${first(this.instance?.authorizationUrl, "")}"
value="${first(
this.instance?.authorizationUrl,
this.providerType.authorizationUrl,
)}"
class="pf-c-form-control"
required
/>
@ -89,7 +105,10 @@ export class OAuthSourceForm extends ModelForm<OAuthSource, string> {
>
<input
type="text"
value="${first(this.instance?.accessTokenUrl, "")}"
value="${first(
this.instance?.accessTokenUrl,
this.providerType.accessTokenUrl,
)}"
class="pf-c-form-control"
required
/>
@ -104,7 +123,7 @@ export class OAuthSourceForm extends ModelForm<OAuthSource, string> {
>
<input
type="text"
value="${first(this.instance?.profileUrl, "")}"
value="${first(this.instance?.profileUrl, this.providerType.profileUrl)}"
class="pf-c-form-control"
required
/>
@ -112,7 +131,7 @@ export class OAuthSourceForm extends ModelForm<OAuthSource, string> {
${t`URL used by authentik to get user information.`}
</p>
</ak-form-element-horizontal>
${this.showRequestTokenURL
${this.providerType.requestTokenUrl
? html`<ak-form-element-horizontal
label=${t`Request token URL`}
name="requestTokenUrl"
@ -226,54 +245,6 @@ export class OAuthSourceForm extends ModelForm<OAuthSource, string> {
>
<input type="text" value="" class="pf-c-form-control" required />
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`Provider type`} name="providerType">
<select
class="pf-c-form-control"
@change=${(ev: Event) => {
const el = ev.target as HTMLSelectElement;
const selected = el.selectedOptions[0];
this.showUrlOptions = "data-urls-custom" in selected.attributes;
this.showRequestTokenURL =
"data-request-token" in selected.attributes;
if (!this.instance) {
this.instance = {} as OAuthSource;
}
this.instance.providerType = selected.value;
}}
>
${until(
new SourcesApi(DEFAULT_CONFIG)
.sourcesOauthSourceTypesList()
.then((types) => {
return types.map((type) => {
let selected =
this.instance?.providerType === type.slug;
const modelSlug = this.modelName
?.replace("oauthsource", "")
.replace("-", "");
const typeSlug = type.slug.replace("-", "");
if (!this.instance?.pk) {
if (modelSlug === typeSlug) {
selected = true;
this.showUrlOptions = type.urlsCustomizable;
this.showRequestTokenURL =
type.requestTokenUrl !== null;
}
}
return html`<option
?data-urls-custom=${type.urlsCustomizable}
?data-request-token=${type.requestTokenUrl}
value=${type.slug}
?selected=${selected}
>
${type.name}
</option>`;
});
}),
html`<option>${t`Loading...`}</option>`,
)}
</select>
</ak-form-element-horizontal>
</div>
</ak-form-group>
${this.renderUrlOptions()}

View File

@ -27,6 +27,7 @@ import "./settings/UserSettingsAuthenticatorTOTP";
import "./settings/UserSettingsAuthenticatorWebAuthn";
import "./settings/UserSettingsPassword";
import "./settings/SourceSettingsOAuth";
import "./settings/SourceSettingsPlex";
import { EVENT_REFRESH } from "../../constants";
@customElement("ak-user-settings")
@ -112,6 +113,12 @@ export class UserSettingsPage extends LitElement {
.configureUrl=${source.configureUrl}
>
</ak-user-settings-source-oauth>`;
case "ak-user-settings-source-plex":
return html`<ak-user-settings-source-plex
objectId=${source.objectUid}
title=${source.title}
>
</ak-user-settings-source-plex>`;
default:
return html`<p>${t`Error: unsupported source settings: ${source.component}`}</p>`;
}

View File

@ -21,7 +21,7 @@ export class SourceSettingsOAuth extends BaseUserSettings {
renderInner(): TemplateResult {
return html`${until(
new SourcesApi(DEFAULT_CONFIG)
.sourcesOauthUserConnectionsList({
.sourcesUserConnectionsOauthList({
sourceSlug: this.objectId,
})
.then((connection) => {
@ -32,7 +32,7 @@ export class SourceSettingsOAuth extends BaseUserSettings {
@click=${() => {
return new SourcesApi(
DEFAULT_CONFIG,
).sourcesOauthUserConnectionsDestroy({
).sourcesUserConnectionsOauthDestroy({
id: connection.results[0].pk || 0,
});
}}

View File

@ -0,0 +1,46 @@
import { customElement, html, property, TemplateResult } from "lit-element";
import { BaseUserSettings } from "./BaseUserSettings";
import { SourcesApi } from "@goauthentik/api";
import { until } from "lit-html/directives/until";
import { DEFAULT_CONFIG } from "../../../api/Config";
import { t } from "@lingui/macro";
@customElement("ak-user-settings-source-plex")
export class SourceSettingsPlex extends BaseUserSettings {
@property()
title!: string;
render(): TemplateResult {
return html`<div class="pf-c-card">
<div class="pf-c-card__title">${t`Source ${this.title}`}</div>
<div class="pf-c-card__body">${this.renderInner()}</div>
</div>`;
}
renderInner(): TemplateResult {
return html`${until(
new SourcesApi(DEFAULT_CONFIG)
.sourcesUserConnectionsPlexList({
sourceSlug: this.objectId,
})
.then((connection) => {
if (connection.results.length > 0) {
return html`<p>${t`Connected.`}</p>
<button
class="pf-c-button pf-m-danger"
@click=${() => {
return new SourcesApi(
DEFAULT_CONFIG,
).sourcesUserConnectionsPlexDestroy({
id: connection.results[0].pk || 0,
});
}}
>
${t`Disconnect`}
</button>`;
}
return html`<p>${t`Not connected.`}</p>`;
}),
)}`;
}
}

View File

@ -12,9 +12,9 @@ This installation method is for test-setups and small-scale productive setups.
## Preparation
Download the latest `docker-compose.yml` from [here](https://raw.githubusercontent.com/goauthentik/authentik/version/2021.7.3/docker-compose.yml). Place it in a directory of your choice.
Download the latest `docker-compose.yml` from [here](https://raw.githubusercontent.com/goauthentik/authentik/version/2021.8.1-rc1/docker-compose.yml). Place it in a directory of your choice.
To optionally deploy a different version run `echo AUTHENTIK_TAG=2021.7.3 >> .env`
To optionally deploy a different version run `echo AUTHENTIK_TAG=2021.8.1-rc1 >> .env`
If this is a fresh authentik install run the following commands to generate a password:
@ -92,10 +92,10 @@ The docker-compose project contains the following containers:
- worker
This container executes backgorund tasks, everything you can see on the *System Tasks* page in the frontend.
This container executes background tasks, everything you can see on the *System Tasks* page in the frontend.
- redis & postgresql
Cache and database respectively.
Additionally, if you've enabled GeoIP, there is a container running which regularly updates the GeoIP database.
Additionally, if you've enabled GeoIP, there is a container running that regularly updates the GeoIP database.

View File

@ -45,11 +45,11 @@ Assumption is being made that you have successfully downloaded and activated the
In Wordpress, under _Settings_, Select _OpenID Connect Client_
::note
:::note
Only settings that have been modified from default have been listed.
:::
- Login Type: OpenID Connect Button of Login (This option display a button to login using OpenID as well as local WP login)
- Login Type: OpenID Connect Button on Login (This option display a button to login using OpenID as well as local WP login)
- Client ID: Client ID from step 1
- Client Secret: Client Secret from step 1
- OpenID Scope: `email profile openid`

View File

@ -11,7 +11,7 @@ version: "3.5"
services:
authentik_proxy:
image: ghcr.io/goauthentik/proxy:2021.7.3
image: ghcr.io/goauthentik/proxy:2021.8.1-rc1
ports:
- 4180:4180
- 4443:4443
@ -21,7 +21,7 @@ services:
AUTHENTIK_TOKEN: token-generated-by-authentik
# Or, for the LDAP Outpost
authentik_proxy:
image: ghcr.io/goauthentik/ldap:2021.7.3
image: ghcr.io/goauthentik/ldap:2021.8.1-rc1
ports:
- 389:3389
environment:

View File

@ -14,7 +14,7 @@ metadata:
app.kubernetes.io/instance: __OUTPOST_NAME__
app.kubernetes.io/managed-by: goauthentik.io
app.kubernetes.io/name: authentik-proxy
app.kubernetes.io/version: 2021.7.3
app.kubernetes.io/version: 2021.8.1-rc1
name: authentik-outpost-api
stringData:
authentik_host: "__AUTHENTIK_URL__"
@ -29,7 +29,7 @@ metadata:
app.kubernetes.io/instance: __OUTPOST_NAME__
app.kubernetes.io/managed-by: goauthentik.io
app.kubernetes.io/name: authentik-proxy
app.kubernetes.io/version: 2021.7.3
app.kubernetes.io/version: 2021.8.1-rc1
name: authentik-outpost
spec:
ports:
@ -54,7 +54,7 @@ metadata:
app.kubernetes.io/instance: __OUTPOST_NAME__
app.kubernetes.io/managed-by: goauthentik.io
app.kubernetes.io/name: authentik-proxy
app.kubernetes.io/version: 2021.7.3
app.kubernetes.io/version: 2021.8.1-rc1
name: authentik-outpost
spec:
selector:
@ -62,14 +62,14 @@ spec:
app.kubernetes.io/instance: __OUTPOST_NAME__
app.kubernetes.io/managed-by: goauthentik.io
app.kubernetes.io/name: authentik-proxy
app.kubernetes.io/version: 2021.7.3
app.kubernetes.io/version: 2021.8.1-rc1
template:
metadata:
labels:
app.kubernetes.io/instance: __OUTPOST_NAME__
app.kubernetes.io/managed-by: goauthentik.io
app.kubernetes.io/name: authentik-proxy
app.kubernetes.io/version: 2021.7.3
app.kubernetes.io/version: 2021.8.1-rc1
spec:
containers:
- env:
@ -88,7 +88,7 @@ spec:
secretKeyRef:
key: authentik_host_insecure
name: authentik-outpost-api
image: ghcr.io/goauthentik/proxy:2021.7.3
image: ghcr.io/goauthentik/proxy:2021.8.1-rc1
name: proxy
ports:
- containerPort: 4180
@ -110,7 +110,7 @@ metadata:
app.kubernetes.io/instance: __OUTPOST_NAME__
app.kubernetes.io/managed-by: goauthentik.io
app.kubernetes.io/name: authentik-proxy
app.kubernetes.io/version: 2021.7.3
app.kubernetes.io/version: 2021.8.1-rc1
name: authentik-outpost
spec:
rules:

View File

@ -14,7 +14,7 @@ Binding against the LDAP Server uses a flow in the background. This allows you t
You can configure under which base DN the information should be available. For this documentation we'll use the default of `DC=ldap,DC=goauthentik,DC=io`.
Users are available under `ou=users,<base DN>` and groups under `ou=groups,<base DN>`.
Users are available under `ou=users,<base DN>` and groups under `ou=groups,<base DN>`. To aid compatibility, each user belongs to its own "virtual" group, as is standard on most Unix-like systems. This group does not exist in the authentik database, and is generated on the fly. These virtual groups are under the `ou=virtual-groups,<base DN>` DN.
You can bind using the DN `cn=<username>,ou=users,<base DN>`, or using the following ldapsearch command for example:

View File

@ -23,7 +23,9 @@ slug: "2021.8"
- core: allow changing of groups a user is in from user api
- flows: fix unhandled error in stage execution not being logged as SYSTEM_EXCEPTION event
- lifecycle: decrease default worker count on compose
- outpost/ldap: Performance improvements, support for (member=) lookup
- providers/proxy: don't create ingress when no hosts are defined
- sources/plex: add API to get user connections
- web: add API Drawer
- web/admin: add UI to copy invitation link
- web/admin: allow modification of users groups from user view

View File

@ -174,6 +174,7 @@ module.exports = {
type: "category",
label: "Release Notes",
items: [
"releases/v2021.8",
"releases/v2021.7",
"releases/v2021.6",
"releases/v2021.5",