Skip to content

Commit

Permalink
Fix some attributes and state for KC export (#4370)
Browse files Browse the repository at this point in the history
  • Loading branch information
rhysyngsun authored Dec 18, 2024
1 parent 85ea0b9 commit 4c3d802
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import calendar
from urllib.parse import urljoin
import sys

Expand Down Expand Up @@ -62,6 +61,12 @@ def add_arguments(self, parser):
"""parse arguments"""

# pylint: disable=expression-not-assigned
parser.add_argument(
"--verbose",
help="Enable verbose logging",
action="store_true",
default=False,
)
parser.add_argument(
"--client-id",
required=True,
Expand Down Expand Up @@ -150,17 +155,12 @@ def _generate_keycloak_user_payload(self, user, keycloak_group_path):
dict: user representation for use with the Keycloak partialImport Admin REST API endpoint.
"""
user_keycloak_payload = {
"createdTimestamp": calendar.timegm(user.date_joined.timetuple()),
"createdTimestamp": user.date_joined.timestamp() * 1000,
"username": user.email,
"enabled": True,
"totp": False,
"emailVerified": True,
"email": user.email,
"credentials": [],
"disableableCredentialTypes": [],
"requiredActions": [],
"realmRoles": ["default-roles-master"],
"notBefore": 0,
"realmRoles": [f"default-roles-{settings.KEYCLOAK_REALM_NAME}"],
"groups": [keycloak_group_path] if keycloak_group_path else [],
"attributes": {
"fullName": user.profile.name,
Expand Down Expand Up @@ -190,7 +190,23 @@ def _verify_environment_variables_configured(self):
"KEYCLOAK_REALM_NAME must be defined as an environment variable."
)

def _log_api_call(self, response):
"""Log the API call to keycloak"""
status_code = response.status_code

if not self.verbose and status_code == 200:
return

log_out = self.stdout if status_code == 200 else self.stderr

log_out.write(f"{response.request.method} {response.request.url}")
log_out.write(f"Status code: {status_code}")
log_out.write(f"Request:\t{response.request.body.decode('utf-8')}")
log_out.write(f"Response:\t{response.text}")

def handle(self, *args, **kwargs):
self.verbose = kwargs["verbose"]

self._verify_environment_variables_configured()

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

# If the response from Keycloak is not 200, print out an error and move on to
# the next batch of users to export.
if response.status_code != 200:
self.stderr.write("Error calling Keycloak REST API, returned:")
self.stderr.write(f"Status code: {response.status_code}")
self.stderr.write("Content:")
self.stderr.write(response.text)
else:
self._log_api_call(response)

if response.status_code == 200:
user_synced_with_keycloak_records = []
keycloak_response_body = response.json()

Expand All @@ -258,12 +269,14 @@ def handle(self, *args, **kwargs):
item["resourceName"]: item for item in keycloak_results
}
for user in batch:
if (
keycloak_results_email_key_dict[user.email]["action"]
== "ADDED"
):
action = keycloak_results_email_key_dict[user.email]["action"]
if action in ("ADDED", "SKIPPED"):
user_synced_with_keycloak_records.append(
UserExportToKeycloak(user=user)
UserExportToKeycloak(user=user, action=action)
)
else:
self.stderr.write(
f"Unexpected action '{action} for user '{user.email}"
)
UserExportToKeycloak.objects.bulk_create(
user_synced_with_keycloak_records, ignore_conflicts=True
Expand Down
18 changes: 18 additions & 0 deletions keycloak_user_export/migrations/0002_add_export_action.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.2.15 on 2024-12-18 18:14

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("keycloak_user_export", "0001_initial"),
]

operations = [
migrations.AddField(
model_name="userexporttokeycloak",
name="action",
field=models.CharField(default="ADDED", max_length=20),
),
]
1 change: 1 addition & 0 deletions keycloak_user_export/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ class UserExportToKeycloak(models.Model):
"""

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

0 comments on commit 4c3d802

Please sign in to comment.