diff --git a/authentik/flows/tests/test_inspector.py b/authentik/flows/tests/test_inspector.py index 49ba593566..a12054fd37 100644 --- a/authentik/flows/tests/test_inspector.py +++ b/authentik/flows/tests/test_inspector.py @@ -53,6 +53,7 @@ class TestFlowInspector(APITestCase): "title": flow.title, "layout": "stacked", }, + "flow_designation": "authentication", "type": ChallengeTypes.NATIVE.value, "password_fields": False, "primary_action": "Log in", diff --git a/authentik/sources/ldap/api.py b/authentik/sources/ldap/api.py index dc45523380..8a672a6aa7 100644 --- a/authentik/sources/ldap/api.py +++ b/authentik/sources/ldap/api.py @@ -77,6 +77,7 @@ class LDAPSourceSerializer(SourceSerializer): "group_object_filter", "group_membership_field", "object_uniqueness_field", + "password_login_update_internal_password", "sync_users", "sync_users_password", "sync_groups", @@ -118,6 +119,7 @@ class LDAPSourceViewSet(UsedByMixin, ModelViewSet): "group_object_filter", "group_membership_field", "object_uniqueness_field", + "password_login_update_internal_password", "sync_users", "sync_users_password", "sync_groups", diff --git a/authentik/sources/ldap/auth.py b/authentik/sources/ldap/auth.py index a271dac5a5..37321ea05f 100644 --- a/authentik/sources/ldap/auth.py +++ b/authentik/sources/ldap/auth.py @@ -41,10 +41,11 @@ class LDAPBackend(InbuiltBackend): # or has a password, but couldn't be authenticated by ModelBackend. # This means we check with a bind to see if the LDAP password has changed if self.auth_user_by_bind(source, user, password): - # Password given successfully binds to LDAP, so we save it in our Database - LOGGER.debug("Updating user's password in DB", user=user) - user.set_password(password, signal=False) - user.save() + if source.password_login_update_internal_password: + # Password given successfully binds to LDAP, so we save it in our Database + LOGGER.debug("Updating user's password in DB", user=user) + user.set_password(password, signal=False) + user.save() return user # Password doesn't match LOGGER.debug("Failed to bind, password invalid") diff --git a/authentik/sources/ldap/migrations/0004_ldapsource_password_login_update_internal_password.py b/authentik/sources/ldap/migrations/0004_ldapsource_password_login_update_internal_password.py new file mode 100644 index 0000000000..cacbe62684 --- /dev/null +++ b/authentik/sources/ldap/migrations/0004_ldapsource_password_login_update_internal_password.py @@ -0,0 +1,29 @@ +# Generated by Django 5.0.1 on 2024-01-31 18:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("authentik_sources_ldap", "0003_ldapsource_client_certificate_ldapsource_sni_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="ldapsource", + name="password_login_update_internal_password", + field=models.BooleanField( + default=True, + help_text="Update internal authentik password when login succeeds with LDAP", + ), + ), + migrations.AlterField( + model_name="ldapsource", + name="password_login_update_internal_password", + field=models.BooleanField( + default=False, + help_text="Update internal authentik password when login succeeds with LDAP", + ), + ), + ] diff --git a/authentik/sources/ldap/models.py b/authentik/sources/ldap/models.py index 074e49b5f4..06ced2f9fa 100644 --- a/authentik/sources/ldap/models.py +++ b/authentik/sources/ldap/models.py @@ -98,6 +98,11 @@ class LDAPSource(Source): help_text=_("Property mappings used for group creation/updating."), ) + password_login_update_internal_password = models.BooleanField( + default=False, + help_text=_("Update internal authentik password when login succeeds with LDAP"), + ) + sync_users = models.BooleanField(default=True) sync_users_password = models.BooleanField( default=True, diff --git a/authentik/stages/authenticator_validate/challenge.py b/authentik/stages/authenticator_validate/challenge.py index a762e44c17..ce0dea1a16 100644 --- a/authentik/stages/authenticator_validate/challenge.py +++ b/authentik/stages/authenticator_validate/challenge.py @@ -120,7 +120,9 @@ def validate_challenge_code(code: str, stage_view: StageView, user: User) -> Dev stage=stage_view.executor.current_stage, device_class=DeviceClasses.TOTP.value, ) - raise ValidationError(_("Invalid Token")) + raise ValidationError( + _("Invalid Token. Please ensure the time on your device is accurate and try again.") + ) return device diff --git a/authentik/stages/identification/stage.py b/authentik/stages/identification/stage.py index 3799991d9f..8be41825d5 100644 --- a/authentik/stages/identification/stage.py +++ b/authentik/stages/identification/stage.py @@ -10,7 +10,7 @@ from django.db.models import Q from django.http import HttpResponse from django.utils.translation import gettext as _ from drf_spectacular.utils import PolymorphicProxySerializer, extend_schema_field -from rest_framework.fields import BooleanField, CharField, DictField, ListField +from rest_framework.fields import BooleanField, CharField, ChoiceField, DictField, ListField from rest_framework.serializers import ValidationError from sentry_sdk.hub import Hub @@ -66,6 +66,7 @@ class IdentificationChallenge(Challenge): user_fields = ListField(child=CharField(), allow_empty=True, allow_null=True) password_fields = BooleanField() application_pre = CharField(required=False) + flow_designation = ChoiceField(FlowDesignation.choices) enroll_url = CharField(required=False) recovery_url = CharField(required=False) @@ -194,11 +195,12 @@ class IdentificationStageView(ChallengeStageView): challenge = IdentificationChallenge( data={ "type": ChallengeTypes.NATIVE.value, - "primary_action": self.get_primary_action(), "component": "ak-stage-identification", + "primary_action": self.get_primary_action(), "user_fields": current_stage.user_fields, "password_fields": bool(current_stage.password_stage), "show_source_labels": current_stage.show_source_labels, + "flow_designation": self.executor.flow.designation, } ) # If the user has been redirected to us whilst trying to access an diff --git a/blueprints/schema.json b/blueprints/schema.json index da1082c7aa..942f37a039 100644 --- a/blueprints/schema.json +++ b/blueprints/schema.json @@ -4347,6 +4347,11 @@ "title": "Object uniqueness field", "description": "Field which contains a unique Identifier." }, + "password_login_update_internal_password": { + "type": "boolean", + "title": "Password login update internal password", + "description": "Update internal authentik password when login succeeds with LDAP" + }, "sync_users": { "type": "boolean", "title": "Sync users" diff --git a/lifecycle/migrate.py b/lifecycle/migrate.py index 6dceb6b007..1dac197119 100755 --- a/lifecycle/migrate.py +++ b/lifecycle/migrate.py @@ -64,6 +64,7 @@ def release_lock(cursor: Cursor): """Release database lock""" if not LOCKED: return + LOGGER.info("releasing database lock") cursor.execute("SELECT pg_advisory_unlock(%s)", (ADV_LOCK_UID,)) diff --git a/lifecycle/system_migrations/template_schema.py b/lifecycle/system_migrations/template_schema.py new file mode 100644 index 0000000000..9ab53c0605 --- /dev/null +++ b/lifecycle/system_migrations/template_schema.py @@ -0,0 +1,12 @@ +from lifecycle.migrate import BaseMigration + + +class Migration(BaseMigration): + def needs_migration(self) -> bool: + self.cur.execute( + "SELECT schema_name FROM information_schema.schemata WHERE schema_name = 'template';" + ) + return not bool(self.cur.rowcount) + + def run(self): + self.cur.execute("CREATE SCHEMA IF NOT EXISTS template; COMMIT;") diff --git a/poetry.lock b/poetry.lock index e063d4cee1..761a4c5216 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3351,13 +3351,13 @@ test = ["fixtures", "mock", "purl", "pytest", "requests-futures", "sphinx", "tes [[package]] name = "requests-oauthlib" -version = "1.4.0" +version = "2.0.0" description = "OAuthlib authentication support for Requests." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.4" files = [ - {file = "requests-oauthlib-1.4.0.tar.gz", hash = "sha256:acee623221e4a39abcbb919312c8ff04bd44e7e417087fb4bd5e2a2f53d5e79a"}, - {file = "requests_oauthlib-1.4.0-py2.py3-none-any.whl", hash = "sha256:7a3130d94a17520169e38db6c8d75f2c974643788465ecc2e4b36d288bf13033"}, + {file = "requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9"}, + {file = "requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36"}, ] [package.dependencies] @@ -3509,28 +3509,28 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.3.3" +version = "0.3.4" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.3.3-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:973a0e388b7bc2e9148c7f9be8b8c6ae7471b9be37e1cc732f8f44a6f6d7720d"}, - {file = "ruff-0.3.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:cfa60d23269d6e2031129b053fdb4e5a7b0637fc6c9c0586737b962b2f834493"}, - {file = "ruff-0.3.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1eca7ff7a47043cf6ce5c7f45f603b09121a7cc047447744b029d1b719278eb5"}, - {file = "ruff-0.3.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7d3f6762217c1da954de24b4a1a70515630d29f71e268ec5000afe81377642d"}, - {file = "ruff-0.3.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b24c19e8598916d9c6f5a5437671f55ee93c212a2c4c569605dc3842b6820386"}, - {file = "ruff-0.3.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5a6cbf216b69c7090f0fe4669501a27326c34e119068c1494f35aaf4cc683778"}, - {file = "ruff-0.3.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:352e95ead6964974b234e16ba8a66dad102ec7bf8ac064a23f95371d8b198aab"}, - {file = "ruff-0.3.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d6ab88c81c4040a817aa432484e838aaddf8bfd7ca70e4e615482757acb64f8"}, - {file = "ruff-0.3.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79bca3a03a759cc773fca69e0bdeac8abd1c13c31b798d5bb3c9da4a03144a9f"}, - {file = "ruff-0.3.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:2700a804d5336bcffe063fd789ca2c7b02b552d2e323a336700abb8ae9e6a3f8"}, - {file = "ruff-0.3.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fd66469f1a18fdb9d32e22b79f486223052ddf057dc56dea0caaf1a47bdfaf4e"}, - {file = "ruff-0.3.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:45817af234605525cdf6317005923bf532514e1ea3d9270acf61ca2440691376"}, - {file = "ruff-0.3.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:0da458989ce0159555ef224d5b7c24d3d2e4bf4c300b85467b08c3261c6bc6a8"}, - {file = "ruff-0.3.3-py3-none-win32.whl", hash = "sha256:f2831ec6a580a97f1ea82ea1eda0401c3cdf512cf2045fa3c85e8ef109e87de0"}, - {file = "ruff-0.3.3-py3-none-win_amd64.whl", hash = "sha256:be90bcae57c24d9f9d023b12d627e958eb55f595428bafcb7fec0791ad25ddfc"}, - {file = "ruff-0.3.3-py3-none-win_arm64.whl", hash = "sha256:0171aab5fecdc54383993389710a3d1227f2da124d76a2784a7098e818f92d61"}, - {file = "ruff-0.3.3.tar.gz", hash = "sha256:38671be06f57a2f8aba957d9f701ea889aa5736be806f18c0cd03d6ff0cbca8d"}, + {file = "ruff-0.3.4-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:60c870a7d46efcbc8385d27ec07fe534ac32f3b251e4fc44b3cbfd9e09609ef4"}, + {file = "ruff-0.3.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6fc14fa742e1d8f24910e1fff0bd5e26d395b0e0e04cc1b15c7c5e5fe5b4af91"}, + {file = "ruff-0.3.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3ee7880f653cc03749a3bfea720cf2a192e4f884925b0cf7eecce82f0ce5854"}, + {file = "ruff-0.3.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cf133dd744f2470b347f602452a88e70dadfbe0fcfb5fd46e093d55da65f82f7"}, + {file = "ruff-0.3.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f3860057590e810c7ffea75669bdc6927bfd91e29b4baa9258fd48b540a4365"}, + {file = "ruff-0.3.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:986f2377f7cf12efac1f515fc1a5b753c000ed1e0a6de96747cdf2da20a1b369"}, + {file = "ruff-0.3.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fd98e85869603e65f554fdc5cddf0712e352fe6e61d29d5a6fe087ec82b76c"}, + {file = "ruff-0.3.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64abeed785dad51801b423fa51840b1764b35d6c461ea8caef9cf9e5e5ab34d9"}, + {file = "ruff-0.3.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df52972138318bc7546d92348a1ee58449bc3f9eaf0db278906eb511889c4b50"}, + {file = "ruff-0.3.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:98e98300056445ba2cc27d0b325fd044dc17fcc38e4e4d2c7711585bd0a958ed"}, + {file = "ruff-0.3.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:519cf6a0ebed244dce1dc8aecd3dc99add7a2ee15bb68cf19588bb5bf58e0488"}, + {file = "ruff-0.3.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:bb0acfb921030d00070539c038cd24bb1df73a2981e9f55942514af8b17be94e"}, + {file = "ruff-0.3.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:cf187a7e7098233d0d0c71175375c5162f880126c4c716fa28a8ac418dcf3378"}, + {file = "ruff-0.3.4-py3-none-win32.whl", hash = "sha256:af27ac187c0a331e8ef91d84bf1c3c6a5dea97e912a7560ac0cef25c526a4102"}, + {file = "ruff-0.3.4-py3-none-win_amd64.whl", hash = "sha256:de0d5069b165e5a32b3c6ffbb81c350b1e3d3483347196ffdf86dc0ef9e37dd6"}, + {file = "ruff-0.3.4-py3-none-win_arm64.whl", hash = "sha256:6810563cc08ad0096b57c717bd78aeac888a1bfd38654d9113cb3dc4d3f74232"}, + {file = "ruff-0.3.4.tar.gz", hash = "sha256:f0f4484c6541a99862b693e13a151435a279b271cff20e37101116a21e2a1ad1"}, ] [[package]] diff --git a/schema.yml b/schema.yml index 6ac8eb9eb1..a14f542873 100644 --- a/schema.yml +++ b/schema.yml @@ -19926,6 +19926,10 @@ paths: description: Number of results to return per page. schema: type: integer + - in: query + name: password_login_update_internal_password + schema: + type: boolean - in: query name: peer_certificate schema: @@ -31782,8 +31786,7 @@ components: pk: type: string format: uuid - readOnly: true - title: Pbm uuid + title: Connection token uuid provider: type: integer provider_obj: @@ -31793,7 +31796,6 @@ components: endpoint: type: string format: uuid - readOnly: true endpoint_obj: allOf: - $ref: '#/components/schemas/Endpoint' @@ -31805,7 +31807,6 @@ components: required: - endpoint - endpoint_obj - - pk - provider - provider_obj - user @@ -31813,9 +31814,17 @@ components: type: object description: ConnectionToken Serializer properties: + pk: + type: string + format: uuid + title: Connection token uuid provider: type: integer + endpoint: + type: string + format: uuid required: + - endpoint - provider ConsentChallenge: type: object @@ -34332,6 +34341,8 @@ components: type: boolean application_pre: type: string + flow_designation: + $ref: '#/components/schemas/FlowDesignationEnum' enroll_url: type: string recovery_url: @@ -34347,6 +34358,7 @@ components: show_source_labels: type: boolean required: + - flow_designation - password_fields - primary_action - show_source_labels @@ -35217,6 +35229,10 @@ components: object_uniqueness_field: type: string description: Field which contains a unique Identifier. + password_login_update_internal_password: + type: boolean + description: Update internal authentik password when login succeeds with + LDAP sync_users: type: boolean sync_users_password: @@ -35358,6 +35374,10 @@ components: type: string minLength: 1 description: Field which contains a unique Identifier. + password_login_update_internal_password: + type: boolean + description: Update internal authentik password when login succeeds with + LDAP sync_users: type: boolean sync_users_password: @@ -38586,8 +38606,15 @@ components: type: object description: ConnectionToken Serializer properties: + pk: + type: string + format: uuid + title: Connection token uuid provider: type: integer + endpoint: + type: string + format: uuid PatchedConsentStageRequest: type: object description: ConsentStage Serializer @@ -39425,6 +39452,10 @@ components: type: string minLength: 1 description: Field which contains a unique Identifier. + password_login_update_internal_password: + type: boolean + description: Update internal authentik password when login succeeds with + LDAP sync_users: type: boolean sync_users_password: @@ -45584,8 +45615,8 @@ components: description: Get latest version from cache readOnly: true version_latest_valid: - type: boolean - description: Latest version query is a valid non-default value + type: string + description: Check if latest version is valid readOnly: true build_hash: type: string diff --git a/tests/e2e/test_source_ldap_samba.py b/tests/e2e/test_source_ldap_samba.py index d5210f6b51..fb9aa6d12a 100644 --- a/tests/e2e/test_source_ldap_samba.py +++ b/tests/e2e/test_source_ldap_samba.py @@ -128,6 +128,7 @@ class TestSourceLDAPSamba(SeleniumTestCase): base_dn="dc=test,dc=goauthentik,dc=io", additional_user_dn="ou=users", additional_group_dn="ou=groups", + password_login_update_internal_password=True, ) source.property_mappings.set( LDAPPropertyMapping.objects.filter( diff --git a/web/package-lock.json b/web/package-lock.json index 6d8bf502e3..8d3b0569ce 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -17,7 +17,7 @@ "@codemirror/theme-one-dark": "^6.1.2", "@formatjs/intl-listformat": "^7.5.5", "@fortawesome/fontawesome-free": "^6.5.1", - "@goauthentik/api": "^2024.2.2-1710521362", + "@goauthentik/api": "^2024.2.2-1711369360", "@lit-labs/task": "^3.1.0", "@lit/context": "^1.1.0", "@lit/localize": "^0.12.1", @@ -25,7 +25,7 @@ "@open-wc/lit-helpers": "^0.7.0", "@patternfly/elements": "^2.4.0", "@patternfly/patternfly": "^4.224.2", - "@sentry/browser": "^7.107.0", + "@sentry/browser": "^7.108.0", "@webcomponents/webcomponentsjs": "^2.8.0", "base64-js": "^1.5.1", "chart.js": "^4.4.2", @@ -59,7 +59,7 @@ "@jeysal/storybook-addon-css-user-preferences": "^0.2.0", "@lit/localize-tools": "^0.7.2", "@rollup/plugin-replace": "^5.0.5", - "@spotlightjs/spotlight": "^1.2.14", + "@spotlightjs/spotlight": "^1.2.15", "@storybook/addon-essentials": "^7.6.17", "@storybook/addon-links": "^7.6.17", "@storybook/api": "^7.6.17", @@ -2820,9 +2820,9 @@ } }, "node_modules/@goauthentik/api": { - "version": "2024.2.2-1710521362", - "resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2024.2.2-1710521362.tgz", - "integrity": "sha512-rfGIk+l+hcsgYd6Pj8cL9GTrUlJzT2dhAI6kJk7OsE/HamIUxpPG5wquE9oRcxrsWYkuFZQ1Z4lTePdSjxbt0w==" + "version": "2024.2.2-1711369360", + "resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2024.2.2-1711369360.tgz", + "integrity": "sha512-8/J6cfxzpaUyz+piZUXrxPZuAlJ9SxwNrH+Z8xSRLAVavmEjmRM+Oy2XJEIZLDbcBKhNEuE99xdOxq6il/FJVw==" }, "node_modules/@hcaptcha/types": { "version": "1.0.3", @@ -4407,102 +4407,102 @@ "peer": true }, "node_modules/@sentry-internal/feedback": { - "version": "7.107.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.107.0.tgz", - "integrity": "sha512-okF0B9AJHrpkwNMxNs/Lffw3N5ZNbGwz4uvCfyOfnMxc7E2VfDM18QzUvTBRvNr3bA9wl+InJ+EMG3aZhyPunA==", + "version": "7.108.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.108.0.tgz", + "integrity": "sha512-8JcgZEnk1uWrXJhsd3iRvFtEiVeaWOEhN0NZwhwQXHfvODqep6JtrkY1yCIyxbpA37aZmrPc2JhyotRERGfUjg==", "dependencies": { - "@sentry/core": "7.107.0", - "@sentry/types": "7.107.0", - "@sentry/utils": "7.107.0" + "@sentry/core": "7.108.0", + "@sentry/types": "7.108.0", + "@sentry/utils": "7.108.0" }, "engines": { "node": ">=12" } }, "node_modules/@sentry-internal/replay-canvas": { - "version": "7.107.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-7.107.0.tgz", - "integrity": "sha512-dmDL9g3QDfo7axBOsVnpiKdJ/DXrdeuRv1AqsLgwzJKvItsv0ZizX0u+rj5b1UoxcwbXRMxJ0hit5a1yt3t/ow==", + "version": "7.108.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-7.108.0.tgz", + "integrity": "sha512-R5tvjGqWUV5vSk0N1eBgVW7wIADinrkfDEBZ9FyKP2mXHBobsyNGt30heJDEqYmVqluRqjU2NuIRapsnnrpGnA==", "dependencies": { - "@sentry/core": "7.107.0", - "@sentry/replay": "7.107.0", - "@sentry/types": "7.107.0", - "@sentry/utils": "7.107.0" + "@sentry/core": "7.108.0", + "@sentry/replay": "7.108.0", + "@sentry/types": "7.108.0", + "@sentry/utils": "7.108.0" }, "engines": { "node": ">=12" } }, "node_modules/@sentry-internal/tracing": { - "version": "7.107.0", - "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.107.0.tgz", - "integrity": "sha512-le9wM8+OHBbq7m/8P7JUJ1UhSPIty+Z/HmRXc5Z64ODZcOwFV6TmDpYx729IXDdz36XUKmeI+BeM7yQdTTZPfQ==", + "version": "7.108.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.108.0.tgz", + "integrity": "sha512-zuK5XsTsb+U+hgn3SPetYDAogrXsM16U/LLoMW7+TlC6UjlHGYQvmX3o+M2vntejoU1QZS8m1bCAZSMWEypAEw==", "dependencies": { - "@sentry/core": "7.107.0", - "@sentry/types": "7.107.0", - "@sentry/utils": "7.107.0" + "@sentry/core": "7.108.0", + "@sentry/types": "7.108.0", + "@sentry/utils": "7.108.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/browser": { - "version": "7.107.0", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.107.0.tgz", - "integrity": "sha512-KnqaQDhxv6w9dJ+mYLsNwPeGZfgbpM3vaismBNyJCKLgWn2V75kxkSq+bDX8LQT/13AyK7iFp317L6P8EuNa3g==", + "version": "7.108.0", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.108.0.tgz", + "integrity": "sha512-FNpzsdTvGvdHJMUelqEouUXMZU7jC+dpN7CdT6IoHVVFEkoAgrjMVUhXZoQ/dmCkdKWHmFSQhJ8Fm6V+e9Aq0A==", "dependencies": { - "@sentry-internal/feedback": "7.107.0", - "@sentry-internal/replay-canvas": "7.107.0", - "@sentry-internal/tracing": "7.107.0", - "@sentry/core": "7.107.0", - "@sentry/replay": "7.107.0", - "@sentry/types": "7.107.0", - "@sentry/utils": "7.107.0" + "@sentry-internal/feedback": "7.108.0", + "@sentry-internal/replay-canvas": "7.108.0", + "@sentry-internal/tracing": "7.108.0", + "@sentry/core": "7.108.0", + "@sentry/replay": "7.108.0", + "@sentry/types": "7.108.0", + "@sentry/utils": "7.108.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/core": { - "version": "7.107.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.107.0.tgz", - "integrity": "sha512-C7ogye6+KPyBi8NVL0P8Rxx3Ur7Td8ufnjxosVy678lqY+dcYPk/HONROrzUFYW5fMKWL4/KYnwP+x9uHnkDmw==", + "version": "7.108.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.108.0.tgz", + "integrity": "sha512-I/VNZCFgLASxHZaD0EtxZRM34WG9w2gozqgrKGNMzAymwmQ3K9g/1qmBy4e6iS3YRptb7J5UhQkZQHrcwBbjWQ==", "dependencies": { - "@sentry/types": "7.107.0", - "@sentry/utils": "7.107.0" + "@sentry/types": "7.108.0", + "@sentry/utils": "7.108.0" }, "engines": { "node": ">=8" } }, "node_modules/@sentry/replay": { - "version": "7.107.0", - "resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.107.0.tgz", - "integrity": "sha512-BNJDEVaEwr/YnV22qnyVA1almx/3p615m3+KaF8lPo7YleYgJGSJv1auH64j1G8INkrJ0J0wFBujb1EFjMYkxA==", + "version": "7.108.0", + "resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.108.0.tgz", + "integrity": "sha512-jo8fDOzcZJclP1+4n9jUtVxTlBFT9hXwxhAMrhrt70FV/nfmCtYQMD3bzIj79nwbhUtFP6pN39JH1o7Xqt1hxQ==", "dependencies": { - "@sentry-internal/tracing": "7.107.0", - "@sentry/core": "7.107.0", - "@sentry/types": "7.107.0", - "@sentry/utils": "7.107.0" + "@sentry-internal/tracing": "7.108.0", + "@sentry/core": "7.108.0", + "@sentry/types": "7.108.0", + "@sentry/utils": "7.108.0" }, "engines": { "node": ">=12" } }, "node_modules/@sentry/types": { - "version": "7.107.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.107.0.tgz", - "integrity": "sha512-H7qcPjPSUWHE/Zf5bR1EE24G0pGVuJgrSx8Tvvl5nKEepswMYlbXHRVSDN0gTk/E5Z7cqf+hUBOpkQgZyps77w==", + "version": "7.108.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.108.0.tgz", + "integrity": "sha512-bKtHITmBN3kqtqE5eVvL8mY8znM05vEodENwRpcm6TSrrBjC2RnwNWVwGstYDdHpNfFuKwC8mLY9bgMJcENo8g==", "engines": { "node": ">=8" } }, "node_modules/@sentry/utils": { - "version": "7.107.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.107.0.tgz", - "integrity": "sha512-C6PbN5gHh73MRHohnReeQ60N8rrLYa9LciHue3Ru2290eSThg4CzsPnx4SzkGpkSeVlhhptKtKZ+hp/ha3iVuw==", + "version": "7.108.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.108.0.tgz", + "integrity": "sha512-a45yEFD5qtgZaIFRAcFkG8C8lnDzn6t4LfLXuV4OafGAy/3ZAN3XN8wDnrruHkiUezSSANGsLg3bXaLW/JLvJw==", "dependencies": { - "@sentry/types": "7.107.0" + "@sentry/types": "7.108.0" }, "engines": { "node": ">=8" @@ -4514,9 +4514,9 @@ "license": "MIT" }, "node_modules/@spotlightjs/overlay": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@spotlightjs/overlay/-/overlay-1.8.0.tgz", - "integrity": "sha512-yRcxp7Je4OXyr/JNJp5TAixu7gV9Hq99MQ94bMvoLv+WtS1ngd1lBmxMwAWKGp5TFUXCidNzKIjc11T4nCQ6FQ==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@spotlightjs/overlay/-/overlay-1.8.1.tgz", + "integrity": "sha512-t8S2b6AxgDfDoPls3CU7uABLdKx3g8cCXQWEHOICC1i7MYUSQLFMDpWzFWTEjN0XA8MGwNf/QKNlZ/HhaKTzJw==", "dev": true }, "node_modules/@spotlightjs/sidecar": { @@ -4528,12 +4528,12 @@ } }, "node_modules/@spotlightjs/spotlight": { - "version": "1.2.14", - "resolved": "https://registry.npmjs.org/@spotlightjs/spotlight/-/spotlight-1.2.14.tgz", - "integrity": "sha512-bix/qb0qnky3GajKAQ5gJquh81CPlc6/c6KmxCuZbH2pta0M5r9RmQbLFrZkJl9QvkHCf/+qBDrm1Td6KtRIoQ==", + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@spotlightjs/spotlight/-/spotlight-1.2.15.tgz", + "integrity": "sha512-M0VTAyameAsK9kjI9k31CehTLJMqUdOvv7DSOr27dcioytBV0uC0l8w7ngHWxdqCOTpbruEs8EIrbQ0T9b4YZQ==", "dev": true, "dependencies": { - "@spotlightjs/overlay": "1.8.0", + "@spotlightjs/overlay": "1.8.1", "@spotlightjs/sidecar": "1.4.0" }, "bin": { diff --git a/web/package.json b/web/package.json index 02761fd757..664b15a7ba 100644 --- a/web/package.json +++ b/web/package.json @@ -38,7 +38,7 @@ "@codemirror/theme-one-dark": "^6.1.2", "@formatjs/intl-listformat": "^7.5.5", "@fortawesome/fontawesome-free": "^6.5.1", - "@goauthentik/api": "^2024.2.2-1710521362", + "@goauthentik/api": "^2024.2.2-1711369360", "@lit-labs/task": "^3.1.0", "@lit/context": "^1.1.0", "@lit/localize": "^0.12.1", @@ -46,7 +46,7 @@ "@open-wc/lit-helpers": "^0.7.0", "@patternfly/elements": "^2.4.0", "@patternfly/patternfly": "^4.224.2", - "@sentry/browser": "^7.107.0", + "@sentry/browser": "^7.108.0", "@webcomponents/webcomponentsjs": "^2.8.0", "base64-js": "^1.5.1", "chart.js": "^4.4.2", @@ -80,7 +80,7 @@ "@jeysal/storybook-addon-css-user-preferences": "^0.2.0", "@lit/localize-tools": "^0.7.2", "@rollup/plugin-replace": "^5.0.5", - "@spotlightjs/spotlight": "^1.2.14", + "@spotlightjs/spotlight": "^1.2.15", "@storybook/addon-essentials": "^7.6.17", "@storybook/addon-links": "^7.6.17", "@storybook/api": "^7.6.17", diff --git a/web/src/admin/providers/oauth2/OAuth2ProviderViewPage.ts b/web/src/admin/providers/oauth2/OAuth2ProviderViewPage.ts index 337f11be85..6c3bcc4cc8 100644 --- a/web/src/admin/providers/oauth2/OAuth2ProviderViewPage.ts +++ b/web/src/admin/providers/oauth2/OAuth2ProviderViewPage.ts @@ -175,7 +175,7 @@ export class OAuth2ProviderViewPage extends AKElement { `}
@@ -255,7 +255,7 @@ export class OAuth2ProviderViewPage extends AKElement {
-
+
diff --git a/web/src/admin/providers/rac/ConnectionTokenList.ts b/web/src/admin/providers/rac/ConnectionTokenList.ts index 4161cedaee..d9d4fbf830 100644 --- a/web/src/admin/providers/rac/ConnectionTokenList.ts +++ b/web/src/admin/providers/rac/ConnectionTokenList.ts @@ -61,12 +61,12 @@ export class ConnectionTokenListPage extends Table { }} .usedBy=${(item: ConnectionToken) => { return new RacApi(DEFAULT_CONFIG).racConnectionTokensUsedByList({ - connectionTokenUuid: item.pk, + connectionTokenUuid: item.pk || "", }); }} .delete=${(item: ConnectionToken) => { return new RacApi(DEFAULT_CONFIG).racConnectionTokensDestroy({ - connectionTokenUuid: item.pk, + connectionTokenUuid: item.pk || "", }); }} > diff --git a/web/src/admin/sources/ldap/LDAPSourceForm.ts b/web/src/admin/sources/ldap/LDAPSourceForm.ts index f62478963c..a5b9d41c9c 100644 --- a/web/src/admin/sources/ldap/LDAPSourceForm.ts +++ b/web/src/admin/sources/ldap/LDAPSourceForm.ts @@ -86,6 +86,28 @@ export class LDAPSourceForm extends BaseSourceForm { ${msg("Enabled")} + + +

+ ${msg( + "When the user logs in to authentik using this source password backend, update their credentials in authentik.", + )} +

+
+

+ ${msg( + "Please scan the QR code above using the Microsoft Authenticator, Google Authenticator, or other authenticator apps on your device, and enter the code the device displays below to finish setting up the MFA device.", + )} +

uiFields[f])); - return html` + ${msg( + "Enter the email associated with your account, and we'll send you a link to reset your password.", + )} +

+ ` + : nothing} + Support level: Community The integration + is community maintained. -- Support level: Community +- Support level: Vendor The integration + is supported by the vendor. - The integration is community maintained. +- Support level: authentik The integration + is regularly tested by the authentik team. -- Support level: Vendor +### Add a new integration - The integration is supported by the vendor. +To add documentation for a new integration (with support level Community or Vendor), please use the integration template [`service.md`](https://github.com/goauthentik/authentik/blob/main/website/integrations/_template/service.md) file from our GitHub repo. You can download the template file using the following command: -- Support level: authentik +``` +wget https://raw.githubusercontent.com/goauthentik/authentik/main/website/integrations/_template/service.md +``` - The integration is regularly tested by the authentik team. +## Integration categories diff --git a/website/integrations/services/nextcloud/index.md b/website/integrations/services/nextcloud/index.md index 3b8be9c4b5..c26682501f 100644 --- a/website/integrations/services/nextcloud/index.md +++ b/website/integrations/services/nextcloud/index.md @@ -286,7 +286,7 @@ Create a custom SAML Property Mapping: - Set the _Expression_ to: ```python -for group in user.ak_groups.all(): +for group in request.user.all_groups(): yield group.name if ak_is_group_member(request.user, name=""): yield "admin" diff --git a/website/integrations/sources/ldap/index.md b/website/integrations/sources/ldap/index.md index f64e70a070..716edc708e 100644 --- a/website/integrations/sources/ldap/index.md +++ b/website/integrations/sources/ldap/index.md @@ -14,25 +14,25 @@ For Active Directory, follow the [Active Directory Integration](../active-direct For FreeIPA, follow the [FreeIPA Integration](../freeipa/) ::: -- Server URI: URI to your LDAP server/Domain Controller. +- **Server URI**: URI to your LDAP server/Domain Controller. You can specify multiple servers by separating URIs with a comma, like `ldap://ldap1.company,ldap://ldap2.company`. When using a DNS entry with multiple Records, authentik will select a random entry when first connecting. -- Bind CN: CN of the bind user. This can also be a UPN in the format of `user@domain.tld`. -- Bind password: Password used during the bind process. -- Enable StartTLS: Enables StartTLS functionality. To use LDAPS instead, use port `636`. -- Base DN: Base DN used for all LDAP queries. -- Addition User DN: Prepended to the base DN for user queries. -- Addition Group DN: Prepended to the base DN for group queries. -- User object filter: Consider objects matching this filter to be users. -- Group object filter: Consider objects matching this filter to be groups. -- User group membership field: This field contains the user's group memberships. -- Object uniqueness field: This field contains a unique identifier. -- Sync groups: Enable/disable group synchronization. Groups are synced in the background every 5 minutes. -- Sync parent group: Optionally set this group as the parent group for all synced groups. An example use case of this would be to import Active Directory groups under a root `imported-from-ad` group. -- Property mappings: Define which LDAP properties map to which authentik properties. The default set of property mappings is generated for Active Directory. See also [LDAP Property Mappings](../../../docs/property-mappings/#ldap-property-mapping) +- **Bind CN**: CN of the bind user. This can also be a UPN in the format of `user@domain.tld`. +- **Bind password**: Password used during the bind process. +- **Enable StartTLS**: Enables StartTLS functionality. To use LDAPS instead, use port `636`. +- **Base DN**: Base DN used for all LDAP queries. +- **Addition User DN**: Prepended to the base DN for user queries. +- **Addition Group DN**: Prepended to the base DN for group queries. +- **User object filter**: Consider objects matching this filter to be users. +- **Group object filter**: Consider objects matching this filter to be groups. +- **User group membership field**: This field contains the user's group memberships. +- **Object uniqueness field**: This field contains a unique identifier. +- **Sync groups**: Enable/disable group synchronization. Groups are synced in the background every 5 minutes. +- **Sync parent group**: Optionally set this group as the parent group for all synced groups. An example use case of this would be to import Active Directory groups under a root `imported-from-ad` group. +- **Property mappings** and **Group Property Mappings**: Define which LDAP properties map to which authentik properties. The default set of property mappings is generated for Active Directory. See also [LDAP Property Mappings](../../../docs/property-mappings/#ldap-property-mapping) ## Property mappings @@ -42,6 +42,20 @@ By default, authentik ships with some pre-configured mappings for the most commo You can assign the value of a mapping to any user attribute, or save it as a custom attribute by prefixing the object field with `attribute.` Keep in mind though, data types from the LDAP server will be carried over. This means that with some implementations, where fields are stored as array in LDAP, they will be saved as array in authentik. To prevent this, use the built-in `list_flatten` function. +## Password login + +By default, authentik doesn't update the password it stores for a user when they log in using their LDAP credentials. That means that if the LDAP server is not reachable by authentik, users will not be able to log in. This behavior can be turned on with the **Update internal password on login** setting on the LDAP source. + +:::note +Sources created prior to the 2024.2 release have this setting turned on by default. +::: + +Be aware of the following security considerations when turning on this functionality: + +- Updating the LDAP password does not invalid the password stored in authentik, however for LDAP Servers like FreeIPA and Active Directory, authentik will lock its internal password during the next LDAP sync. For other LDAP servers, the old passwords will still be valid indefinitely. +- Logging in via LDAP credentials overwrites the password stored in authentik if users have different passwords in LDAP and authentik. +- Custom security measures used to secure the password in LDAP may differ from the ones used in authentik. Depending on thread model and security requirements this could lead to unknowingly being non-compliant. + ## Troubleshooting To troubleshoot LDAP sources and their synchronization, see [LDAP Troubleshooting](../../../docs/troubleshooting/ldap_source) diff --git a/website/package-lock.json b/website/package-lock.json index 2f2cecc9b3..28757cdbff 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -33,7 +33,7 @@ "@docusaurus/module-type-aliases": "3.1.1", "@docusaurus/tsconfig": "3.1.1", "@docusaurus/types": "3.1.1", - "@types/react": "^18.2.67", + "@types/react": "^18.2.69", "prettier": "3.2.5", "typescript": "~5.4.3" }, @@ -3999,9 +3999,9 @@ "integrity": "sha512-+0autS93xyXizIYiyL02FCY8N+KkKPhILhcUSA276HxzreZ16kl+cmwvV2qAM/PuCCwPXzOXOWhiPcw20uSFcA==" }, "node_modules/@types/react": { - "version": "18.2.67", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.67.tgz", - "integrity": "sha512-vkIE2vTIMHQ/xL0rgmuoECBCkZFZeHr49HeWSc24AptMbNRo7pwSBvj73rlJJs9fGKj0koS+V7kQB1jHS0uCgw==", + "version": "18.2.69", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.69.tgz", + "integrity": "sha512-W1HOMUWY/1Yyw0ba5TkCV+oqynRjG7BnteBB+B7JmAK7iw3l2SW+VGOxL+akPweix6jk2NNJtyJKpn4TkpfK3Q==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -16568,9 +16568,9 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", - "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", "dependencies": { "colorette": "^2.0.10", "memfs": "^3.4.3", diff --git a/website/package.json b/website/package.json index db3d5b63b2..d4b80cc213 100644 --- a/website/package.json +++ b/website/package.json @@ -52,7 +52,7 @@ "@docusaurus/module-type-aliases": "3.1.1", "@docusaurus/tsconfig": "3.1.1", "@docusaurus/types": "3.1.1", - "@types/react": "^18.2.67", + "@types/react": "^18.2.69", "prettier": "3.2.5", "typescript": "~5.4.3" },