mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-17 15:03:02 +00:00
Merge pull request #3397 from 0mar/roles_interface
Refactor scopes tests
This commit is contained in:
@@ -1927,7 +1927,7 @@ class JupyterHub(Application):
|
|||||||
# make sure that on no admin situation, all roles are reset
|
# make sure that on no admin situation, all roles are reset
|
||||||
admin_role = orm.Role.find(db, name='admin')
|
admin_role = orm.Role.find(db, name='admin')
|
||||||
if not admin_role.users:
|
if not admin_role.users:
|
||||||
app_log.info(
|
app_log.warning(
|
||||||
"No admin users found; assuming hub upgrade. Initializing default roles for all entities"
|
"No admin users found; assuming hub upgrade. Initializing default roles for all entities"
|
||||||
)
|
)
|
||||||
# make sure all users, services and tokens have at least one role (update with default)
|
# make sure all users, services and tokens have at least one role (update with default)
|
||||||
|
@@ -371,7 +371,7 @@ def _token_allowed_role(db, token, role):
|
|||||||
raw_owner_scopes = {
|
raw_owner_scopes = {
|
||||||
scope.split('!', 1)[0] if '!' in scope else scope for scope in owner_scopes
|
scope.split('!', 1)[0] if '!' in scope else scope for scope in owner_scopes
|
||||||
}
|
}
|
||||||
if (raw_extra_scopes).issubset(raw_owner_scopes):
|
if raw_extra_scopes.issubset(raw_owner_scopes):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
@@ -89,6 +89,10 @@ class MockAPIHandler:
|
|||||||
self.request = mock.Mock(spec=HTTPServerRequest)
|
self.request = mock.Mock(spec=HTTPServerRequest)
|
||||||
self.request.path = '/path'
|
self.request.path = '/path'
|
||||||
|
|
||||||
|
def set_scopes(self, *scopes):
|
||||||
|
self.raw_scopes = set(scopes)
|
||||||
|
self.parsed_scopes = parse_scopes(self.raw_scopes)
|
||||||
|
|
||||||
@needs_scope('users')
|
@needs_scope('users')
|
||||||
def user_thing(self, user_name):
|
def user_thing(self, user_name):
|
||||||
return True
|
return True
|
||||||
@@ -116,6 +120,12 @@ class MockAPIHandler:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_handler():
|
||||||
|
obj = MockAPIHandler()
|
||||||
|
return obj
|
||||||
|
|
||||||
|
|
||||||
@mark.parametrize(
|
@mark.parametrize(
|
||||||
"scopes, method, arguments, is_allowed",
|
"scopes, method, arguments, is_allowed",
|
||||||
[
|
[
|
||||||
@@ -169,12 +179,10 @@ class MockAPIHandler:
|
|||||||
(['users!user=gob'], 'other_thing', ('maeby',), True),
|
(['users!user=gob'], 'other_thing', ('maeby',), True),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_scope_method_access(scopes, method, arguments, is_allowed):
|
def test_scope_method_access(mock_handler, scopes, method, arguments, is_allowed):
|
||||||
obj = MockAPIHandler()
|
mock_handler.current_user = mock.Mock(name=arguments[0])
|
||||||
obj.current_user = mock.Mock(name=arguments[0])
|
mock_handler.set_scopes(*scopes)
|
||||||
obj.raw_scopes = set(scopes)
|
api_call = getattr(mock_handler, method)
|
||||||
obj.parsed_scopes = parse_scopes(obj.raw_scopes)
|
|
||||||
api_call = getattr(obj, method)
|
|
||||||
if is_allowed:
|
if is_allowed:
|
||||||
assert api_call(*arguments)
|
assert api_call(*arguments)
|
||||||
else:
|
else:
|
||||||
@@ -182,31 +190,18 @@ def test_scope_method_access(scopes, method, arguments, is_allowed):
|
|||||||
api_call(*arguments)
|
api_call(*arguments)
|
||||||
|
|
||||||
|
|
||||||
def test_double_scoped_method_succeeds():
|
def test_double_scoped_method_succeeds(mock_handler):
|
||||||
obj = MockAPIHandler()
|
mock_handler.current_user = mock.Mock(name='lucille')
|
||||||
obj.current_user = mock.Mock(name='lucille')
|
mock_handler.set_scopes('users', 'read:services')
|
||||||
obj.raw_scopes = {'users', 'read:services'}
|
mock_handler.parsed_scopes = parse_scopes(mock_handler.raw_scopes)
|
||||||
obj.parsed_scopes = parse_scopes(obj.raw_scopes)
|
assert mock_handler.secret_thing()
|
||||||
assert obj.secret_thing()
|
|
||||||
|
|
||||||
|
|
||||||
def test_double_scoped_method_denials():
|
def test_double_scoped_method_denials(mock_handler):
|
||||||
obj = MockAPIHandler()
|
mock_handler.current_user = mock.Mock(name='lucille2')
|
||||||
obj.current_user = mock.Mock(name='lucille2')
|
mock_handler.set_scopes('users', 'read:groups')
|
||||||
obj.raw_scopes = {'users', 'read:groups'}
|
|
||||||
obj.parsed_scopes = parse_scopes(obj.raw_scopes)
|
|
||||||
with pytest.raises(web.HTTPError):
|
with pytest.raises(web.HTTPError):
|
||||||
obj.secret_thing()
|
mock_handler.secret_thing()
|
||||||
|
|
||||||
|
|
||||||
def generate_test_role(user_name, scopes, role_name='test'):
|
|
||||||
role = {
|
|
||||||
'name': role_name,
|
|
||||||
'description': '',
|
|
||||||
'users': [user_name],
|
|
||||||
'scopes': scopes,
|
|
||||||
}
|
|
||||||
return role
|
|
||||||
|
|
||||||
|
|
||||||
@mark.parametrize(
|
@mark.parametrize(
|
||||||
@@ -239,7 +234,6 @@ async def test_expand_groups(app, user_name, in_group, status_code):
|
|||||||
app.db.add(group)
|
app.db.add(group)
|
||||||
if in_group and user not in group.users:
|
if in_group and user not in group.users:
|
||||||
group.users.append(user)
|
group.users.append(user)
|
||||||
kind = 'users'
|
|
||||||
roles.update_roles(app.db, user, roles=['test'])
|
roles.update_roles(app.db, user, roles=['test'])
|
||||||
roles.strip_role(app.db, user, 'user')
|
roles.strip_role(app.db, user, 'user')
|
||||||
app.db.commit()
|
app.db.commit()
|
||||||
@@ -247,6 +241,8 @@ async def test_expand_groups(app, user_name, in_group, status_code):
|
|||||||
app, 'users', user_name, headers=auth_header(app.db, user_name)
|
app, 'users', user_name, headers=auth_header(app.db, user_name)
|
||||||
)
|
)
|
||||||
assert r.status_code == status_code
|
assert r.status_code == status_code
|
||||||
|
app.db.delete(group)
|
||||||
|
app.db.commit()
|
||||||
|
|
||||||
|
|
||||||
async def test_by_fake_user(app):
|
async def test_by_fake_user(app):
|
||||||
@@ -262,79 +258,127 @@ async def test_by_fake_user(app):
|
|||||||
err_message = "No access to resources or resources not found"
|
err_message = "No access to resources or resources not found"
|
||||||
|
|
||||||
|
|
||||||
async def test_request_fake_user(app):
|
@pytest.fixture
|
||||||
user_name = 'buster'
|
def create_temp_role(app):
|
||||||
fake_user = 'annyong'
|
"""Generate a temporary role with certain scopes.
|
||||||
user = add_user(app.db, name=user_name)
|
Convenience function that provides setup, database handling and teardown"""
|
||||||
test_role = generate_test_role(user_name, ['read:users!group=stuff'])
|
temp_roles = []
|
||||||
roles.create_role(app.db, test_role)
|
index = [1]
|
||||||
roles.grant_role(app.db, entity=user, rolename='test')
|
|
||||||
|
def temp_role_creator(scopes, role_name=None):
|
||||||
|
if not role_name:
|
||||||
|
role_name = f'temp_role_{index[0]}'
|
||||||
|
index[0] += 1
|
||||||
|
temp_role = orm.Role(name=role_name, scopes=list(scopes))
|
||||||
|
temp_roles.append(temp_role)
|
||||||
|
app.db.add(temp_role)
|
||||||
|
app.db.commit()
|
||||||
|
return temp_role
|
||||||
|
|
||||||
|
yield temp_role_creator
|
||||||
|
for role in temp_roles:
|
||||||
|
app.db.delete(role)
|
||||||
app.db.commit()
|
app.db.commit()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def create_user_with_scopes(app, create_temp_role):
|
||||||
|
"""Generate a temporary user with specific scopes.
|
||||||
|
Convenience function that provides setup, database handling and teardown"""
|
||||||
|
temp_users = []
|
||||||
|
counter = 0
|
||||||
|
get_role = create_temp_role
|
||||||
|
|
||||||
|
def temp_user_creator(*scopes):
|
||||||
|
nonlocal counter
|
||||||
|
counter += 1
|
||||||
|
name = f"temp_user_{counter}"
|
||||||
|
role = get_role(scopes)
|
||||||
|
orm_user = orm.User(name=name)
|
||||||
|
app.db.add(orm_user)
|
||||||
|
app.db.commit()
|
||||||
|
temp_users.append(orm_user)
|
||||||
|
roles.update_roles(app.db, orm_user, roles=[role.name])
|
||||||
|
return app.users[orm_user.id]
|
||||||
|
|
||||||
|
yield temp_user_creator
|
||||||
|
for user in temp_users:
|
||||||
|
app.users.delete(user)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def create_service_with_scopes(app, create_temp_role):
|
||||||
|
"""Generate a temporary service with specific scopes.
|
||||||
|
Convenience function that provides setup, database handling and teardown"""
|
||||||
|
temp_service = []
|
||||||
|
counter = 0
|
||||||
|
role_function = create_temp_role
|
||||||
|
|
||||||
|
def temp_service_creator(*scopes):
|
||||||
|
nonlocal counter
|
||||||
|
counter += 1
|
||||||
|
name = f"temp_service_{counter}"
|
||||||
|
role = role_function(scopes)
|
||||||
|
app.services.append({'name': name})
|
||||||
|
app.init_services()
|
||||||
|
orm_service = orm.Service.find(app.db, name)
|
||||||
|
app.db.commit()
|
||||||
|
roles.update_roles(app.db, orm_service, roles=[role.name])
|
||||||
|
return orm_service
|
||||||
|
|
||||||
|
yield temp_service_creator
|
||||||
|
for service in temp_service:
|
||||||
|
app.db.delete(service)
|
||||||
|
app.db.commit()
|
||||||
|
|
||||||
|
|
||||||
|
async def test_request_fake_user(app, create_user_with_scopes):
|
||||||
|
fake_user = 'annyong'
|
||||||
|
user = create_user_with_scopes('read:users!group=stuff')
|
||||||
r = await api_request(
|
r = await api_request(
|
||||||
app, 'users', fake_user, headers=auth_header(app.db, user_name)
|
app, 'users', fake_user, headers=auth_header(app.db, user.name)
|
||||||
)
|
)
|
||||||
assert r.status_code == 404
|
assert r.status_code == 404
|
||||||
# Consistency between no user and user not accessible
|
# Consistency between no user and user not accessible
|
||||||
assert r.json()['message'] == err_message
|
assert r.json()['message'] == err_message
|
||||||
|
|
||||||
|
|
||||||
async def test_refuse_exceeding_token_permissions(app):
|
async def test_refuse_exceeding_token_permissions(
|
||||||
user_name = 'abed'
|
app, create_user_with_scopes, create_temp_role
|
||||||
user = add_user(app.db, name=user_name)
|
):
|
||||||
add_user(app.db, name='user')
|
user = create_user_with_scopes('self')
|
||||||
api_token = user.new_api_token()
|
user.new_api_token()
|
||||||
exceeding_role = generate_test_role(user_name, ['read:users'], 'exceeding_role')
|
create_temp_role(['admin:users'], 'exceeding_role')
|
||||||
roles.create_role(app.db, exceeding_role)
|
with pytest.raises(ValueError):
|
||||||
roles.grant_role(app.db, entity=user.api_tokens[0], rolename='exceeding_role')
|
roles.update_roles(app.db, entity=user.api_tokens[0], roles=['exceeding_role'])
|
||||||
app.db.commit()
|
|
||||||
headers = {'Authorization': 'token %s' % api_token}
|
|
||||||
r = await api_request(app, 'users', headers=headers)
|
|
||||||
assert r.status_code == 200
|
|
||||||
result_names = {user['name'] for user in r.json()}
|
|
||||||
assert result_names == {user_name}
|
|
||||||
|
|
||||||
|
|
||||||
async def test_exceeding_user_permissions(app):
|
async def test_exceeding_user_permissions(
|
||||||
user_name = 'abed'
|
app, create_user_with_scopes, create_temp_role
|
||||||
user = add_user(app.db, name=user_name)
|
):
|
||||||
add_user(app.db, name='user')
|
user = create_user_with_scopes('read:users:groups')
|
||||||
api_token = user.new_api_token()
|
api_token = user.new_api_token()
|
||||||
orm_api_token = orm.APIToken.find(app.db, token=api_token)
|
orm_api_token = orm.APIToken.find(app.db, token=api_token)
|
||||||
reader_role = generate_test_role(user_name, ['read:users'], 'reader_role')
|
create_temp_role(['read:users'], 'reader_role')
|
||||||
subreader_role = generate_test_role(
|
roles.grant_role(app.db, orm_api_token, rolename='reader_role')
|
||||||
user_name, ['read:users:groups'], 'subreader_role'
|
|
||||||
)
|
|
||||||
roles.create_role(app.db, reader_role)
|
|
||||||
roles.create_role(app.db, subreader_role)
|
|
||||||
app.db.commit()
|
|
||||||
roles.update_roles(app.db, user, roles=['reader_role'])
|
|
||||||
roles.update_roles(app.db, orm_api_token, roles=['subreader_role'])
|
|
||||||
orm_api_token.roles.remove(orm.Role.find(app.db, name='token'))
|
|
||||||
app.db.commit()
|
|
||||||
|
|
||||||
headers = {'Authorization': 'token %s' % api_token}
|
headers = {'Authorization': 'token %s' % api_token}
|
||||||
r = await api_request(app, 'users', headers=headers)
|
r = await api_request(app, 'users', headers=headers)
|
||||||
assert r.status_code == 200
|
assert r.status_code == 200
|
||||||
keys = {key for user in r.json() for key in user.keys()}
|
keys = {key for user in r.json() for key in user.keys()}
|
||||||
assert 'groups' in keys
|
assert 'groups' in keys
|
||||||
assert 'last_activity' not in keys
|
assert 'last_activity' not in keys
|
||||||
roles.strip_role(app.db, user, 'reader_role')
|
|
||||||
|
|
||||||
|
|
||||||
async def test_user_service_separation(app, mockservice_url):
|
async def test_user_service_separation(app, mockservice_url, create_temp_role):
|
||||||
name = mockservice_url.name
|
name = mockservice_url.name
|
||||||
user = add_user(app.db, name=name)
|
user = add_user(app.db, name=name)
|
||||||
|
|
||||||
reader_role = generate_test_role(name, ['read:users'], 'reader_role')
|
create_temp_role(['read:users'], 'reader_role')
|
||||||
subreader_role = generate_test_role(name, ['read:users:groups'], 'subreader_role')
|
create_temp_role(['read:users:groups'], 'subreader_role')
|
||||||
roles.create_role(app.db, reader_role)
|
|
||||||
roles.create_role(app.db, subreader_role)
|
|
||||||
app.db.commit()
|
|
||||||
roles.update_roles(app.db, user, roles=['subreader_role'])
|
roles.update_roles(app.db, user, roles=['subreader_role'])
|
||||||
roles.update_roles(app.db, mockservice_url.orm, roles=['reader_role'])
|
roles.update_roles(app.db, mockservice_url.orm, roles=['reader_role'])
|
||||||
user.roles.remove(orm.Role.find(app.db, name='user'))
|
user.roles.remove(orm.Role.find(app.db, name='user'))
|
||||||
api_token = user.new_api_token()
|
api_token = user.new_api_token()
|
||||||
app.db.commit()
|
|
||||||
headers = {'Authorization': 'token %s' % api_token}
|
headers = {'Authorization': 'token %s' % api_token}
|
||||||
r = await api_request(app, 'users', headers=headers)
|
r = await api_request(app, 'users', headers=headers)
|
||||||
assert r.status_code == 200
|
assert r.status_code == 200
|
||||||
@@ -343,33 +387,22 @@ async def test_user_service_separation(app, mockservice_url):
|
|||||||
assert 'last_activity' not in keys
|
assert 'last_activity' not in keys
|
||||||
|
|
||||||
|
|
||||||
async def test_request_user_outside_group(app):
|
async def test_request_user_outside_group(app, create_user_with_scopes):
|
||||||
user_name = 'buster'
|
outside_user = 'hello'
|
||||||
fake_user = 'hello'
|
user = create_user_with_scopes('read:users!group=stuff')
|
||||||
user = add_user(app.db, name=user_name)
|
add_user(app.db, name=outside_user)
|
||||||
add_user(app.db, name=fake_user)
|
|
||||||
test_role = generate_test_role(user_name, ['read:users!group=stuff'])
|
|
||||||
roles.create_role(app.db, test_role)
|
|
||||||
roles.grant_role(app.db, entity=user, rolename='test')
|
|
||||||
roles.strip_role(app.db, entity=user, rolename='user')
|
|
||||||
app.db.commit()
|
|
||||||
r = await api_request(
|
r = await api_request(
|
||||||
app, 'users', fake_user, headers=auth_header(app.db, user_name)
|
app, 'users', outside_user, headers=auth_header(app.db, user.name)
|
||||||
)
|
)
|
||||||
assert r.status_code == 404
|
assert r.status_code == 404
|
||||||
# Consistency between no user and user not accessible
|
# Consistency between no user and user not accessible
|
||||||
assert r.json()['message'] == err_message
|
assert r.json()['message'] == err_message
|
||||||
|
|
||||||
|
|
||||||
async def test_user_filter(app):
|
async def test_user_filter(app, create_user_with_scopes):
|
||||||
user_name = 'rita'
|
user = create_user_with_scopes(
|
||||||
user = add_user(app.db, name=user_name)
|
'read:users!user=lindsay', 'read:users!user=gob', 'read:users!user=oscar'
|
||||||
app.db.commit()
|
)
|
||||||
scopes = ['read:users!user=lindsay', 'read:users!user=gob', 'read:users!user=oscar']
|
|
||||||
test_role = generate_test_role(user, scopes)
|
|
||||||
roles.create_role(app.db, test_role)
|
|
||||||
roles.grant_role(app.db, entity=user, rolename='test')
|
|
||||||
roles.strip_role(app.db, entity=user, rolename='user')
|
|
||||||
name_in_scope = {'lindsay', 'oscar', 'gob'}
|
name_in_scope = {'lindsay', 'oscar', 'gob'}
|
||||||
outside_scope = {'maeby', 'marta'}
|
outside_scope = {'maeby', 'marta'}
|
||||||
group_name = 'bluth'
|
group_name = 'bluth'
|
||||||
@@ -378,17 +411,19 @@ async def test_user_filter(app):
|
|||||||
group = orm.Group(name=group_name)
|
group = orm.Group(name=group_name)
|
||||||
app.db.add(group)
|
app.db.add(group)
|
||||||
for name in name_in_scope | outside_scope:
|
for name in name_in_scope | outside_scope:
|
||||||
user = add_user(app.db, name=name)
|
group_user = add_user(app.db, name=name)
|
||||||
if name not in group.users:
|
if name not in group.users:
|
||||||
group.users.append(user)
|
group.users.append(group_user)
|
||||||
app.db.commit()
|
app.db.commit()
|
||||||
r = await api_request(app, 'users', headers=auth_header(app.db, user_name))
|
r = await api_request(app, 'users', headers=auth_header(app.db, user.name))
|
||||||
assert r.status_code == 200
|
assert r.status_code == 200
|
||||||
result_names = {user['name'] for user in r.json()}
|
result_names = {user['name'] for user in r.json()}
|
||||||
assert result_names == name_in_scope
|
assert result_names == name_in_scope
|
||||||
|
app.db.delete(group)
|
||||||
|
app.db.commit()
|
||||||
|
|
||||||
|
|
||||||
async def test_service_filter(app):
|
async def test_service_filter(app, create_user_with_scopes):
|
||||||
services = [
|
services = [
|
||||||
{'name': 'cull_idle', 'api_token': 'some-token'},
|
{'name': 'cull_idle', 'api_token': 'some-token'},
|
||||||
{'name': 'user_service', 'api_token': 'some-other-token'},
|
{'name': 'user_service', 'api_token': 'some-other-token'},
|
||||||
@@ -396,124 +431,90 @@ async def test_service_filter(app):
|
|||||||
for service in services:
|
for service in services:
|
||||||
app.services.append(service)
|
app.services.append(service)
|
||||||
app.init_services()
|
app.init_services()
|
||||||
user_name = 'buster'
|
user = create_user_with_scopes('read:services!service=cull_idle')
|
||||||
user = add_user(app.db, name=user_name)
|
r = await api_request(app, 'services', headers=auth_header(app.db, user.name))
|
||||||
app.db.commit()
|
|
||||||
test_role = generate_test_role(user, ['read:services!service=cull_idle'])
|
|
||||||
roles.create_role(app.db, test_role)
|
|
||||||
roles.grant_role(app.db, entity=user, rolename='test')
|
|
||||||
r = await api_request(app, 'services', headers=auth_header(app.db, user_name))
|
|
||||||
assert r.status_code == 200
|
assert r.status_code == 200
|
||||||
service_names = set(r.json().keys())
|
service_names = set(r.json().keys())
|
||||||
assert service_names == {'cull_idle'}
|
assert service_names == {'cull_idle'}
|
||||||
|
|
||||||
|
|
||||||
async def test_user_filter_with_group(app):
|
async def test_user_filter_with_group(app, create_user_with_scopes):
|
||||||
# Move role setup to setup method?
|
|
||||||
user_name = 'sally'
|
|
||||||
user = add_user(app.db, name=user_name)
|
|
||||||
external_user_name = 'britta'
|
|
||||||
add_user(app.db, name=external_user_name)
|
|
||||||
test_role = generate_test_role(user_name, ['read:users!group=sitwell'])
|
|
||||||
roles.create_role(app.db, test_role)
|
|
||||||
roles.grant_role(app.db, entity=user, rolename='test')
|
|
||||||
|
|
||||||
name_set = {'sally', 'stan'}
|
|
||||||
group_name = 'sitwell'
|
group_name = 'sitwell'
|
||||||
|
user1 = create_user_with_scopes(f'read:users!group={group_name}')
|
||||||
|
user2 = create_user_with_scopes('self')
|
||||||
|
external_user = create_user_with_scopes('self')
|
||||||
|
name_set = {user1.name, user2.name}
|
||||||
group = orm.Group.find(app.db, name=group_name)
|
group = orm.Group.find(app.db, name=group_name)
|
||||||
if not group:
|
if not group:
|
||||||
group = orm.Group(name=group_name)
|
group = orm.Group(name=group_name)
|
||||||
app.db.add(group)
|
app.db.add(group)
|
||||||
for name in name_set:
|
for user in {user1, user2}:
|
||||||
user = add_user(app.db, name=name)
|
group.users.append(user)
|
||||||
if name not in group.users:
|
|
||||||
group.users.append(user)
|
|
||||||
app.db.commit()
|
app.db.commit()
|
||||||
|
|
||||||
r = await api_request(app, 'users', headers=auth_header(app.db, user_name))
|
r = await api_request(app, 'users', headers=auth_header(app.db, user1.name))
|
||||||
assert r.status_code == 200
|
assert r.status_code == 200
|
||||||
result_names = {user['name'] for user in r.json()}
|
result_names = {user['name'] for user in r.json()}
|
||||||
assert result_names == name_set
|
assert result_names == name_set
|
||||||
assert external_user_name not in result_names
|
assert external_user.name not in result_names
|
||||||
|
app.db.delete(group)
|
||||||
|
app.db.commit()
|
||||||
|
|
||||||
|
|
||||||
async def test_group_scope_filter(app):
|
async def test_group_scope_filter(app, create_user_with_scopes):
|
||||||
user_name = 'rollerblade'
|
in_groups = {'sitwell', 'bluth'}
|
||||||
user = add_user(app.db, name=user_name)
|
out_groups = {'austero'}
|
||||||
scopes = ['read:groups!group=sitwell', 'read:groups!group=bluth']
|
user = create_user_with_scopes(
|
||||||
test_role = generate_test_role(user_name, scopes)
|
*(f'read:groups!group={group}' for group in in_groups)
|
||||||
roles.create_role(app.db, test_role)
|
)
|
||||||
roles.grant_role(app.db, entity=user, rolename='test')
|
for group_name in in_groups | out_groups:
|
||||||
|
|
||||||
group_set = {'sitwell', 'bluth', 'austero'}
|
|
||||||
for group_name in group_set:
|
|
||||||
group = orm.Group.find(app.db, name=group_name)
|
group = orm.Group.find(app.db, name=group_name)
|
||||||
if not group:
|
if not group:
|
||||||
group = orm.Group(name=group_name)
|
group = orm.Group(name=group_name)
|
||||||
app.db.add(group)
|
app.db.add(group)
|
||||||
app.db.commit()
|
app.db.commit()
|
||||||
r = await api_request(app, 'groups', headers=auth_header(app.db, user_name))
|
r = await api_request(app, 'groups', headers=auth_header(app.db, user.name))
|
||||||
assert r.status_code == 200
|
assert r.status_code == 200
|
||||||
result_names = {user['name'] for user in r.json()}
|
result_names = {user['name'] for user in r.json()}
|
||||||
assert result_names == {'sitwell', 'bluth'}
|
assert result_names == in_groups
|
||||||
|
for group_name in in_groups | out_groups:
|
||||||
|
group = orm.Group.find(app.db, name=group_name)
|
||||||
async def test_vertical_filter(app):
|
app.db.delete(group)
|
||||||
user_name = 'lindsey'
|
|
||||||
user = add_user(app.db, name=user_name)
|
|
||||||
test_role = generate_test_role(user_name, ['read:users:name'])
|
|
||||||
roles.create_role(app.db, test_role)
|
|
||||||
roles.grant_role(app.db, entity=user, rolename='test')
|
|
||||||
roles.strip_role(app.db, entity=user, rolename='user')
|
|
||||||
app.db.commit()
|
app.db.commit()
|
||||||
|
|
||||||
r = await api_request(app, 'users', headers=auth_header(app.db, user_name))
|
|
||||||
|
async def test_vertical_filter(app, create_user_with_scopes):
|
||||||
|
user = create_user_with_scopes('read:users:name')
|
||||||
|
r = await api_request(app, 'users', headers=auth_header(app.db, user.name))
|
||||||
assert r.status_code == 200
|
assert r.status_code == 200
|
||||||
allowed_keys = {'name', 'kind'}
|
allowed_keys = {'name', 'kind'}
|
||||||
assert set([key for user in r.json() for key in user.keys()]) == allowed_keys
|
assert set([key for user in r.json() for key in user.keys()]) == allowed_keys
|
||||||
|
|
||||||
|
|
||||||
async def test_stacked_vertical_filter(app):
|
async def test_stacked_vertical_filter(app, create_user_with_scopes):
|
||||||
user_name = 'user'
|
user = create_user_with_scopes('read:users:activity', 'read:users:servers')
|
||||||
user = add_user(app.db, name=user_name)
|
r = await api_request(app, 'users', headers=auth_header(app.db, user.name))
|
||||||
test_role = generate_test_role(
|
|
||||||
user_name, ['read:users:activity', 'read:users:servers']
|
|
||||||
)
|
|
||||||
roles.create_role(app.db, test_role)
|
|
||||||
roles.grant_role(app.db, entity=user, rolename='test')
|
|
||||||
roles.strip_role(app.db, entity=user, rolename='user')
|
|
||||||
app.db.commit()
|
|
||||||
|
|
||||||
r = await api_request(app, 'users', headers=auth_header(app.db, user_name))
|
|
||||||
assert r.status_code == 200
|
assert r.status_code == 200
|
||||||
allowed_keys = {'name', 'kind', 'servers', 'last_activity'}
|
allowed_keys = {'name', 'kind', 'servers', 'last_activity'}
|
||||||
result_model = set([key for user in r.json() for key in user.keys()])
|
result_model = set([key for user in r.json() for key in user.keys()])
|
||||||
assert result_model == allowed_keys
|
assert result_model == allowed_keys
|
||||||
|
|
||||||
|
|
||||||
async def test_cross_filter(app):
|
async def test_cross_filter(app, create_user_with_scopes):
|
||||||
user_name = 'abed'
|
user = create_user_with_scopes('read:users:activity', 'self')
|
||||||
user = add_user(app.db, name=user_name)
|
|
||||||
test_role = generate_test_role(
|
|
||||||
user_name, ['read:users:activity', 'read:users!user=abed']
|
|
||||||
)
|
|
||||||
roles.create_role(app.db, test_role)
|
|
||||||
roles.grant_role(app.db, entity=user, rolename='test')
|
|
||||||
roles.strip_role(app.db, entity=user, rolename='user')
|
|
||||||
app.db.commit()
|
|
||||||
new_users = {'britta', 'jeff', 'annie'}
|
new_users = {'britta', 'jeff', 'annie'}
|
||||||
for new_user_name in new_users:
|
for new_user_name in new_users:
|
||||||
add_user(app.db, name=new_user_name)
|
add_user(app.db, name=new_user_name)
|
||||||
app.db.commit()
|
app.db.commit()
|
||||||
r = await api_request(app, 'users', headers=auth_header(app.db, user_name))
|
r = await api_request(app, 'users', headers=auth_header(app.db, user.name))
|
||||||
assert r.status_code == 200
|
assert r.status_code == 200
|
||||||
restricted_keys = {'name', 'kind', 'last_activity'}
|
restricted_keys = {'name', 'kind', 'last_activity'}
|
||||||
key_in_full_model = 'created'
|
key_in_full_model = 'created'
|
||||||
for user in r.json():
|
for model_user in r.json():
|
||||||
if user['name'] == user_name:
|
if model_user['name'] == user.name:
|
||||||
assert key_in_full_model in user
|
assert key_in_full_model in model_user
|
||||||
else:
|
else:
|
||||||
assert set(user.keys()) == restricted_keys
|
assert set(model_user.keys()) == restricted_keys
|
||||||
|
|
||||||
|
|
||||||
@mark.parametrize(
|
@mark.parametrize(
|
||||||
@@ -523,13 +524,13 @@ async def test_cross_filter(app):
|
|||||||
('services', False),
|
('services', False),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_metascope_self_expansion(app, kind, has_user_scopes):
|
async def test_metascope_self_expansion(
|
||||||
Class = orm.get_class(kind)
|
app, kind, has_user_scopes, create_user_with_scopes, create_service_with_scopes
|
||||||
orm_obj = Class(name=f'test_{kind}')
|
):
|
||||||
app.db.add(orm_obj)
|
if kind == 'users':
|
||||||
app.db.commit()
|
orm_obj = create_user_with_scopes('self')
|
||||||
test_role = orm.Role(name='test_role', scopes=['self'])
|
else:
|
||||||
orm_obj.roles.append(test_role)
|
orm_obj = create_service_with_scopes('self')
|
||||||
# test expansion of user/service scopes
|
# test expansion of user/service scopes
|
||||||
scopes = roles.expand_roles_to_scopes(orm_obj)
|
scopes = roles.expand_roles_to_scopes(orm_obj)
|
||||||
assert bool(scopes) == has_user_scopes
|
assert bool(scopes) == has_user_scopes
|
||||||
@@ -538,14 +539,10 @@ async def test_metascope_self_expansion(app, kind, has_user_scopes):
|
|||||||
orm_obj.new_api_token()
|
orm_obj.new_api_token()
|
||||||
token_scopes = get_scopes_for(orm_obj.api_tokens[0])
|
token_scopes = get_scopes_for(orm_obj.api_tokens[0])
|
||||||
assert bool(token_scopes) == has_user_scopes
|
assert bool(token_scopes) == has_user_scopes
|
||||||
app.db.delete(orm_obj)
|
|
||||||
app.db.delete(test_role)
|
|
||||||
app.db.commit()
|
|
||||||
|
|
||||||
|
|
||||||
async def test_metascope_all_expansion(app):
|
async def test_metascope_all_expansion(app, create_user_with_scopes):
|
||||||
user = add_user(app.db, name='user')
|
user = create_user_with_scopes('self')
|
||||||
scope_set = {scope for role in user.roles for scope in role.scopes}
|
|
||||||
user.new_api_token()
|
user.new_api_token()
|
||||||
token = user.api_tokens[0]
|
token = user.api_tokens[0]
|
||||||
# Check 'all' expansion
|
# Check 'all' expansion
|
||||||
@@ -622,7 +619,7 @@ async def test_server_state_access(
|
|||||||
service.roles.append(role)
|
service.roles.append(role)
|
||||||
app.db.commit()
|
app.db.commit()
|
||||||
api_token = service.new_api_token()
|
api_token = service.new_api_token()
|
||||||
app.init_roles()
|
await app.init_roles()
|
||||||
headers = {'Authorization': 'token %s' % api_token}
|
headers = {'Authorization': 'token %s' % api_token}
|
||||||
r = await api_request(app, 'users', username, headers=headers)
|
r = await api_request(app, 'users', username, headers=headers)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
|
Reference in New Issue
Block a user