[go: nahoru, domu]

Skip to content

Commit

Permalink
feat(auth): ability to delete provider in auth (#579)
Browse files Browse the repository at this point in the history
* [add] ability to delete provider in auth

* [fix] pylint

* [fix] tests

* [fix] tests

* fix comments

* fix tests

* fix lint

* [fix] address comments
  • Loading branch information
hardikns committed Oct 5, 2021
1 parent f38c5f7 commit 0a11d07
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 2 deletions.
2 changes: 2 additions & 0 deletions firebase_admin/_auth_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,8 @@ def update_user(self, uid, **kwargs): # pylint: disable=differing-param-doc
valid_since: An integer signifying the seconds since the epoch (optional). This field
is set by ``revoke_refresh_tokens`` and it is discouraged to set this field
directly.
providers_to_delete: The list of provider IDs to unlink,
eg: 'google.com', 'password', etc.
Returns:
UserRecord: An updated UserRecord instance for the user.
Expand Down
9 changes: 9 additions & 0 deletions firebase_admin/_auth_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,15 @@ def validate_action_type(action_type):
Valid values are {1}'.format(action_type, ', '.join(VALID_EMAIL_ACTION_TYPES)))
return action_type

def validate_provider_ids(provider_ids, required=False):
if not provider_ids:
if required:
raise ValueError('Invalid provider IDs. Provider ids should be provided')
return []
for provider_id in provider_ids:
validate_provider_id(provider_id, True)
return provider_ids

def build_update_mask(params):
"""Creates an update mask list from the given dictionary."""
mask = []
Expand Down
8 changes: 6 additions & 2 deletions firebase_admin/_user_mgt.py
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,7 @@ def create_user(self, uid=None, display_name=None, email=None, phone_number=None

def update_user(self, uid, display_name=None, email=None, phone_number=None,
photo_url=None, password=None, disabled=None, email_verified=None,
valid_since=None, custom_claims=None):
valid_since=None, custom_claims=None, providers_to_delete=None):
"""Updates an existing user account with the specified properties"""
payload = {
'localId': _auth_utils.validate_uid(uid, required=True),
Expand All @@ -700,6 +700,7 @@ def update_user(self, uid, display_name=None, email=None, phone_number=None,
}

remove = []
remove_provider = _auth_utils.validate_provider_ids(providers_to_delete)
if display_name is not None:
if display_name is DELETE_ATTRIBUTE:
remove.append('DISPLAY_NAME')
Expand All @@ -715,7 +716,7 @@ def update_user(self, uid, display_name=None, email=None, phone_number=None,

if phone_number is not None:
if phone_number is DELETE_ATTRIBUTE:
payload['deleteProvider'] = ['phone']
remove_provider.append('phone')
else:
payload['phoneNumber'] = _auth_utils.validate_phone(phone_number)

Expand All @@ -726,6 +727,9 @@ def update_user(self, uid, display_name=None, email=None, phone_number=None,
custom_claims, dict) else custom_claims
payload['customAttributes'] = _auth_utils.validate_custom_claims(json_claims)

if remove_provider:
payload['deleteProvider'] = list(set(remove_provider))

payload = {k: v for k, v in payload.items() if v is not None}
body, http_resp = self._make_request('post', '/accounts:update', json=payload)
if not body or not body.get('localId'):
Expand Down
8 changes: 8 additions & 0 deletions integration/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,14 @@ def test_disable_user(new_user_with_params):
assert user.disabled is True
assert len(user.provider_data) == 1

def test_remove_provider(new_user_with_provider):
provider_ids = [provider.provider_id for provider in new_user_with_provider.provider_data]
assert 'google.com' in provider_ids
user = auth.update_user(new_user_with_provider, providers_to_delete=['google.com'])
assert user.uid == new_user_with_params.uid
new_provider_ids = [provider.provider_id for provider in user.provider_data]
assert 'google.com' not in new_provider_ids

def test_delete_user():
user = auth.create_user()
auth.delete_user(user.uid)
Expand Down
17 changes: 17 additions & 0 deletions tests/test_user_mgt.py
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,23 @@ def test_update_user_valid_since(self, user_mgt_app, arg):
request = json.loads(recorder[0].body.decode())
assert request == {'localId': 'testuser', 'validSince': int(arg)}

@pytest.mark.parametrize('arg', [['phone'], ['google.com', 'phone']])
def test_update_user_delete_provider(self, user_mgt_app, arg):
user_mgt, recorder = _instrument_user_manager(user_mgt_app, 200, '{"localId":"testuser"}')
user_mgt.update_user('testuser', providers_to_delete=arg)
request = json.loads(recorder[0].body.decode())
assert set(request['deleteProvider']) == set(arg)

@pytest.mark.parametrize('arg', [[], ['phone'], ['google.com'], ['google.com', 'phone']])
def test_update_user_delete_provider_and_phone(self, user_mgt_app, arg):
user_mgt, recorder = _instrument_user_manager(user_mgt_app, 200, '{"localId":"testuser"}')
user_mgt.update_user('testuser',
providers_to_delete=arg,
phone_number=auth.DELETE_ATTRIBUTE)
request = json.loads(recorder[0].body.decode())
assert 'phone' in request['deleteProvider']
assert len(set(request['deleteProvider'])) == len(request['deleteProvider'])
assert set(arg) - set(request['deleteProvider']) == set()

class TestSetCustomUserClaims:

Expand Down

0 comments on commit 0a11d07

Please sign in to comment.