Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#644 fixed allowing default provider config for tenants #745

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
Binary file added firebase_admin/.DS_Store
Binary file not shown.
8 changes: 7 additions & 1 deletion firebase_admin/_user_mgt.py
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,7 @@ def update_user(self, uid, display_name=None, email=None, phone_number=None,
"""Updates an existing user account with the specified properties"""
payload = {
'localId': _auth_utils.validate_uid(uid, required=True),
'email': _auth_utils.validate_email(email),
'email': _auth_utils.validate_email(email) if email is not DELETE_ATTRIBUTE else None,
'password': _auth_utils.validate_password(password),
'validSince': _auth_utils.validate_timestamp(valid_since, 'valid_since'),
'emailVerified': bool(email_verified) if email_verified is not None else None,
Expand Down Expand Up @@ -720,6 +720,12 @@ def update_user(self, uid, display_name=None, email=None, phone_number=None,
else:
payload['phoneNumber'] = _auth_utils.validate_phone(phone_number)

if email is not None:
if email is DELETE_ATTRIBUTE:
remove_provider.append('email')
else:
payload['email'] = _auth_utils.validate_email(email)

if custom_claims is not None:
if custom_claims is DELETE_ATTRIBUTE:
custom_claims = {}
Expand Down
26 changes: 20 additions & 6 deletions firebase_admin/tenant_mgt.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def get_tenant(tenant_id, app=None):


def create_tenant(
display_name, allow_password_sign_up=None, enable_email_link_sign_in=None, app=None):
display_name, allow_password_sign_up=None, enable_email_link_sign_in=None, allow_default_provider=None, app=None):
"""Creates a new tenant from the given options.

Args:
Expand All @@ -101,6 +101,8 @@ def create_tenant(
provider (optional).
enable_email_link_sign_in: A boolean indicating whether to enable or disable email link
sign-in (optional). Disabling this makes the password required for email sign-in.
allow_default_provider: A boolean indicating whether to enable or disable default provider
sign-in (optional).
app: An App instance (optional).

Returns:
Expand All @@ -113,12 +115,12 @@ def create_tenant(
tenant_mgt_service = _get_tenant_mgt_service(app)
return tenant_mgt_service.create_tenant(
display_name=display_name, allow_password_sign_up=allow_password_sign_up,
enable_email_link_sign_in=enable_email_link_sign_in)
enable_email_link_sign_in=enable_email_link_sign_in, allow_default_provider=allow_default_provider)


def update_tenant(
tenant_id, display_name=None, allow_password_sign_up=None, enable_email_link_sign_in=None,
app=None):
allow_default_provider=None, app=None):
"""Updates an existing tenant with the given options.

Args:
Expand All @@ -128,6 +130,8 @@ def update_tenant(
provider.
enable_email_link_sign_in: A boolean indicating whether to enable or disable email link
sign-in. Disabling this makes the password required for email sign-in.
allow_default_provider: A boolean indicating whether to enable or disable default provider
sign-in (optional).
app: An App instance (optional).

Returns:
Expand All @@ -141,7 +145,7 @@ def update_tenant(
tenant_mgt_service = _get_tenant_mgt_service(app)
return tenant_mgt_service.update_tenant(
tenant_id, display_name=display_name, allow_password_sign_up=allow_password_sign_up,
enable_email_link_sign_in=enable_email_link_sign_in)
enable_email_link_sign_in=enable_email_link_sign_in, allow_default_provider=allow_default_provider)


def delete_tenant(tenant_id, app=None):
Expand Down Expand Up @@ -227,6 +231,10 @@ def allow_password_sign_up(self):
@property
def enable_email_link_sign_in(self):
return self._data.get('enableEmailLinkSignin', False)

@property
def allow_default_provider(self):
return self._data.get('allowDefaultProvider', False)


class _TenantManagementService:
Expand Down Expand Up @@ -272,7 +280,7 @@ def get_tenant(self, tenant_id):
return Tenant(body)

def create_tenant(
self, display_name, allow_password_sign_up=None, enable_email_link_sign_in=None):
self, display_name, allow_password_sign_up=None, enable_email_link_sign_in=None, allow_default_provider=None):
"""Creates a new tenant from the given parameters."""

payload = {'displayName': _validate_display_name(display_name)}
Expand All @@ -282,6 +290,9 @@ def create_tenant(
if enable_email_link_sign_in is not None:
payload['enableEmailLinkSignin'] = _auth_utils.validate_boolean(
enable_email_link_sign_in, 'enableEmailLinkSignin')
if allow_default_provider is not None:
payload['allowDefaultProvider'] = _auth_utils.validate_boolean(
allow_default_provider, 'allowDefaultProvider')

try:
body = self.client.body('post', '/tenants', json=payload)
Expand All @@ -292,7 +303,7 @@ def create_tenant(

def update_tenant(
self, tenant_id, display_name=None, allow_password_sign_up=None,
enable_email_link_sign_in=None):
enable_email_link_sign_in=None, allow_default_provider=None):
"""Updates the specified tenant with the given parameters."""
if not isinstance(tenant_id, str) or not tenant_id:
raise ValueError('Tenant ID must be a non-empty string.')
Expand All @@ -306,6 +317,9 @@ def update_tenant(
if enable_email_link_sign_in is not None:
payload['enableEmailLinkSignin'] = _auth_utils.validate_boolean(
enable_email_link_sign_in, 'enableEmailLinkSignin')
if allow_default_provider is not None:
payload['allowDefaultProvider'] = _auth_utils.validate_boolean(
allow_default_provider, 'allowDefaultProvider')

if not payload:
raise ValueError('At least one parameter must be specified for update.')
Expand Down
Binary file added integration/.DS_Store
Binary file not shown.
10 changes: 7 additions & 3 deletions integration/test_tenant_mgt.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ def sample_tenant():
tenant = tenant_mgt.create_tenant(
display_name='admin-python-tenant',
allow_password_sign_up=True,
enable_email_link_sign_in=True)
enable_email_link_sign_in=True,
allow_default_provider=True)
yield tenant
tenant_mgt.delete_tenant(tenant.tenant_id)

Expand All @@ -59,6 +60,7 @@ def test_get_tenant(sample_tenant):
assert tenant.display_name == 'admin-python-tenant'
assert tenant.allow_password_sign_up is True
assert tenant.enable_email_link_sign_in is True
assert tenant.allow_default_provider is True


def test_list_tenants(sample_tenant):
Expand All @@ -73,20 +75,22 @@ def test_list_tenants(sample_tenant):
assert result.display_name == 'admin-python-tenant'
assert result.allow_password_sign_up is True
assert result.enable_email_link_sign_in is True
assert result.allow_default_provider is True


def test_update_tenant():
tenant = tenant_mgt.create_tenant(
display_name='py-update-test', allow_password_sign_up=True, enable_email_link_sign_in=True)
display_name='py-update-test', allow_password_sign_up=True, enable_email_link_sign_in=True, allow_default_provider=True)
try:
tenant = tenant_mgt.update_tenant(
tenant.tenant_id, display_name='updated-py-tenant', allow_password_sign_up=False,
enable_email_link_sign_in=False)
enable_email_link_sign_in=False, allow_default_provider=False)
assert isinstance(tenant, tenant_mgt.Tenant)
assert tenant.tenant_id == tenant.tenant_id
assert tenant.display_name == 'updated-py-tenant'
assert tenant.allow_password_sign_up is False
assert tenant.enable_email_link_sign_in is False
assert tenant.allow_default_provider is False
finally:
tenant_mgt.delete_tenant(tenant.tenant_id)

Expand Down
Binary file added snippets/.DS_Store
Binary file not shown.
Binary file added snippets/auth/.DS_Store
Binary file not shown.
3 changes: 2 additions & 1 deletion snippets/auth/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -777,7 +777,8 @@ def create_tenant():
tenant = tenant_mgt.create_tenant(
display_name='myTenant1',
enable_email_link_sign_in=True,
allow_password_sign_up=True)
allow_password_sign_up=True,
allow_default_provider=True)

