Skip to content

Commit aa092d6

Browse files
authored
Handle authenticator slug collision
Adds random hex suffix to generated slug if it collides with an existing one (normally due to authenticator name change).
1 parent 3dc1dca commit aa092d6

File tree

3 files changed

+27
-4
lines changed

3 files changed

+27
-4
lines changed

ansible_base/authentication/authenticator_plugins/utils.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from functools import lru_cache
33
from glob import glob
44
from os.path import basename, isfile, join
5+
from typing import Optional
56

67
from django.conf import settings
78
from django.utils.text import slugify
@@ -52,5 +53,7 @@ def get_authenticator_urls(authenticator_type: str) -> list:
5253
return []
5354

5455

55-
def generate_authenticator_slug(type: str, name: str) -> str:
56-
return slugify(f"{type.replace('.', ' ')}__{name}")
56+
def generate_authenticator_slug(type: str, name: str, suffix: Optional[str] = None) -> str:
57+
clean_type = f"{type.replace('.', ' ')}"
58+
slug_template = f"{clean_type}__{name}" if not suffix else f"{clean_type}__{name}__{suffix}"
59+
return slugify(slug_template)

ansible_base/authentication/models/authenticator.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import secrets
2+
13
from django.db.models import SET_NULL, ForeignKey, JSONField, fields
24

35
from ansible_base.authentication.authenticator_plugins.utils import generate_authenticator_slug, get_authenticator_plugin
@@ -61,8 +63,8 @@ def save(self, *args, **kwargs):
6163

6264
if not self.slug:
6365
self.slug = generate_authenticator_slug(self.type, self.name)
64-
# TODO: What happens if computed slug is not unique?
65-
# You would have to create an adapter with a name, rename it and then create a new one with the same name
66+
if Authenticator.objects.filter(slug=self.slug).count():
67+
self.slug = generate_authenticator_slug(self.type, self.name, secrets.token_hex(4))
6668
super().save(*args, **kwargs)
6769

6870
def __str__(self):

test_app/tests/authentication/models/test_authenticator.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import re
12
from unittest import mock
23

34
import pytest
@@ -32,3 +33,20 @@ def test_authenticator_order_on_create_update():
3233

3334
auth3 = Authenticator.objects.create(name='Authenticator 3', type=auth_type)
3435
assert auth3.order == 12
36+
37+
38+
@pytest.mark.django_db
39+
def test_dupe_slug(ldap_authenticator):
40+
ldap_auth = Authenticator.objects.first()
41+
ldap_slug = ldap_auth.slug
42+
43+
dupe = Authenticator()
44+
dupe.name = ldap_auth.name
45+
dupe.type = ldap_auth.type
46+
47+
ldap_auth.name = "changed"
48+
ldap_auth.save()
49+
50+
dupe.save()
51+
pattern = ldap_slug + '[a-z0-9_]{8}'
52+
assert re.match(pattern, dupe.slug) is not None

0 commit comments

Comments
 (0)