From cbc4874b0ef7e452661cc598db4d681f2b8ba963 Mon Sep 17 00:00:00 2001
From: Antoine Lambert <anlambert@softwareheritage.org>
Date: Mon, 19 Jun 2023 15:48:43 +0200
Subject: [PATCH] django/utils: Add conversion functions between django and
 keycloak ids

Django uses integer identifiers while keycloak uses UUIDs so add some
utility functions to convert back and forth between the two.
---
 swh/auth/django/utils.py            | 28 +++++++++++++++++++++++++++-
 swh/auth/tests/django/test_utils.py |  9 +++++++++
 2 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/swh/auth/django/utils.py b/swh/auth/django/utils.py
index aad1729..78b5a1c 100644
--- a/swh/auth/django/utils.py
+++ b/swh/auth/django/utils.py
@@ -5,6 +5,7 @@
 
 from datetime import datetime, timedelta
 from typing import Any, Dict, Optional
+from uuid import UUID
 
 from django.conf import settings
 from django.contrib.auth.models import Group
@@ -15,6 +16,31 @@ from swh.auth.django.models import OIDCUser
 from swh.auth.keycloak import ExpiredSignatureError, KeycloakOpenIDConnect
 
 
+def keycloak_uuid_to_django_id(keycloak_uuid: str) -> int:
+    """Convert keycloak user uuid to its django integer id.
+
+    Args:
+        keycloak_uuid: UUID identifier of a Keycloak user
+
+    Returns:
+        Django integer identifier for the user
+
+    """
+    return UUID(keycloak_uuid).int
+
+
+def django_id_to_keycloak_uuid(django_id: int) -> str:
+    """Convert django user integer id to its keycloak uuid.
+
+    Args:
+        django_id: Integer identifier of a django user
+
+    Returns:
+        Keycloak UUID identifier for the user
+    """
+    return str(UUID(int=django_id))
+
+
 def oidc_user_from_decoded_token(
     decoded_token: Dict[str, Any], client_id: Optional[str] = None
 ) -> OIDCUser:
@@ -32,7 +58,7 @@ def oidc_user_from_decoded_token(
     # compute an integer user identifier for Django User model
     # by concatenating all groups of the UUID4 user identifier
     # generated by Keycloak and converting it from hex to decimal
-    user_id = int("".join(decoded_token["sub"].split("-")), 16)
+    user_id = keycloak_uuid_to_django_id(decoded_token["sub"])
 
     # create a Django user that will not be saved to database
     user = OIDCUser(
diff --git a/swh/auth/tests/django/test_utils.py b/swh/auth/tests/django/test_utils.py
index 5e899d2..2ca1bc8 100644
--- a/swh/auth/tests/django/test_utils.py
+++ b/swh/auth/tests/django/test_utils.py
@@ -5,12 +5,15 @@
 
 from copy import copy
 from datetime import datetime
+import uuid
 
 from django.test import override_settings
 import pytest
 
 from swh.auth.django.utils import (
+    django_id_to_keycloak_uuid,
     keycloak_oidc_client,
+    keycloak_uuid_to_django_id,
     oidc_user_from_decoded_token,
     oidc_user_from_profile,
 )
@@ -130,3 +133,9 @@ def test_keycloak_oidc_client_parameters_from_django_settings():
     assert kc_oidc_client.server_url == SERVER_URL
     assert kc_oidc_client.realm_name == REALM_NAME
     assert kc_oidc_client.client_id == CLIENT_ID
+
+
+def test_django_id_to_keycloak_uuid():
+    keycloak_uuid = str(uuid.uuid4())
+    django_id = keycloak_uuid_to_django_id(keycloak_uuid)
+    assert django_id_to_keycloak_uuid(django_id) == keycloak_uuid
-- 
GitLab