From e49b40719902ada80824d899b617b788fb44dfef Mon Sep 17 00:00:00 2001 From: 0z5a Date: Sat, 14 Nov 2026 23:52:57 +0100 Subject: [PATCH] fix(auth): Clear redacted password hashes returned by list_users() B64_REDACTED was the bytes value base64.b64encode(b'REDACTED'), but the passwordHash field of the JSON response is a str, so the comparison was always false and ExportedUserRecord.password_hash returned the "UkVEQUNURUQ=" placeholder instead of None when the service account cannot read password hashes. Make B64_REDACTED a str and feed the existing test a str value, as the API returns it. --- firebase_admin/_user_mgt.py | 2 +- tests/test_user_mgt.py | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/firebase_admin/_user_mgt.py b/firebase_admin/_user_mgt.py index 4d852500b..34007d13b 100644 --- a/firebase_admin/_user_mgt.py +++ b/firebase_admin/_user_mgt.py @@ -32,7 +32,7 @@ MAX_LIST_USERS_RESULTS = 1000 MAX_IMPORT_USERS_SIZE = 1000 -B64_REDACTED = base64.b64encode(b'REDACTED') +B64_REDACTED = base64.b64encode(b'REDACTED').decode() class Sentinel: diff --git a/tests/test_user_mgt.py b/tests/test_user_mgt.py index 4623f5e54..178c1dbd1 100644 --- a/tests/test_user_mgt.py +++ b/tests/test_user_mgt.py @@ -215,7 +215,7 @@ def test_exported_record_empty_password(self): def test_redacted_passwords_cleared(self): user = auth.ExportedUserRecord({ 'localId': 'user', - 'passwordHash': base64.b64encode(b'REDACTED'), + 'passwordHash': base64.b64encode(b'REDACTED').decode(), }) assert user.password_hash is None @@ -947,6 +947,22 @@ def test_list_users_no_users_response(self, user_mgt_app): users = list(user for user in page.iterate_all()) assert len(users) == 0 + def test_list_users_redacted_password_hash(self, user_mgt_app): + response = {'users': [ + { + 'localId': 'redacted', + 'passwordHash': base64.b64encode(b'REDACTED').decode(), + 'salt': 'passwordSalt', + }, + {'localId': 'user', 'passwordHash': 'passwordHash', 'salt': 'passwordSalt'}, + ]} + _instrument_user_manager(user_mgt_app, 200, json.dumps(response)) + page = auth.list_users(app=user_mgt_app) + assert len(page.users) == 2 + redacted, user = page.users + assert redacted.password_hash is None + assert user.password_hash == 'passwordHash' + def test_list_users_with_max_results(self, user_mgt_app): _, recorder = _instrument_user_manager(user_mgt_app, 200, MOCK_LIST_USERS_RESPONSE) page = auth.list_users(max_results=500, app=user_mgt_app)