Skip to content

Commit

Permalink
Merge pull request #58 from geoadmin/feat-PB-1288-validate-email
Browse files Browse the repository at this point in the history
PB-1288 Set e-mail as validated in cognito
  • Loading branch information
msom authored Dec 19, 2024
2 parents 9ffabdd + 4abaf9d commit 8c4333a
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 13 deletions.
42 changes: 32 additions & 10 deletions app/cognito/utils/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ def create_user(self, username: str, preferred_username: str, email: str) -> boo
Returns False, if a (managed or unmanaged) user already exist.
Marks the provided email as verified because the newly created user will receive an email
with a temporary password that they must change upon logging in. If the email is invalid,
the user will not receive the password and therefore cannot log in, ensuring the email's
validity.
"""

user = self.get_user(username, return_unmanaged=True)
Expand All @@ -82,6 +87,8 @@ def create_user(self, username: str, preferred_username: str, email: str) -> boo
Username=username,
UserAttributes=[{
"Name": "email", "Value": email
}, {
"Name": "email_verified", "Value": "true"
}, {
"Name": "preferred_username", "Value": preferred_username
}, {
Expand All @@ -108,23 +115,38 @@ def delete_user(self, username: str) -> bool:
def update_user(self, username: str, preferred_username: str, email: str) -> bool:
""" Update the user with the given cognito username.
Only updates changed attributes.
If the email is changed, it is marked as verified, and the user's password is reset. The
user must reset the password using the new email before being able to log in. If the email
is invalid, the user cannot complete the password reset, ensuring the email's validity.
Returns False, if the user does not exist or doesn't have the managed flag.
"""

user = self.get_user(username)
if user is not None:
if user is None:
return False

old_attributes = user_attributes_to_dict(user['UserAttributes'])
new_attributes: list[AttributeTypeTypeDef] = []
reset_password = False
if old_attributes.get('preferred_username') != preferred_username:
new_attributes.append({'Name': 'email', 'Value': email})
new_attributes.append({'Name': 'email_verified', 'Value': 'true'})
reset_password = True
if old_attributes.get('email') != email:
new_attributes.append({'Name': 'preferred_username', 'Value': preferred_username})
if new_attributes:
self.client.admin_update_user_attributes(
UserPoolId=self.user_pool_id,
Username=username,
UserAttributes=[{
"Name": "email", "Value": email
}, {
"Name": "preferred_username", "Value": preferred_username
}]
UserPoolId=self.user_pool_id, Username=username, UserAttributes=new_attributes
)
return True
return False

if reset_password:
self.client.admin_reset_user_password(UserPoolId=self.user_pool_id, Username=username)

return True

def enable_user(self, username: str) -> bool:
"""Enable the user with the given cognito username.
Expand Down
27 changes: 24 additions & 3 deletions app/tests/cognito/test_cognito_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ def test_create_user_creates_managed(boto3, cognito_user_response_factory):
Username='2ihg2ox304po',
UserAttributes=[{
'Name': 'email', 'Value': 'test@example.org'
}, {
'Name': 'email_verified', 'Value': 'true'
}, {
'Name': 'preferred_username', 'Value': '1234'
}, {
Expand Down Expand Up @@ -172,18 +174,37 @@ def test_update_user_updates_managed(boto3, cognito_user_response_factory):
)

client = Client()
updated = client.update_user('2ihg2ox304po', '1234', 'test@example.org')
updated = client.update_user('2ihg2ox304po', '5678', 'new@example.org')
assert updated is True
assert '().admin_update_user_attributes' in [call[0] for call in boto3.mock_calls]
assert '().admin_reset_user_password' in [call[0] for call in boto3.mock_calls]
assert call().admin_update_user_attributes(
UserPoolId=client.user_pool_id,
Username='2ihg2ox304po',
UserAttributes=[{
'Name': 'email', 'Value': 'test@example.org'
'Name': 'email', 'Value': 'new@example.org'
}, {
'Name': 'preferred_username', 'Value': '1234'
'Name': 'email_verified', 'Value': 'true'
}, {
'Name': 'preferred_username', 'Value': '5678'
}]
) in boto3.mock_calls
assert call().admin_reset_user_password(
UserPoolId=client.user_pool_id, Username='2ihg2ox304po'
) in boto3.mock_calls


@patch('cognito.utils.client.client')
def test_update_user_does_not_update_unchanged_managed(boto3, cognito_user_response_factory):
boto3.return_value.admin_get_user.return_value = cognito_user_response_factory(
'2ihg2ox304po', '1234', managed=True, attributes_key='UserAttributes'
)

client = Client()
updated = client.update_user('2ihg2ox304po', '1234', 'test@example.org')
assert updated is True
assert '().admin_update_user_attributes' not in [call[0] for call in boto3.mock_calls]
assert '().admin_reset_user_password' not in [call[0] for call in boto3.mock_calls]


@patch('cognito.utils.client.client')
Expand Down

0 comments on commit 8c4333a

Please sign in to comment.