Skip to content

Commit 4c3d802

Browse files
authored
Fix some attributes and state for KC export (#4370)
1 parent 85ea0b9 commit 4c3d802

File tree

3 files changed

+53
-21
lines changed

3 files changed

+53
-21
lines changed

keycloak_user_export/management/commands/migrate_users_to_keycloak.py

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import calendar
21
from urllib.parse import urljoin
32
import sys
43

@@ -62,6 +61,12 @@ def add_arguments(self, parser):
6261
"""parse arguments"""
6362

6463
# pylint: disable=expression-not-assigned
64+
parser.add_argument(
65+
"--verbose",
66+
help="Enable verbose logging",
67+
action="store_true",
68+
default=False,
69+
)
6570
parser.add_argument(
6671
"--client-id",
6772
required=True,
@@ -150,17 +155,12 @@ def _generate_keycloak_user_payload(self, user, keycloak_group_path):
150155
dict: user representation for use with the Keycloak partialImport Admin REST API endpoint.
151156
"""
152157
user_keycloak_payload = {
153-
"createdTimestamp": calendar.timegm(user.date_joined.timetuple()),
158+
"createdTimestamp": user.date_joined.timestamp() * 1000,
154159
"username": user.email,
155160
"enabled": True,
156-
"totp": False,
157161
"emailVerified": True,
158162
"email": user.email,
159-
"credentials": [],
160-
"disableableCredentialTypes": [],
161-
"requiredActions": [],
162-
"realmRoles": ["default-roles-master"],
163-
"notBefore": 0,
163+
"realmRoles": [f"default-roles-{settings.KEYCLOAK_REALM_NAME}"],
164164
"groups": [keycloak_group_path] if keycloak_group_path else [],
165165
"attributes": {
166166
"fullName": user.profile.name,
@@ -190,7 +190,23 @@ def _verify_environment_variables_configured(self):
190190
"KEYCLOAK_REALM_NAME must be defined as an environment variable."
191191
)
192192

193+
def _log_api_call(self, response):
194+
"""Log the API call to keycloak"""
195+
status_code = response.status_code
196+
197+
if not self.verbose and status_code == 200:
198+
return
199+
200+
log_out = self.stdout if status_code == 200 else self.stderr
201+
202+
log_out.write(f"{response.request.method} {response.request.url}")
203+
log_out.write(f"Status code: {status_code}")
204+
log_out.write(f"Request:\t{response.request.body.decode('utf-8')}")
205+
log_out.write(f"Response:\t{response.text}")
206+
193207
def handle(self, *args, **kwargs):
208+
self.verbose = kwargs["verbose"]
209+
194210
self._verify_environment_variables_configured()
195211

196212
keycloak_partial_import_url = f"{settings.KEYCLOAK_BASE_URL}/admin/realms/{settings.KEYCLOAK_REALM_NAME}/partialImport"
@@ -239,14 +255,9 @@ def handle(self, *args, **kwargs):
239255
)
240256
response = session.post(keycloak_partial_import_url, json=payload)
241257

242-
# If the response from Keycloak is not 200, print out an error and move on to
243-
# the next batch of users to export.
244-
if response.status_code != 200:
245-
self.stderr.write("Error calling Keycloak REST API, returned:")
246-
self.stderr.write(f"Status code: {response.status_code}")
247-
self.stderr.write("Content:")
248-
self.stderr.write(response.text)
249-
else:
258+
self._log_api_call(response)
259+
260+
if response.status_code == 200:
250261
user_synced_with_keycloak_records = []
251262
keycloak_response_body = response.json()
252263

@@ -258,12 +269,14 @@ def handle(self, *args, **kwargs):
258269
item["resourceName"]: item for item in keycloak_results
259270
}
260271
for user in batch:
261-
if (
262-
keycloak_results_email_key_dict[user.email]["action"]
263-
== "ADDED"
264-
):
272+
action = keycloak_results_email_key_dict[user.email]["action"]
273+
if action in ("ADDED", "SKIPPED"):
265274
user_synced_with_keycloak_records.append(
266-
UserExportToKeycloak(user=user)
275+
UserExportToKeycloak(user=user, action=action)
276+
)
277+
else:
278+
self.stderr.write(
279+
f"Unexpected action '{action} for user '{user.email}"
267280
)
268281
UserExportToKeycloak.objects.bulk_create(
269282
user_synced_with_keycloak_records, ignore_conflicts=True
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 4.2.15 on 2024-12-18 18:14
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
("keycloak_user_export", "0001_initial"),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name="userexporttokeycloak",
15+
name="action",
16+
field=models.CharField(default="ADDED", max_length=20),
17+
),
18+
]

keycloak_user_export/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ class UserExportToKeycloak(models.Model):
1111
"""
1212

1313
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
14+
action = models.CharField(max_length=20, null=False, default="ADDED")

0 commit comments

Comments
 (0)