diff --git a/authentik/providers/ldap/api.py b/authentik/providers/ldap/api.py index 3a535be810..232a239f38 100644 --- a/authentik/providers/ldap/api.py +++ b/authentik/providers/ldap/api.py @@ -2,15 +2,25 @@ from django.db.models import QuerySet from django.db.models.query import Q +from django.shortcuts import get_object_or_404 from django_filters.filters import BooleanFilter from django_filters.filterset import FilterSet -from rest_framework.fields import CharField, ListField, SerializerMethodField +from drf_spectacular.types import OpenApiTypes +from drf_spectacular.utils import OpenApiParameter, extend_schema +from rest_framework.decorators import action +from rest_framework.fields import BooleanField, CharField, ListField, SerializerMethodField from rest_framework.mixins import ListModelMixin +from rest_framework.request import Request +from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet, ModelViewSet from authentik.core.api.providers import ProviderSerializer from authentik.core.api.used_by import UsedByMixin -from authentik.core.api.utils import ModelSerializer +from authentik.core.api.utils import ModelSerializer, PassiveSerializer +from authentik.core.models import Application +from authentik.policies.api.exec import PolicyTestResultSerializer +from authentik.policies.engine import PolicyEngine +from authentik.policies.types import PolicyResult from authentik.providers.ldap.models import LDAPProvider @@ -23,7 +33,6 @@ class LDAPProviderSerializer(ProviderSerializer): model = LDAPProvider fields = ProviderSerializer.Meta.fields + [ "base_dn", - "search_group", "certificate", "tls_server_name", "uid_start_number", @@ -55,8 +64,6 @@ class LDAPProviderFilter(FilterSet): "name": ["iexact"], "authorization_flow__slug": ["iexact"], "base_dn": ["iexact"], - "search_group__group_uuid": ["iexact"], - "search_group__name": ["iexact"], "certificate__kp_uuid": ["iexact"], "certificate__name": ["iexact"], "tls_server_name": ["iexact"], @@ -95,7 +102,6 @@ class LDAPOutpostConfigSerializer(ModelSerializer): "base_dn", "bind_flow_slug", "application_slug", - "search_group", "certificate", "tls_server_name", "uid_start_number", @@ -116,3 +122,33 @@ class LDAPOutpostConfigViewSet(ListModelMixin, GenericViewSet): ordering = ["name"] search_fields = ["name"] filterset_fields = ["name"] + + class LDAPCheckAccessSerializer(PassiveSerializer): + has_search_permission = BooleanField(required=False) + access = PolicyTestResultSerializer() + + @extend_schema( + request=None, + parameters=[OpenApiParameter("app_slug", OpenApiTypes.STR)], + responses={ + 200: LDAPCheckAccessSerializer(), + }, + operation_id="outposts_ldap_access_check", + ) + @action(detail=True) + def check_access(self, request: Request, pk) -> Response: + """Check access to a single application by slug""" + provider = get_object_or_404(LDAPProvider, pk=pk) + application = get_object_or_404(Application, slug=request.query_params["app_slug"]) + engine = PolicyEngine(application, request.user, request) + engine.use_cache = False + engine.build() + result = engine.result + access_response = PolicyResult(result.passing) + response = self.LDAPCheckAccessSerializer( + instance={ + "has_search_permission": request.user.has_perm("search_full_directory", provider), + "access": access_response, + } + ) + return Response(response.data) diff --git a/authentik/providers/ldap/migrations/0004_alter_ldapprovider_options_and_more.py b/authentik/providers/ldap/migrations/0004_alter_ldapprovider_options_and_more.py new file mode 100644 index 0000000000..54d632b793 --- /dev/null +++ b/authentik/providers/ldap/migrations/0004_alter_ldapprovider_options_and_more.py @@ -0,0 +1,52 @@ +# Generated by Django 5.0.7 on 2024-07-25 14:59 +from django.apps.registry import Apps + +from django.db.backends.base.schema import BaseDatabaseSchemaEditor + +from django.db import migrations +from django.contrib.auth.management import create_permissions + + +def migrate_search_group(apps: Apps, schema_editor: BaseDatabaseSchemaEditor): + from guardian.shortcuts import assign_perm + from authentik.core.models import User + from django.apps import apps as real_apps + + db_alias = schema_editor.connection.alias + + # Permissions are only created _after_ migrations are run + # - https://github.com/django/django/blob/43cdfa8b20e567a801b7d0a09ec67ddd062d5ea4/django/contrib/auth/apps.py#L19 + # - https://stackoverflow.com/a/72029063/1870445 + create_permissions(real_apps.get_app_config("authentik_providers_ldap"), using=db_alias) + + LDAPProvider = apps.get_model("authentik_providers_ldap", "ldapprovider") + + for provider in LDAPProvider.objects.using(db_alias).all(): + for user_pk in ( + provider.search_group.users.using(db_alias).all().values_list("pk", flat=True) + ): + # We need the correct user model instance to assign the permission + assign_perm("search_full_directory", User.objects.get(pk=user_pk), provider) + + +class Migration(migrations.Migration): + + dependencies = [ + ("authentik_providers_ldap", "0003_ldapprovider_mfa_support_and_more"), + ] + + operations = [ + migrations.AlterModelOptions( + name="ldapprovider", + options={ + "permissions": [("search_full_directory", "Search full LDAP directory")], + "verbose_name": "LDAP Provider", + "verbose_name_plural": "LDAP Providers", + }, + ), + migrations.RunPython(migrate_search_group), + migrations.RemoveField( + model_name="ldapprovider", + name="search_group", + ), + ] diff --git a/authentik/providers/ldap/models.py b/authentik/providers/ldap/models.py index 3288b71498..e6cd97b0de 100644 --- a/authentik/providers/ldap/models.py +++ b/authentik/providers/ldap/models.py @@ -7,7 +7,7 @@ from django.templatetags.static import static from django.utils.translation import gettext_lazy as _ from rest_framework.serializers import Serializer -from authentik.core.models import BackchannelProvider, Group +from authentik.core.models import BackchannelProvider from authentik.crypto.models import CertificateKeyPair from authentik.outposts.models import OutpostModel @@ -27,17 +27,6 @@ class LDAPProvider(OutpostModel, BackchannelProvider): help_text=_("DN under which objects are accessible."), ) - search_group = models.ForeignKey( - Group, - null=True, - default=None, - on_delete=models.SET_DEFAULT, - help_text=_( - "Users in this group can do search queries. " - "If not set, every user can execute search queries." - ), - ) - tls_server_name = models.TextField( default="", blank=True, @@ -113,3 +102,6 @@ class LDAPProvider(OutpostModel, BackchannelProvider): class Meta: verbose_name = _("LDAP Provider") verbose_name_plural = _("LDAP Providers") + permissions = [ + ("search_full_directory", _("Search full LDAP directory")), + ] diff --git a/authentik/providers/radius/api/providers.py b/authentik/providers/radius/api/providers.py index 67a512bc26..0ab9d04a10 100644 --- a/authentik/providers/radius/api/providers.py +++ b/authentik/providers/radius/api/providers.py @@ -154,6 +154,7 @@ class RadiusOutpostConfigViewSet(ListModelMixin, GenericViewSet): responses={ 200: RadiusCheckAccessSerializer(), }, + operation_id="outposts_radius_access_check", ) @action(detail=True) def check_access(self, request: Request, pk) -> Response: diff --git a/authentik/stages/authenticator_duo/migrations/0006_duodevice_created_duodevice_last_updated_and_more.py b/authentik/stages/authenticator_duo/migrations/0006_duodevice_created_duodevice_last_updated_and_more.py index 37ba2a730d..c7b032f6e0 100644 --- a/authentik/stages/authenticator_duo/migrations/0006_duodevice_created_duodevice_last_updated_and_more.py +++ b/authentik/stages/authenticator_duo/migrations/0006_duodevice_created_duodevice_last_updated_and_more.py @@ -14,7 +14,9 @@ class Migration(migrations.Migration): migrations.AddField( model_name="duodevice", name="created", - field=models.DateTimeField(auto_now_add=True, default=datetime.datetime(1, 1, 1, 0, 0)), + field=models.DateTimeField( + auto_now_add=True, default=datetime.datetime(1, 1, 1, 0, 0, tzinfo=datetime.UTC) + ), preserve_default=False, ), migrations.AddField( diff --git a/authentik/stages/authenticator_sms/migrations/0007_smsdevice_created_smsdevice_last_updated_and_more.py b/authentik/stages/authenticator_sms/migrations/0007_smsdevice_created_smsdevice_last_updated_and_more.py index 440258dac6..0621cdc9c6 100644 --- a/authentik/stages/authenticator_sms/migrations/0007_smsdevice_created_smsdevice_last_updated_and_more.py +++ b/authentik/stages/authenticator_sms/migrations/0007_smsdevice_created_smsdevice_last_updated_and_more.py @@ -14,7 +14,9 @@ class Migration(migrations.Migration): migrations.AddField( model_name="smsdevice", name="created", - field=models.DateTimeField(auto_now_add=True, default=datetime.datetime(1, 1, 1, 0, 0)), + field=models.DateTimeField( + auto_now_add=True, default=datetime.datetime(1, 1, 1, 0, 0, tzinfo=datetime.UTC) + ), preserve_default=False, ), migrations.AddField( diff --git a/authentik/stages/authenticator_static/migrations/0010_staticdevice_created_staticdevice_last_updated_and_more.py b/authentik/stages/authenticator_static/migrations/0010_staticdevice_created_staticdevice_last_updated_and_more.py index 3ba394ec21..7a38f5fe0d 100644 --- a/authentik/stages/authenticator_static/migrations/0010_staticdevice_created_staticdevice_last_updated_and_more.py +++ b/authentik/stages/authenticator_static/migrations/0010_staticdevice_created_staticdevice_last_updated_and_more.py @@ -14,7 +14,9 @@ class Migration(migrations.Migration): migrations.AddField( model_name="staticdevice", name="created", - field=models.DateTimeField(auto_now_add=True, default=datetime.datetime(1, 1, 1, 0, 0)), + field=models.DateTimeField( + auto_now_add=True, default=datetime.datetime(1, 1, 1, 0, 0, tzinfo=datetime.UTC) + ), preserve_default=False, ), migrations.AddField( diff --git a/authentik/stages/authenticator_totp/migrations/0011_totpdevice_created_totpdevice_last_updated_and_more.py b/authentik/stages/authenticator_totp/migrations/0011_totpdevice_created_totpdevice_last_updated_and_more.py index c4cfb933b5..ed5ea528d7 100644 --- a/authentik/stages/authenticator_totp/migrations/0011_totpdevice_created_totpdevice_last_updated_and_more.py +++ b/authentik/stages/authenticator_totp/migrations/0011_totpdevice_created_totpdevice_last_updated_and_more.py @@ -14,7 +14,9 @@ class Migration(migrations.Migration): migrations.AddField( model_name="totpdevice", name="created", - field=models.DateTimeField(auto_now_add=True, default=datetime.datetime(1, 1, 1, 0, 0)), + field=models.DateTimeField( + auto_now_add=True, default=datetime.datetime(1, 1, 1, 0, 0, tzinfo=datetime.UTC) + ), preserve_default=False, ), migrations.AddField( diff --git a/authentik/stages/authenticator_webauthn/migrations/0012_webauthndevice_created_webauthndevice_last_updated_and_more.py b/authentik/stages/authenticator_webauthn/migrations/0012_webauthndevice_created_webauthndevice_last_updated_and_more.py index 7e82a77cc0..e0c74030ad 100644 --- a/authentik/stages/authenticator_webauthn/migrations/0012_webauthndevice_created_webauthndevice_last_updated_and_more.py +++ b/authentik/stages/authenticator_webauthn/migrations/0012_webauthndevice_created_webauthndevice_last_updated_and_more.py @@ -14,7 +14,9 @@ class Migration(migrations.Migration): migrations.AddField( model_name="webauthndevice", name="created", - field=models.DateTimeField(auto_now_add=True, default=datetime.datetime(1, 1, 1, 0, 0)), + field=models.DateTimeField( + auto_now_add=True, default=datetime.datetime(1, 1, 1, 0, 0, tzinfo=datetime.UTC) + ), preserve_default=False, ), migrations.AddField( diff --git a/blueprints/schema.json b/blueprints/schema.json index 3d8b7436ae..f63ce69963 100644 --- a/blueprints/schema.json +++ b/blueprints/schema.json @@ -5131,12 +5131,6 @@ "title": "Base dn", "description": "DN under which objects are accessible." }, - "search_group": { - "type": "string", - "format": "uuid", - "title": "Search group", - "description": "Users in this group can do search queries. If not set, every user can execute search queries." - }, "certificate": { "type": "string", "format": "uuid", diff --git a/internal/outpost/flow/executor.go b/internal/outpost/flow/executor.go index 6cbad86f7e..162aafb7e6 100644 --- a/internal/outpost/flow/executor.go +++ b/internal/outpost/flow/executor.go @@ -120,21 +120,6 @@ func (fe *FlowExecutor) DelegateClientIP(a string) { fe.api.GetConfig().AddDefaultHeader(HeaderAuthentikRemoteIP, fe.cip) } -func (fe *FlowExecutor) CheckApplicationAccess(appSlug string) (bool, error) { - acsp := sentry.StartSpan(fe.Context, "authentik.outposts.flow_executor.check_access") - defer acsp.Finish() - p, _, err := fe.api.CoreApi.CoreApplicationsCheckAccessRetrieve(acsp.Context(), appSlug).Execute() - if err != nil { - return false, fmt.Errorf("failed to check access: %w", err) - } - if !p.Passing { - fe.log.Info("Access denied for user") - return false, nil - } - fe.log.Debug("User has access") - return true, nil -} - func (fe *FlowExecutor) getAnswer(stage StageComponent) string { if v, o := fe.Answers[stage]; o { return v diff --git a/internal/outpost/ldap/bind/direct/bind.go b/internal/outpost/ldap/bind/direct/bind.go index b7850e853d..e095d5715e 100644 --- a/internal/outpost/ldap/bind/direct/bind.go +++ b/internal/outpost/ldap/bind/direct/bind.go @@ -58,8 +58,10 @@ func (db *DirectBinder) Bind(username string, req *bind.Request) (ldap.LDAPResul return ldap.LDAPResultInvalidCredentials, nil } - access, err := fe.CheckApplicationAccess(db.si.GetAppSlug()) - if !access { + access, _, err := fe.ApiClient().OutpostsApi.OutpostsLdapAccessCheck( + req.Context(), db.si.GetProviderID(), + ).AppSlug(db.si.GetAppSlug()).Execute() + if !access.Access.Passing { req.Log().Info("Access denied for user") metrics.RequestsRejected.With(prometheus.Labels{ "outpost_name": db.si.GetOutpostName(), @@ -93,12 +95,11 @@ func (db *DirectBinder) Bind(username string, req *bind.Request) (ldap.LDAPResul req.Log().WithError(err).Warning("failed to get user info") return ldap.LDAPResultOperationsError, nil } - cs := db.SearchAccessCheck(userInfo.User) flags.UserPk = userInfo.User.Pk - flags.CanSearch = cs != nil + flags.CanSearch = access.HasSearchPermission != nil db.si.SetFlags(req.BindDN, &flags) if flags.CanSearch { - req.Log().WithField("group", cs).Info("Allowed access to search") + req.Log().Debug("Allowed access to search") } uisp.Finish() return ldap.LDAPResultSuccess, nil diff --git a/internal/outpost/ldap/bind/direct/direct.go b/internal/outpost/ldap/bind/direct/direct.go index cd43498508..e678df4bba 100644 --- a/internal/outpost/ldap/bind/direct/direct.go +++ b/internal/outpost/ldap/bind/direct/direct.go @@ -7,7 +7,6 @@ import ( goldap "github.com/go-ldap/ldap/v3" log "github.com/sirupsen/logrus" - "goauthentik.io/api/v3" "goauthentik.io/internal/outpost/flow" "goauthentik.io/internal/outpost/ldap/server" "goauthentik.io/internal/outpost/ldap/utils" @@ -47,22 +46,6 @@ func (db *DirectBinder) GetUsername(dn string) (string, error) { return "", errors.New("failed to find cn") } -// SearchAccessCheck Check if the current user is allowed to search -func (db *DirectBinder) SearchAccessCheck(user api.UserSelf) *string { - for _, group := range user.Groups { - for _, allowedGroup := range db.si.GetSearchAllowedGroups() { - if allowedGroup == nil { - continue - } - db.log.WithField("userGroup", group.Pk).WithField("allowedGroup", allowedGroup).Trace("Checking search access") - if group.Pk == allowedGroup.String() { - return &group.Name - } - } - } - return nil -} - func (db *DirectBinder) TimerFlowCacheExpiry(ctx context.Context) { fe := flow.NewFlowExecutor(ctx, db.si.GetAuthenticationFlowSlug(), db.si.GetAPIClient().GetConfig(), log.Fields{}) fe.Params.Add("goauthentik.io/outpost/ldap", "true") diff --git a/internal/outpost/ldap/instance.go b/internal/outpost/ldap/instance.go index fe6ef7b71d..0b2d5ba38d 100644 --- a/internal/outpost/ldap/instance.go +++ b/internal/outpost/ldap/instance.go @@ -5,7 +5,6 @@ import ( "strings" "sync" - "github.com/go-openapi/strfmt" log "github.com/sirupsen/logrus" "goauthentik.io/api/v3" @@ -31,14 +30,13 @@ type ProviderInstance struct { s *LDAPServer log *log.Entry - tlsServerName *string - cert *tls.Certificate - certUUID string - outpostName string - outpostPk int32 - searchAllowedGroups []*strfmt.UUID - boundUsersMutex *sync.RWMutex - boundUsers map[string]*flags.UserFlags + tlsServerName *string + cert *tls.Certificate + certUUID string + outpostName string + providerPk int32 + boundUsersMutex *sync.RWMutex + boundUsers map[string]*flags.UserFlags uidStartNumber int32 gidStartNumber int32 @@ -105,8 +103,8 @@ func (pi *ProviderInstance) GetInvalidationFlowSlug() string { return pi.invalidationFlowSlug } -func (pi *ProviderInstance) GetSearchAllowedGroups() []*strfmt.UUID { - return pi.searchAllowedGroups +func (pi *ProviderInstance) GetProviderID() int32 { + return pi.providerPk } func (pi *ProviderInstance) GetNeededObjects(scope int, baseDN string, filterOC string) (bool, bool) { diff --git a/internal/outpost/ldap/refresh.go b/internal/outpost/ldap/refresh.go index 9f5dbc1496..7a336c621a 100644 --- a/internal/outpost/ldap/refresh.go +++ b/internal/outpost/ldap/refresh.go @@ -7,7 +7,6 @@ import ( "strings" "sync" - "github.com/go-openapi/strfmt" log "github.com/sirupsen/logrus" "goauthentik.io/api/v3" @@ -23,7 +22,7 @@ import ( func (ls *LDAPServer) getCurrentProvider(pk int32) *ProviderInstance { for _, p := range ls.providers { - if p.outpostPk == pk { + if p.providerPk == pk { return p } } @@ -77,7 +76,6 @@ func (ls *LDAPServer) Refresh() error { appSlug: provider.ApplicationSlug, authenticationFlowSlug: provider.BindFlowSlug, invalidationFlowSlug: invalidationFlow, - searchAllowedGroups: []*strfmt.UUID{(*strfmt.UUID)(provider.SearchGroup.Get())}, boundUsersMutex: usersMutex, boundUsers: users, s: ls, @@ -87,7 +85,7 @@ func (ls *LDAPServer) Refresh() error { gidStartNumber: provider.GetGidStartNumber(), mfaSupport: provider.GetMfaSupport(), outpostName: ls.ac.Outpost.Name, - outpostPk: provider.Pk, + providerPk: provider.Pk, } if kp := provider.Certificate.Get(); kp != nil { err := ls.cs.AddKeypair(*kp) diff --git a/internal/outpost/ldap/server/base.go b/internal/outpost/ldap/server/base.go index 2983e3afca..092959f8b8 100644 --- a/internal/outpost/ldap/server/base.go +++ b/internal/outpost/ldap/server/base.go @@ -2,7 +2,6 @@ package server import ( "beryju.io/ldap" - "github.com/go-openapi/strfmt" "goauthentik.io/api/v3" "goauthentik.io/internal/outpost/ldap/flags" @@ -15,7 +14,7 @@ type LDAPServerInstance interface { GetAuthenticationFlowSlug() string GetInvalidationFlowSlug() string GetAppSlug() string - GetSearchAllowedGroups() []*strfmt.UUID + GetProviderID() int32 UserEntry(u api.User) *ldap.Entry diff --git a/internal/outpost/radius/handle_access_request.go b/internal/outpost/radius/handle_access_request.go index 58f880cd78..308279cb4b 100644 --- a/internal/outpost/radius/handle_access_request.go +++ b/internal/outpost/radius/handle_access_request.go @@ -45,7 +45,9 @@ func (rs *RadiusServer) Handle_AccessRequest(w radius.ResponseWriter, r *RadiusR _ = w.Write(r.Response(radius.CodeAccessReject)) return } - access, _, err := fe.ApiClient().OutpostsApi.OutpostsRadiusCheckAccessRetrieve(r.Context(), r.pi.providerId).AppSlug(r.pi.appSlug).Execute() + access, _, err := fe.ApiClient().OutpostsApi.OutpostsRadiusAccessCheck( + r.Context(), r.pi.providerId, + ).AppSlug(r.pi.appSlug).Execute() if err != nil { r.Log().WithField("username", username).WithError(err).Warning("failed to check access") _ = w.Write(r.Response(radius.CodeAccessReject)) diff --git a/schema.yml b/schema.yml index bb6df8dd62..bf42d1cc2b 100644 --- a/schema.yml +++ b/schema.yml @@ -9641,6 +9641,44 @@ paths: schema: $ref: '#/components/schemas/GenericError' description: '' + /outposts/ldap/{id}/check_access/: + get: + operationId: outposts_ldap_access_check + description: Check access to a single application by slug + parameters: + - in: query + name: app_slug + schema: + type: string + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this LDAP Provider. + required: true + tags: + - outposts + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/LDAPCheckAccess' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' /outposts/proxy/: get: operationId: outposts_proxy_list @@ -9755,7 +9793,7 @@ paths: description: '' /outposts/radius/{id}/check_access/: get: - operationId: outposts_radius_check_access_retrieve + operationId: outposts_radius_access_check description: Check access to a single application by slug parameters: - in: query @@ -18342,15 +18380,6 @@ paths: description: A search term. schema: type: string - - in: query - name: search_group__group_uuid__iexact - schema: - type: string - format: uuid - - in: query - name: search_group__name__iexact - schema: - type: string - in: query name: tls_server_name__iexact schema: @@ -40705,6 +40734,16 @@ components: - direct - cached type: string + LDAPCheckAccess: + type: object + description: Base serializer class which doesn't implement create/update methods + properties: + has_search_permission: + type: boolean + access: + $ref: '#/components/schemas/PolicyTestResult' + required: + - access LDAPDebug: type: object properties: @@ -40749,12 +40788,6 @@ components: type: string description: Prioritise backchannel slug over direct application slug readOnly: true - search_group: - type: string - format: uuid - nullable: true - description: Users in this group can do search queries. If not set, every - user can execute search queries. certificate: type: string format: uuid @@ -40852,12 +40885,6 @@ components: base_dn: type: string description: DN under which objects are accessible. - search_group: - type: string - format: uuid - nullable: true - description: Users in this group can do search queries. If not set, every - user can execute search queries. certificate: type: string format: uuid @@ -40934,12 +40961,6 @@ components: type: string minLength: 1 description: DN under which objects are accessible. - search_group: - type: string - format: uuid - nullable: true - description: Users in this group can do search queries. If not set, every - user can execute search queries. certificate: type: string format: uuid @@ -45706,12 +45727,6 @@ components: type: string minLength: 1 description: DN under which objects are accessible. - search_group: - type: string - format: uuid - nullable: true - description: Users in this group can do search queries. If not set, every - user can execute search queries. certificate: type: string format: uuid diff --git a/tests/e2e/test_provider_ldap.py b/tests/e2e/test_provider_ldap.py index a750d17782..af75a734f5 100644 --- a/tests/e2e/test_provider_ldap.py +++ b/tests/e2e/test_provider_ldap.py @@ -5,6 +5,7 @@ from time import sleep from docker.client import DockerClient, from_env from docker.models.containers import Container +from guardian.shortcuts import assign_perm from ldap3 import ALL, ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES, SUBTREE, Connection, Server from ldap3.core.exceptions import LDAPInvalidCredentialsResult @@ -54,9 +55,9 @@ class TestProviderLDAP(SeleniumTestCase): ldap: LDAPProvider = LDAPProvider.objects.create( name=generate_id(), authorization_flow=Flow.objects.get(slug="default-authentication-flow"), - search_group=self.user.ak_groups.first(), search_mode=APIAccessMode.CACHED, ) + assign_perm("search_full_directory", self.user, ldap) # we need to create an application to actually access the ldap Application.objects.create(name=generate_id(), slug=generate_id(), provider=ldap) outpost: Outpost = Outpost.objects.create( diff --git a/web/src/admin/applications/wizard/methods/ldap/LDAPOptionsAndHelp.ts b/web/src/admin/applications/wizard/methods/ldap/LDAPOptionsAndHelp.ts index 5b2f1f4830..5265abf049 100644 --- a/web/src/admin/applications/wizard/methods/ldap/LDAPOptionsAndHelp.ts +++ b/web/src/admin/applications/wizard/methods/ldap/LDAPOptionsAndHelp.ts @@ -43,10 +43,6 @@ export const mfaSupportHelp = msg( "When enabled, code-based multi-factor authentication can be used by appending a semicolon and the TOTP code to the password. This should only be enabled if all users that will bind to this provider have a TOTP device configured, as otherwise a password may incorrectly be rejected if it contains a semicolon.", ); -export const groupHelp = msg( - "The start for gidNumbers, this number is added to a number generated from the group.Pk to make sure that the numbers aren't too low for POSIX groups. Default is 4000 to ensure that we don't collide with local groups or users primary groups gidNumber", -); - export const cryptoCertificateHelp = msg( "The certificate for the above configured Base DN. As a fallback, the provider uses a self-signed certificate.", ); diff --git a/web/src/admin/applications/wizard/methods/ldap/ak-application-wizard-authentication-by-ldap.ts b/web/src/admin/applications/wizard/methods/ldap/ak-application-wizard-authentication-by-ldap.ts index d9b0870eee..c34f797684 100644 --- a/web/src/admin/applications/wizard/methods/ldap/ak-application-wizard-authentication-by-ldap.ts +++ b/web/src/admin/applications/wizard/methods/ldap/ak-application-wizard-authentication-by-ldap.ts @@ -1,5 +1,4 @@ import "@goauthentik/admin/applications/wizard/ak-wizard-title"; -import "@goauthentik/admin/common/ak-core-group-search"; import "@goauthentik/admin/common/ak-crypto-certificate-search"; import "@goauthentik/admin/common/ak-flow-search/ak-branded-flow-search"; import { first } from "@goauthentik/common/utils"; @@ -24,7 +23,6 @@ import { bindModeOptions, cryptoCertificateHelp, gidStartNumberHelp, - groupHelp, mfaSupportHelp, searchModeOptions, tlsServerNameHelp, @@ -65,18 +63,6 @@ export class ApplicationWizardApplicationDetails extends WithBrandConfig(BasePro
-${groupHelp}
-${msg( "Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application.", )}
-${msg("Flow used for users to authenticate.")}
-- ${msg( - "Users in the selected group can do search queries. If no group is selected, no LDAP Searches are allowed.", - )} -
-