Skip to content

Commit

Permalink
Update export script
Browse files Browse the repository at this point in the history
- Do not export inactive users, they have never logged in.
- Set OW4 userid on export
- Support exporting without password for updating a previous export
- Fix off-by one in number of scripts
  • Loading branch information
henrikhorluck committed Feb 28, 2024
1 parent 2ba3f8e commit a4b5092
Showing 1 changed file with 31 additions and 17 deletions.
48 changes: 31 additions & 17 deletions scripts/management/commands/auth0_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from django.core.management.base import BaseCommand

from apps.authentication.models import OnlineUser
from apps.authentication.models import Email, OnlineUser

ws = re.compile(r"\s+")

Expand Down Expand Up @@ -36,10 +36,12 @@ def extract_phone_number(u: OnlineUser) -> Optional[str]:

def create_auth0_user(u: OnlineUser):
if not u.has_usable_password:
print(f"Skipping {u}, no usable password")
print(f"Skipping {u.pk}, no usable password")
return None
if u.email is None or len(u.email) == 0:
print(f"Skipping {u}, no email")
emails = Email.objects.filter(user=u)
# print(u.email_user)
print(f"Skipping {u.pk}, no email or? {emails}")
return None
# if u.auth0_subject is not None:
# print(f"Skipping {u}, already migrated")
Expand All @@ -48,7 +50,7 @@ def create_auth0_user(u: OnlineUser):
try:
algorithm, iterations, salt, hash = u.password.split("$", 3)
except ValueError as e:
print(f"{e=}\n{u=}\n{u.password=}")
print(f"{e}\n{u.pk=}\n{u.password=}")
return None

# thank you https://community.auth0.com/t/wrong-password-for-imported-users-from-django/61105
Expand All @@ -58,24 +60,34 @@ def create_auth0_user(u: OnlineUser):
# we probably only use pbkdf2_sha256, in auth0 they use -
algorithm = algorithm.replace("_", "-")

id = str(uuid4())
u.auth0_subject = f"auth0|{id}"
user_previously_exported = True
if not u.auth0_subject:
user_previously_exported = False
id = str(uuid4())
u.auth0_subject = f"auth0|{id}"

auth0_user = {
"user_id": id,
"user_id": u.auth0_subject.split("|")[1],
"email": u.email,
"email_verified": u.is_active,
"given_name": u.first_name,
"family_name": u.last_name,
"name": f"{u.first_name} {u.last_name}",
"custom_password_hash": {
"user_metadata": {},
"app_metadata": {
"ow4_userid": u.pk,
},
}

if not user_previously_exported:
# we do not want to export passwords of existing users in auth0
# auth0 then just errors out, and users might not remember their passwords
auth0_user["custom_password_hash"] = {
"algorithm": "pbkdf2",
"hash": {
"encoding": "utf-8",
"value": f"$pbkdf2-sha256$i={iterations},l=32${salt}${hash}",
},
},
}
}

if len(u.first_name) == 0:
del auth0_user["given_name"]
Expand All @@ -84,21 +96,23 @@ def create_auth0_user(u: OnlineUser):
del auth0_user["family_name"]

if num := extract_phone_number(u):
auth0_user["mfa_factors"] = [{"phone": {"value": num}}]
auth0_user["user_metadata"]["phone"] = num

if len(auth0_user["user_metadata"]) == 0:
del auth0_user["user_metadata"]

return (u, auth0_user)


class Command(BaseCommand):
def handle(self, *args, **options):
users = [
create_auth0_user(u) for u in OnlineUser.objects.iterator(chunk_size=100)
]
qs = OnlineUser.objects.filter(is_active=True)
users = [create_auth0_user(u) for u in qs.iterator(chunk_size=100)]
users = [u for u in users if u is not None]
N = 700
for i in range(int(OnlineUser.objects.count() / 700)):
for i in range(int(qs.count() / N) + 1):
chunk = users[i * N : i * N + N]
OnlineUser.objects.bulk_update([u for (u, _) in chunk], ["auth0_subject"])
file = json.dumps([a0u for (_, a0u) in chunk])
with open(f"auth0_users_staging_{i}.json", "w") as f:
with open(f"auth0_users_prod_{i}.json", "w") as f:
f.write(file)

0 comments on commit a4b5092

Please sign in to comment.