Repository: goauthentik/authentik

Issue:
Unable to generate avatars
**Describe the bug**
It seems that Authentik is unable to generate avatars and as a result groups API request is not succeeding.

**To Reproduce**
Steps to reproduce the behavior:
1. Had been using gh-next for the security key fix
2. Update to 2022.2.2
3. See error

**Expected behavior**
I don't think it should error.

**Logs**
```
{"action": "system_exception", "auth_via": "session", "client_ip": "2001:<snip>:16e5:faaf:f9b7:eda0:ecb7:baf0", "context": {"geo": {<snip loc info>}, "http_request": {"args": {"ordering": "name"}, "method": "GET", "path": "/api/v3/core/groups/"}, "message": "Traceback (most recent call last):\n  File \"/usr/local/lib/python3.11/site-packages/asgiref/sync.py\", line 472, in thread_handler\n    raise exc_info[1]\n  File \"/usr/local/lib/python3.11/site-packages/django/core/handlers/base.py\", line 253, in _get_response_async\n    response = await wrapped_callback(\n               ^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/asgiref/sync.py\", line 435, in __call__\n    ret = await asyncio.wait_for(future, timeout=None)\n          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/asyncio/tasks.py\", line 442, in wait_for\n    return await fut\n           ^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/asgiref/current_thread_executor.py\", line 22, in run\n    result = self.fn(*self.args, **self.kwargs)\n             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/asgiref/sync.py\", line 476, in thread_handler\n    return func(*args, **kwargs)\n           ^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/django/views/decorators/csrf.py\", line 55, in wrapped_view\n    return view_func(*args, **kwargs)\n           ^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/viewsets.py\", line 125, in view\n    return self.dispatch(request, *args, **kwargs)\n           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/views.py\", line 509, in dispatch\n    response = self.handle_exception(exc)\n               ^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/views.py\", line 469, in handle_exception\n    self.raise_uncaught_exception(exc)\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/views.py\", line 480, in raise_uncaught_exception\n    raise exc\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/views.py\", line 506, in dispatch\n    response = handler(request, *args, **kwargs)\n               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/mixins.py\", line 43, in list\n    return self.get_paginated_response(serializer.data)\n                                       ^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py\", line 768, in data\n    ret = super().data\n          ^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py\", line 253, in data\n    self._data = self.to_representation(self.instance)\n                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py\", line 686, in to_representation\n    return [\n           ^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py\", line 687, in <listcomp>\n    self.child.to_representation(item) for item in iterable\n    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py\", line 522, in to_representation\n    ret[field.field_name] = field.to_representation(attribute)\n                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py\", line 686, in to_representation\n    return [\n           ^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py\", line 687, in <listcomp>\n    self.child.to_representation(item) for item in iterable\n    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py\", line 509, in to_representation\n    attribute = field.get_attribute(instance)\n                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/fields.py\", line 446, in get_attribute\n    return get_attribute(instance, self.source_attrs)\n           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/fields.py\", line 96, in get_attribute\n    instance = getattr(instance, attr)\n               ^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/authentik/core/models.py\", line 231, in avatar\n    return get_avatar(self)\n           ^^^^^^^^^^^^^^^^\n  File \"/authentik/lib/avatars.py\", line 178, in get_avatar\n    avatar = mode_map[mode](user, mode)\n             ^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/authentik/lib/avatars.py\", line 153, in avatar_mode_generated\n    svg = generate_avatar_from_name(user.name if user.name != \"\" else \"a k\")\n          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/authentik/lib/avatars.py\", line 110, in generate_avatar_from_name\n    initials += name_parts[-1]\n                ~~~~~~~~~~^^^^\nbuiltins.IndexError: list index out of range"}, "event": "Created Event", "host": "login.pikaviestin.fi", "level": "info", "logger": "authentik.events.models", "pid": 20, "request_id": "1877017341194265a759ca47d93159c9", "timestamp": "2023-02-21T11:28:22.364103", "user": {"email": "sm@<snip>.fi", "pk": 10, "username": "sm"}}
{"auth_via": "session", "event": "Task published", "host": "login.pikaviestin.fi", "level": "info", "logger": "authentik.root.celery", "pid": 20, "request_id": "1877017341194265a759ca47d93159c9", "task_id": "683731e3-b188-42e2-a78a-be84a8c11745", "task_name": "authentik.events.tasks.event_notification_handler", "timestamp": "2023-02-21T11:28:22.416294"}
{"event": "Internal Server Error: /api/v3/core/groups/", "exc_info": ["<class 'IndexError'>", "IndexError('list index out of range')", "<traceback object at 0x7fa798667fc0>"], "level": "error", "logger": "django.request", "timestamp": 1676978902.4232843}
{"auth_via": "session", "event": "/api/v3/core/groups/?ordering=name", "host": "login.pikaviestin.fi", "level": "info", "logger": "authentik.asgi", "method": "GET", "pid": 20, "remote": "2001:<snip>16e5:faaf:f9b7:eda0:ecb7:baf0", "request_id": "1877017341194265a759ca47d93159c9", "runtime": 10020, "scheme": "https", "status": 500, "timestamp": "2023-02-21T11:28:22.438719", "user": "sm", "user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 OPR/94.0.0.0"}
{"auth_via": "unauthenticated", "event": "/-/metrics/", "host": "localhost:8000", "level": "info", "logger": "authentik.asgi", "method": "GET", "pid": 19, "remote": "127.0.0.1", "request_id": "fc6af02c7a734c84af691b1ad3cb2a6a", "runtime": 653, "scheme": "http", "status": 200, "timestamp": "2023-02-21T11:28:29.812381", "user": "", "user_agent": "Go-http-client/1.1"}
{"auth_via": "unauthenticated", "event": "/-/health/ready/", "host": "localhost:9000", "level": "info", "logger": "authentik.asgi", "method": "HEAD", "pid": 19, "remote": "127.0.0.1", "request_id": "d2133369a9bd443697ab724c1ad5d34e", "runtime": 36, "scheme": "http", "status": 204, "timestamp": "2023-02-21T11:28:37.997634", "user": "", "user_agent": "goauthentik.io lifecycle Healthcheck"}
```