print('Created tenant:', tenant.tenant_id)
# [END create_tenant]
Expand Down
Binary file added tests/.DS_Store
Binary file not shown.
42 changes: 33 additions & 9 deletions tests/test_tenant_mgt.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
"name": "projects/mock-project-id/tenants/tenant-id",
"displayName": "Test Tenant",
"allowPasswordSignup": true,
"enableEmailLinkSignin": true
"enableEmailLinkSignin": true,
"allowDefaultProvider": true
}"""

TENANT_NOT_FOUND_RESPONSE = """{
Expand All @@ -49,13 +50,15 @@
"name": "projects/mock-project-id/tenants/tenant0",
"displayName": "Test Tenant",
"allowPasswordSignup": true,
"enableEmailLinkSignin": true
"enableEmailLinkSignin": true,
"allowDefaultProvider": true
},
{
"name": "projects/mock-project-id/tenants/tenant1",
"displayName": "Test Tenant",
"allowPasswordSignup": true,
"enableEmailLinkSignin": true
"enableEmailLinkSignin": true,
"allowDefaultProvider": true
}
]
}"""
Expand Down Expand Up @@ -160,12 +163,14 @@ def test_tenant(self):
'displayName': 'Test Tenant',
'allowPasswordSignup': True,
'enableEmailLinkSignin': True,
'allowDefaultProvider': True
}
tenant = tenant_mgt.Tenant(data)
assert tenant.tenant_id == 'tenant-id'
assert tenant.display_name == 'Test Tenant'
assert tenant.allow_password_sign_up is True
assert tenant.enable_email_link_sign_in is True
assert tenant.allow_default_provider is True

def test_tenant_optional_params(self):
data = {
Expand Down Expand Up @@ -236,30 +241,39 @@ def test_invalid_enable_email_link_sign_in(self, enable, tenant_mgt_app):
display_name='test', enable_email_link_sign_in=enable, app=tenant_mgt_app)
assert str(excinfo.value).startswith('Invalid type for enableEmailLinkSignin')

@pytest.mark.parametrize('allow', INVALID_BOOLEANS)
def test_invalid_allow_default_provider(self, allow, tenant_mgt_app):
with pytest.raises(ValueError) as excinfo:
tenant_mgt.create_tenant(
display_name='test', allow_default_provider=allow, app=tenant_mgt_app)
assert str(excinfo.value).startswith('Invalid type for allowDefaultProvider')

def test_create_tenant(self, tenant_mgt_app):
_, recorder = _instrument_tenant_mgt(tenant_mgt_app, 200, GET_TENANT_RESPONSE)
tenant = tenant_mgt.create_tenant(
display_name='My-Tenant', allow_password_sign_up=True, enable_email_link_sign_in=True,
app=tenant_mgt_app)
allow_default_provider=True, app=tenant_mgt_app)

_assert_tenant(tenant)
self._assert_request(recorder, {
'displayName': 'My-Tenant',
'allowPasswordSignup': True,
'enableEmailLinkSignin': True,
'allowDefaultProvider': True,
})

def test_create_tenant_false_values(self, tenant_mgt_app):
_, recorder = _instrument_tenant_mgt(tenant_mgt_app, 200, GET_TENANT_RESPONSE)
tenant = tenant_mgt.create_tenant(
display_name='test', allow_password_sign_up=False, enable_email_link_sign_in=False,
app=tenant_mgt_app)
allow_default_provider=False, app=tenant_mgt_app)

_assert_tenant(tenant)
self._assert_request(recorder, {
'displayName': 'test',
'allowPasswordSignup': False,
'enableEmailLinkSignin': False,
'allowDefaultProvider': False,
})

def test_create_tenant_minimal(self, tenant_mgt_app):
Expand Down Expand Up @@ -321,6 +335,13 @@ def test_invalid_enable_email_link_sign_in(self, enable, tenant_mgt_app):
tenant_mgt.update_tenant(
'tenant-id', enable_email_link_sign_in=enable, app=tenant_mgt_app)
assert str(excinfo.value).startswith('Invalid type for enableEmailLinkSignin')

@pytest.mark.parametrize('allow', INVALID_BOOLEANS)
def test_invalid_allow_default_provider(self, allow, tenant_mgt_app):
with pytest.raises(ValueError) as excinfo:
tenant_mgt.update_tenant(
'tenant-id', allow_default_provider=allow, app=tenant_mgt_app)
assert str(excinfo.value).startswith('Invalid type for allowDefaultProvider')

def test_update_tenant_no_args(self, tenant_mgt_app):
with pytest.raises(ValueError) as excinfo:
Expand All @@ -331,29 +352,31 @@ def test_update_tenant(self, tenant_mgt_app):
_, recorder = _instrument_tenant_mgt(tenant_mgt_app, 200, GET_TENANT_RESPONSE)
tenant = tenant_mgt.update_tenant(
'tenant-id', display_name='My-Tenant', allow_password_sign_up=True,
enable_email_link_sign_in=True, app=tenant_mgt_app)
enable_email_link_sign_in=True, allow_default_provider=True, app=tenant_mgt_app)

_assert_tenant(tenant)
body = {
'displayName': 'My-Tenant',
'allowPasswordSignup': True,
'enableEmailLinkSignin': True,
'allowDefaultProvider': True,
}
mask = ['allowPasswordSignup', 'displayName', 'enableEmailLinkSignin']
mask = ['allowDefaultProvider', 'allowPasswordSignup', 'displayName', 'enableEmailLinkSignin']
self._assert_request(recorder, body, mask)

def test_update_tenant_false_values(self, tenant_mgt_app):
_, recorder = _instrument_tenant_mgt(tenant_mgt_app, 200, GET_TENANT_RESPONSE)
tenant = tenant_mgt.update_tenant(
'tenant-id', allow_password_sign_up=False,
enable_email_link_sign_in=False, app=tenant_mgt_app)
enable_email_link_sign_in=False, allow_default_provider=False, app=tenant_mgt_app)

_assert_tenant(tenant)
body = {
'allowPasswordSignup': False,
'enableEmailLinkSignin': False,
'allowDefaultProvider': False,
}
mask = ['allowPasswordSignup', 'enableEmailLinkSignin']
mask = ['allowDefaultProvider', 'allowPasswordSignup', 'enableEmailLinkSignin']
self._assert_request(recorder, body, mask)

def test_update_tenant_minimal(self, tenant_mgt_app):
Expand Down Expand Up @@ -1002,3 +1025,4 @@ def _assert_tenant(tenant, tenant_id='tenant-id'):
assert tenant.display_name == 'Test Tenant'
assert tenant.allow_password_sign_up is True
assert tenant.enable_email_link_sign_in is True
assert tenant.allow_default_provider is True
16 changes: 14 additions & 2 deletions tests/test_user_mgt.py
Original file line number Diff line number Diff line change
Expand Up @@ -631,12 +631,13 @@ def test_update_user_delete_fields(self, user_mgt_app):
'testuser',
display_name=auth.DELETE_ATTRIBUTE,
photo_url=auth.DELETE_ATTRIBUTE,
phone_number=auth.DELETE_ATTRIBUTE)
phone_number=auth.DELETE_ATTRIBUTE,
email=auth.DELETE_ATTRIBUTE)
request = json.loads(recorder[0].body.decode())
assert request == {
'localId' : 'testuser',
'deleteAttribute' : ['DISPLAY_NAME', 'PHOTO_URL'],
'deleteProvider' : ['phone'],
'deleteProvider' : ['email', 'phone'],
}

def test_update_user_error(self, user_mgt_app):
Expand Down Expand Up @@ -681,6 +682,17 @@ def test_update_user_delete_provider_and_phone(self, user_mgt_app, arg):
assert len(set(request['deleteProvider'])) == len(request['deleteProvider'])
assert set(arg) - set(request['deleteProvider']) == set()

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

class TestSetCustomUserClaims:

@pytest.mark.parametrize('arg', INVALID_STRINGS + ['a'*129])
Expand Down