We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
FreeIPA LDAP sync broken in 2023.8.*
**Describe the bug**
After upgrading Authentik to `2023.8.0` (and `2023.8.1`), the LDAP sync with FreeIPA seems to be broken. The `ldap_sync:freeipa:groups` tasks complete without issues, but the `ldap_sync:freeipa:users` task fails:

```
ldap_sync:freeipa:users:cd24b105-15d6-4d2b-85bc-29492f0f86a8

Task finished with errors
["“['TRUE']” value must be either True or False."]
```

**To Reproduce**
Steps to reproduce the behavior:

1. Go to 'if/admin/#/core/sources'
2. Click on the FreeIPA LDAP source
3. Click "Run Sync Again"

**Expected behavior**
It is expected that the sync completes without errors

**Screenshots**
![image](https://github.com/goauthentik/authentik/assets/9056525/864efc40-83e7-4fc4-9a0a-01cce4ba9a23)

**Logs**
Error log from `if/admin/#/events/log` --> `System task exception: authentik.events.monitored_tasks`:

```
Task ldap_sync encountered an error: Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/celery/app/trace.py", line 477, in trace_task
    R = retval = fun(*args, **kwargs)
                 ^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/celery.py", line 275, in _inner
    reraise(*exc_info)
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/_compat.py", line 60, in reraise
    raise value
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/celery.py", line 270, in _inner
    return f(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/celery/app/trace.py", line 760, in __protected_call__
    return self.run(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/authentik/sources/ldap/tasks.py", line 97, in ldap_sync
    count = sync_inst.sync(page)
            ^^^^^^^^^^^^^^^^^^^^
  File "/authentik/sources/ldap/sync/users.py", line 73, in sync
    FreeIPA(self._source).sync(attributes, ak_user, created)
  File "/authentik/sources/ldap/sync/vendor/freeipa.py", line 23, in sync
    self.check_nsaccountlock(attributes, user)
  File "/authentik/sources/ldap/sync/vendor/freeipa.py", line 51, in check_nsaccountlock
    user.save()
  File "/usr/local/lib/python3.11/site-packages/django/contrib/auth/base_user.py", line 76, in save
    super().save(*args, **kwargs)
  File "/usr/local/lib/python3.11/site-packages/django/db/models/base.py", line 814, in save
    self.save_base(
  File "/usr/local/lib/python3.11/site-packages/django/db/models/base.py", line 877, in save_base
    updated = self._save_table(
              ^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/db/models/base.py", line 990, in _save_table
    updated = self._do_update(
              ^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/db/models/base.py", line 1054, in _do_update
    return filtered._update(values) > 0
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/db/models/query.py", line 1231, in _update
    return query.get_compiler(self.db).execute_sql(CURSOR)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/db/models/sql/compiler.py", line 1984, in execute_sql
    cursor = super().execute_sql(result_type)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/db/models/sql/compiler.py", line 1549, in execute_sql
    sql, params = self.as_sql()
                  ^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/db/models/sql/compiler.py", line 1947, in as_sql
    val = field.get_db_prep_save(val, connection=self.connection)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/db/models/fields/__init__.py", line 954, in get_db_prep_save
    return self.get_db_prep_value(value, connection=connection, prepared=False)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/db/models/fields/__init__.py", line 947, in get_db_prep_value
    value = self.get_prep_value(value)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/db/models/fields/__init__.py", line 1122, in get_prep_value
    return self.to_python(value)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/django/db/models/fields/__init__.py", line 1112, in to_python
    raise exceptions.ValidationError(
django.core.exceptions.ValidationError: ["“['TRUE']” value must be either True or False."]
```

**Version and Deployment (please complete the following information):**

-   authentik version: `2023.8.0`, `2023.8.1`
-   Deployment: `docker-compose`

**Additional context**
N/A


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `authentik/sources/ldap/sync/vendor/freeipa.py`
Content:
```
1 """FreeIPA specific"""
2 from datetime import datetime
3 from typing import Any, Generator
4 
5 from pytz import UTC
6 
7 from authentik.core.models import User
8 from authentik.sources.ldap.sync.base import BaseLDAPSynchronizer
9 
10 
11 class FreeIPA(BaseLDAPSynchronizer):
12     """FreeIPA-specific LDAP"""
13 
14     @staticmethod
15     def name() -> str:
16         return "freeipa"
17 
18     def get_objects(self, **kwargs) -> Generator:
19         yield None
20 
21     def sync(self, attributes: dict[str, Any], user: User, created: bool):
22         self.check_pwd_last_set(attributes, user, created)
23         self.check_nsaccountlock(attributes, user)
24 
25     def check_pwd_last_set(self, attributes: dict[str, Any], user: User, created: bool):
26         """Check krbLastPwdChange"""
27         if "krbLastPwdChange" not in attributes:
28             return
29         pwd_last_set: datetime = attributes.get("krbLastPwdChange", datetime.now())
30         pwd_last_set = pwd_last_set.replace(tzinfo=UTC)
31         if created or pwd_last_set >= user.password_change_date:
32             self.message(f"'{user.username}': Reset user's password")
33             self._logger.debug(
34                 "Reset user's password",
35                 user=user.username,
36                 created=created,
37                 pwd_last_set=pwd_last_set,
38             )
39             user.set_unusable_password()
40             user.save()
41 
42     def check_nsaccountlock(self, attributes: dict[str, Any], user: User):
43         """https://www.port389.org/docs/389ds/howto/howto-account-inactivation.html"""
44         # This is more of a 389-ds quirk rather than FreeIPA, but FreeIPA uses
45         # 389-ds and this will trigger regardless
46         if "nsaccountlock" not in attributes:
47             return
48         is_active = attributes.get("nsaccountlock", False)
49         if is_active != user.is_active:
50             user.is_active = is_active
51             user.save()
52
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/authentik/sources/ldap/sync/vendor/freeipa.py b/authentik/sources/ldap/sync/vendor/freeipa.py
--- a/authentik/sources/ldap/sync/vendor/freeipa.py
+++ b/authentik/sources/ldap/sync/vendor/freeipa.py
@@ -45,7 +45,11 @@
         # 389-ds and this will trigger regardless
         if "nsaccountlock" not in attributes:
             return
-        is_active = attributes.get("nsaccountlock", False)
+        # For some reason, nsaccountlock is not defined properly in the schema as bool
+        # hence we get it as a list of strings
+        _is_active = str(self._flatten(attributes.get("nsaccountlock", ["FALSE"])))
+        # So we have to attempt to convert it to a bool
+        is_active = _is_active.lower() == "true"
         if is_active != user.is_active:
             user.is_active = is_active
             user.save()

{"golden_diff": "diff --git a/authentik/sources/ldap/sync/vendor/freeipa.py b/authentik/sources/ldap/sync/vendor/freeipa.py\n--- a/authentik/sources/ldap/sync/vendor/freeipa.py\n+++ b/authentik/sources/ldap/sync/vendor/freeipa.py\n@@ -45,7 +45,11 @@\n         # 389-ds and this will trigger regardless\n         if \"nsaccountlock\" not in attributes:\n             return\n-        is_active = attributes.get(\"nsaccountlock\", False)\n+        # For some reason, nsaccountlock is not defined properly in the schema as bool\n+        # hence we get it as a list of strings\n+        _is_active = str(self._flatten(attributes.get(\"nsaccountlock\", [\"FALSE\"])))\n+        # So we have to attempt to convert it to a bool\n+        is_active = _is_active.lower() == \"true\"\n         if is_active != user.is_active:\n             user.is_active = is_active\n             user.save()\n", "issue": "FreeIPA LDAP sync broken in 2023.8.*\n**Describe the bug**\r\nAfter upgrading Authentik to `2023.8.0` (and `2023.8.1`), the LDAP sync with FreeIPA seems to be broken. The `ldap_sync:freeipa:groups` tasks complete without issues, but the `ldap_sync:freeipa:users` task fails:\r\n\r\n```\r\nldap_sync:freeipa:users:cd24b105-15d6-4d2b-85bc-29492f0f86a8\r\n\r\nTask finished with errors\r\n[\"\u201c['TRUE']\u201d value must be either True or False.\"]\r\n```\r\n\r\n**To Reproduce**\r\nSteps to reproduce the behavior:\r\n\r\n1. Go to 'if/admin/#/core/sources'\r\n2. Click on the FreeIPA LDAP source\r\n3. Click \"Run Sync Again\"\r\n\r\n**Expected behavior**\r\nIt is expected that the sync completes without errors\r\n\r\n**Screenshots**\r\n![image](https://github.com/goauthentik/authentik/assets/9056525/864efc40-83e7-4fc4-9a0a-01cce4ba9a23)\r\n\r\n**Logs**\r\nError log from `if/admin/#/events/log` --> `System task exception: authentik.events.monitored_tasks`:\r\n\r\n```\r\nTask ldap_sync encountered an error: Traceback (most recent call last):\r\n  File \"/usr/local/lib/python3.11/site-packages/celery/app/trace.py\", line 477, in trace_task\r\n    R = retval = fun(*args, **kwargs)\r\n                 ^^^^^^^^^^^^^^^^^^^^\r\n  File \"/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/celery.py\", line 275, in _inner\r\n    reraise(*exc_info)\r\n  File \"/usr/local/lib/python3.11/site-packages/sentry_sdk/_compat.py\", line 60, in reraise\r\n    raise value\r\n  File \"/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/celery.py\", line 270, in _inner\r\n    return f(*args, **kwargs)\r\n           ^^^^^^^^^^^^^^^^^^\r\n  File \"/usr/local/lib/python3.11/site-packages/celery/app/trace.py\", line 760, in __protected_call__\r\n    return self.run(*args, **kwargs)\r\n           ^^^^^^^^^^^^^^^^^^^^^^^^^\r\n  File \"/authentik/sources/ldap/tasks.py\", line 97, in ldap_sync\r\n    count = sync_inst.sync(page)\r\n            ^^^^^^^^^^^^^^^^^^^^\r\n  File \"/authentik/sources/ldap/sync/users.py\", line 73, in sync\r\n    FreeIPA(self._source).sync(attributes, ak_user, created)\r\n  File \"/authentik/sources/ldap/sync/vendor/freeipa.py\", line 23, in sync\r\n    self.check_nsaccountlock(attributes, user)\r\n  File \"/authentik/sources/ldap/sync/vendor/freeipa.py\", line 51, in check_nsaccountlock\r\n    user.save()\r\n  File \"/usr/local/lib/python3.11/site-packages/django/contrib/auth/base_user.py\", line 76, in save\r\n    super().save(*args, **kwargs)\r\n  File \"/usr/local/lib/python3.11/site-packages/django/db/models/base.py\", line 814, in save\r\n    self.save_base(\r\n  File \"/usr/local/lib/python3.11/site-packages/django/db/models/base.py\", line 877, in save_base\r\n    updated = self._save_table(\r\n              ^^^^^^^^^^^^^^^^^\r\n  File \"/usr/local/lib/python3.11/site-packages/django/db/models/base.py\", line 990, in _save_table\r\n    updated = self._do_update(\r\n              ^^^^^^^^^^^^^^^^\r\n  File \"/usr/local/lib/python3.11/site-packages/django/db/models/base.py\", line 1054, in _do_update\r\n    return filtered._update(values) > 0\r\n           ^^^^^^^^^^^^^^^^^^^^^^^^\r\n  File \"/usr/local/lib/python3.11/site-packages/django/db/models/query.py\", line 1231, in _update\r\n    return query.get_compiler(self.db).execute_sql(CURSOR)\r\n           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r\n  File \"/usr/local/lib/python3.11/site-packages/django/db/models/sql/compiler.py\", line 1984, in execute_sql\r\n    cursor = super().execute_sql(result_type)\r\n             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r\n  File \"/usr/local/lib/python3.11/site-packages/django/db/models/sql/compiler.py\", line 1549, in execute_sql\r\n    sql, params = self.as_sql()\r\n                  ^^^^^^^^^^^^^\r\n  File \"/usr/local/lib/python3.11/site-packages/django/db/models/sql/compiler.py\", line 1947, in as_sql\r\n    val = field.get_db_prep_save(val, connection=self.connection)\r\n          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r\n  File \"/usr/local/lib/python3.11/site-packages/django/db/models/fields/__init__.py\", line 954, in get_db_prep_save\r\n    return self.get_db_prep_value(value, connection=connection, prepared=False)\r\n           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r\n  File \"/usr/local/lib/python3.11/site-packages/django/db/models/fields/__init__.py\", line 947, in get_db_prep_value\r\n    value = self.get_prep_value(value)\r\n            ^^^^^^^^^^^^^^^^^^^^^^^^^^\r\n  File \"/usr/local/lib/python3.11/site-packages/django/db/models/fields/__init__.py\", line 1122, in get_prep_value\r\n    return self.to_python(value)\r\n           ^^^^^^^^^^^^^^^^^^^^^\r\n  File \"/usr/local/lib/python3.11/site-packages/django/db/models/fields/__init__.py\", line 1112, in to_python\r\n    raise exceptions.ValidationError(\r\ndjango.core.exceptions.ValidationError: [\"\u201c['TRUE']\u201d value must be either True or False.\"]\r\n```\r\n\r\n**Version and Deployment (please complete the following information):**\r\n\r\n-   authentik version: `2023.8.0`, `2023.8.1`\r\n-   Deployment: `docker-compose`\r\n\r\n**Additional context**\r\nN/A\r\n\n", "before_files": [{"content": "\"\"\"FreeIPA specific\"\"\"\nfrom datetime import datetime\nfrom typing import Any, Generator\n\nfrom pytz import UTC\n\nfrom authentik.core.models import User\nfrom authentik.sources.ldap.sync.base import BaseLDAPSynchronizer\n\n\nclass FreeIPA(BaseLDAPSynchronizer):\n    \"\"\"FreeIPA-specific LDAP\"\"\"\n\n    @staticmethod\n    def name() -> str:\n        return \"freeipa\"\n\n    def get_objects(self, **kwargs) -> Generator:\n        yield None\n\n    def sync(self, attributes: dict[str, Any], user: User, created: bool):\n        self.check_pwd_last_set(attributes, user, created)\n        self.check_nsaccountlock(attributes, user)\n\n    def check_pwd_last_set(self, attributes: dict[str, Any], user: User, created: bool):\n        \"\"\"Check krbLastPwdChange\"\"\"\n        if \"krbLastPwdChange\" not in attributes:\n            return\n        pwd_last_set: datetime = attributes.get(\"krbLastPwdChange\", datetime.now())\n        pwd_last_set = pwd_last_set.replace(tzinfo=UTC)\n        if created or pwd_last_set >= user.password_change_date:\n            self.message(f\"'{user.username}': Reset user's password\")\n            self._logger.debug(\n                \"Reset user's password\",\n                user=user.username,\n                created=created,\n                pwd_last_set=pwd_last_set,\n            )\n            user.set_unusable_password()\n            user.save()\n\n    def check_nsaccountlock(self, attributes: dict[str, Any], user: User):\n        \"\"\"https://www.port389.org/docs/389ds/howto/howto-account-inactivation.html\"\"\"\n        # This is more of a 389-ds quirk rather than FreeIPA, but FreeIPA uses\n        # 389-ds and this will trigger regardless\n        if \"nsaccountlock\" not in attributes:\n            return\n        is_active = attributes.get(\"nsaccountlock\", False)\n        if is_active != user.is_active:\n            user.is_active = is_active\n            user.save()\n", "path": "authentik/sources/ldap/sync/vendor/freeipa.py"}], "after_files": [{"content": "\"\"\"FreeIPA specific\"\"\"\nfrom datetime import datetime\nfrom typing import Any, Generator\n\nfrom pytz import UTC\n\nfrom authentik.core.models import User\nfrom authentik.sources.ldap.sync.base import BaseLDAPSynchronizer\n\n\nclass FreeIPA(BaseLDAPSynchronizer):\n    \"\"\"FreeIPA-specific LDAP\"\"\"\n\n    @staticmethod\n    def name() -> str:\n        return \"freeipa\"\n\n    def get_objects(self, **kwargs) -> Generator:\n        yield None\n\n    def sync(self, attributes: dict[str, Any], user: User, created: bool):\n        self.check_pwd_last_set(attributes, user, created)\n        self.check_nsaccountlock(attributes, user)\n\n    def check_pwd_last_set(self, attributes: dict[str, Any], user: User, created: bool):\n        \"\"\"Check krbLastPwdChange\"\"\"\n        if \"krbLastPwdChange\" not in attributes:\n            return\n        pwd_last_set: datetime = attributes.get(\"krbLastPwdChange\", datetime.now())\n        pwd_last_set = pwd_last_set.replace(tzinfo=UTC)\n        if created or pwd_last_set >= user.password_change_date:\n            self.message(f\"'{user.username}': Reset user's password\")\n            self._logger.debug(\n                \"Reset user's password\",\n                user=user.username,\n                created=created,\n                pwd_last_set=pwd_last_set,\n            )\n            user.set_unusable_password()\n            user.save()\n\n    def check_nsaccountlock(self, attributes: dict[str, Any], user: User):\n        \"\"\"https://www.port389.org/docs/389ds/howto/howto-account-inactivation.html\"\"\"\n        # This is more of a 389-ds quirk rather than FreeIPA, but FreeIPA uses\n        # 389-ds and this will trigger regardless\n        if \"nsaccountlock\" not in attributes:\n            return\n        # For some reason, nsaccountlock is not defined properly in the schema as bool\n        # hence we get it as a list of strings\n        _is_active = str(self._flatten(attributes.get(\"nsaccountlock\", [\"FALSE\"])))\n        # So we have to attempt to convert it to a bool\n        is_active = _is_active.lower() == \"true\"\n        if is_active != user.is_active:\n            user.is_active = is_active\n            user.save()\n", "path": "authentik/sources/ldap/sync/vendor/freeipa.py"}]}