You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by cc...@apache.org on 2026/06/19 20:12:46 UTC
(allura) 03/03: [#8610] Implement field level encryption for Users email addresses
This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch cc/8610-part2
in repository https://gitbox.apache.org/repos/asf/allura.git
commit 16b2bc9f39e105914a8b2c5d61a33ac9d79552ca
Author: Carlos Cruz <ca...@slashdotmedia.com>
AuthorDate: Thu Jun 18 20:59:58 2026 +0000
[#8610] Implement field level encryption for Users email addresses
---
Allura/allura/model/auth.py | 23 +++--------------------
Allura/allura/tests/model/test_auth.py | 4 ++--
2 files changed, 5 insertions(+), 22 deletions(-)
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index d9d26baf1..4f526a5ae 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -38,8 +38,8 @@
from tg import tmpl_context as c, app_globals as g
from tg import request
from ming import schema as S
-from ming.odm import session, state, MapperExtension
-from ming.odm import DecryptedProperty, FieldProperty, RelationProperty, ForeignIdProperty
+from ming.odm import session, state
+from ming.odm import FieldProperty, RelationProperty, ForeignIdProperty, DecryptedProperty, DecryptedListProperty
from ming.odm.declarative import MappedClass
from ming.odm.odmsession import ThreadLocalODMSession
from ming.utils import LazyProperty
@@ -266,15 +266,6 @@ def get_decrypted(self, instance):
return super().__get__(instance, type(instance))
-class UserEmailAddressesMapperExtension(MapperExtension):
-
- def before_insert(self, obj, state, sess):
- obj.sync_email_addresses_encrypted()
-
- def before_update(self, obj, state, sess):
- obj.sync_email_addresses_encrypted()
-
-
class User(MappedClass, ActivityNode, ActivityObject, SearchIndexable):
SALT_LEN = 8
@@ -283,7 +274,6 @@ class __mongometa__:
session = main_orm_session
indexes = ['tool_data.AuthPasswordReset.hash']
unique_indexes = ['username']
- extensions = [UserEmailAddressesMapperExtension]
custom_indexes = [
dict(fields=('tool_data.phone_verification.number_hash',), sparse=True),
]
@@ -295,7 +285,7 @@ class __mongometa__:
_id = FieldProperty(S.ObjectId)
sfx_userid = FieldProperty(S.Deprecated)
username = FieldProperty(str)
- email_addresses = FieldProperty([str])
+ email_addresses = DecryptedListProperty('email_addresses_encrypted')
email_addresses_encrypted = FieldProperty([S.Binary], if_missing=[])
password = FieldProperty(str) # hashed
last_password_updated = FieldProperty(datetime) # to access, use AuthProvider's get_last_password_updated
@@ -798,13 +788,6 @@ def set_tool_data(self, tool, **kw):
d.update(kw)
state(self).soil()
- @classmethod
- def encrypt_email_addresses(cls, email_addresses):
- return [cls.encr(addr) if addr is not None else None for addr in email_addresses or []]
-
- def sync_email_addresses_encrypted(self):
- self.email_addresses_encrypted = type(self).encrypt_email_addresses(self.email_addresses)
-
def address_object(self, addr):
return EmailAddress.get(email=addr, claimed_by_user_id=self._id)
diff --git a/Allura/allura/tests/model/test_auth.py b/Allura/allura/tests/model/test_auth.py
index 014cf0021..15a1b20aa 100644
--- a/Allura/allura/tests/model/test_auth.py
+++ b/Allura/allura/tests/model/test_auth.py
@@ -445,7 +445,7 @@ def test_email_addresses_encrypted_is_populated_on_creation(self):
]
assert user.email_addresses == ['primary@example.com', None, 'secondary@example.com']
assert user.email_addresses_encrypted == expected_encrypted
- assert state(user).document['email_addresses'] == ['primary@example.com', None, 'secondary@example.com']
+ assert 'email_addresses' not in state(user).document
assert state(user).document['email_addresses_encrypted'] == expected_encrypted
def test_email_addresses_encrypted_is_synced_on_update(self):
@@ -464,7 +464,7 @@ def test_email_addresses_encrypted_is_synced_on_update(self):
]
assert user.email_addresses == ['keep@example.com', 'add@example.com']
assert user.email_addresses_encrypted == expected_encrypted
- assert state(user).document['email_addresses'] == ['keep@example.com', 'add@example.com']
+ assert 'email_addresses' not in state(user).document
assert state(user).document['email_addresses_encrypted'] == expected_encrypted
def test_set_display_name_pref_updates_encrypted_field_and_cache(self):