**Version and Deployment (please complete the following information):**
 - authentik version: 2022.2.2
 - Deployment: Docker via Ansible

**Additional context**
Generated event:
```
{
    "geo": {
       <snip>
    },
    "message": "Traceback (most recent call last):\n  File \"/usr/local/lib/python3.11/site-packages/asgiref/sync.py\", line 472, in thread_handler\n    raise exc_info[1]\n  File \"/usr/local/lib/python3.11/site-packages/django/core/handlers/base.py\", line 253, in _get_response_async\n    response = await wrapped_callback(\n               ^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/asgiref/sync.py\", line 435, in __call__\n    ret = await asyncio.wait_for(future, timeout=None)\n          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/asyncio/tasks.py\", line 442, in wait_for\n    return await fut\n           ^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/asgiref/current_thread_executor.py\", line 22, in run\n    result = self.fn(*self.args, **self.kwargs)\n             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/asgiref/sync.py\", line 476, in thread_handler\n    return func(*args, **kwargs)\n           ^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/django/views/decorators/csrf.py\", line 55, in wrapped_view\n    return view_func(*args, **kwargs)\n           ^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/viewsets.py\", line 125, in view\n    return self.dispatch(request, *args, **kwargs)\n           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/views.py\", line 509, in dispatch\n    response = self.handle_exception(exc)\n               ^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/views.py\", line 469, in handle_exception\n    self.raise_uncaught_exception(exc)\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/views.py\", line 480, in raise_uncaught_exception\n    raise exc\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/views.py\", line 506, in dispatch\n    response = handler(request, *args, **kwargs)\n               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/mixins.py\", line 43, in list\n    return self.get_paginated_response(serializer.data)\n                                       ^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py\", line 768, in data\n    ret = super().data\n          ^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py\", line 253, in data\n    self._data = self.to_representation(self.instance)\n                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py\", line 686, in to_representation\n    return [\n           ^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py\", line 687, in <listcomp>\n    self.child.to_representation(item) for item in iterable\n    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py\", line 522, in to_representation\n    ret[field.field_name] = field.to_representation(attribute)\n                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py\", line 686, in to_representation\n    return [\n           ^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py\", line 687, in <listcomp>\n    self.child.to_representation(item) for item in iterable\n    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/serializers.py\", line 509, in to_representation\n    attribute = field.get_attribute(instance)\n                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/fields.py\", line 446, in get_attribute\n    return get_attribute(instance, self.source_attrs)\n           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/local/lib/python3.11/site-packages/rest_framework/fields.py\", line 96, in get_attribute\n    instance = getattr(instance, attr)\n               ^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/authentik/core/models.py\", line 231, in avatar\n    return get_avatar(self)\n           ^^^^^^^^^^^^^^^^\n  File \"/authentik/lib/avatars.py\", line 178, in get_avatar\n    avatar = mode_map[mode](user, mode)\n             ^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/authentik/lib/avatars.py\", line 153, in avatar_mode_generated\n    svg = generate_avatar_from_name(user.name if user.name != \"\" else \"a k\")\n          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/authentik/lib/avatars.py\", line 110, in generate_avatar_from_name\n    initials += name_parts[-1]\n                ~~~~~~~~~~^^^^\nbuiltins.IndexError: list index out of range",
    "http_request": {
        "args": {
            "ordering": "name"
        },
        "path": "/api/v3/core/groups/",
        "method": "GET"
    }
}
```
Probaby related https://github.com/goauthentik/authentik/blob/main/authentik/lib/avatars.py#L105 as we don't have names in Authentik.



Discussion:

Resolving patch:
diff --git a/authentik/lib/avatars.py b/authentik/lib/avatars.py
--- a/authentik/lib/avatars.py
+++ b/authentik/lib/avatars.py
@@ -154,7 +154,7 @@ def generate_avatar_from_name(
 
 def avatar_mode_generated(user: "User", mode: str) -> Optional[str]:
     """Wrapper that converts generated avatar to base64 svg"""
-    svg = generate_avatar_from_name(user.name if user.name != "" else "a k")
+    svg = generate_avatar_from_name(user.name if user.name.strip() != "" else "a k")
     return f"data:image/svg+xml;base64,{b64encode(svg.encode('utf-8')).decode('utf-8')}"
 
 


Test patch: