Replaced auth_state and server_state with scopes

This commit is contained in:
0mar
2021-03-26 13:47:01 +01:00
parent b74075d945
commit c5c44f6dbe
4 changed files with 40 additions and 40 deletions

View File

@@ -220,7 +220,13 @@ class APIHandler(BaseHandler):
model.update(extra)
return model
def user_model(self, user, include_servers=False, include_state=False):
def user_model(
self,
user,
include_servers=False,
include_server_state=False,
include_auth_state=False,
):
"""Get the JSON model for a User object"""
if isinstance(user, orm.User):
user = self.users[user.id]
@@ -234,13 +240,26 @@ class APIHandler(BaseHandler):
'pending': None,
'created': isoformat(user.created),
'last_activity': isoformat(user.last_activity),
'auth_state': '', # placeholder, filled in later
}
access_map = {
'read:users': set(model.keys()), # All available components
'read:users': {
'kind',
'name',
'admin',
'roles',
'groups',
'server',
'pending',
'created',
'last_activity',
},
'read:users:name': {'kind', 'name'},
'read:users:groups': {'kind', 'name', 'groups'},
'read:users:activity': {'kind', 'name', 'last_activity'},
'read:users:servers': {'kind', 'name', 'servers'},
'read:users:auth_state': {'kind', 'name', 'auth_state'},
'read:users:server_state': {'kind', 'name', 'server_state'},
}
self.log.debug(
"Asking for user model of %s with scopes [%s]",
@@ -254,18 +273,20 @@ class APIHandler(BaseHandler):
if scope_filter(user, kind='user'):
allowed_keys |= access_map[scope]
model = {key: model[key] for key in allowed_keys if key in model}
if not include_auth_state:
model.pop("auth_state", None)
if model:
include_server_state &= 'server_state' in allowed_keys
if '' in user.spawners and 'pending' in allowed_keys:
model['pending'] = user.spawners[''].pending
if include_servers and 'servers' in allowed_keys:
# Todo: Replace include_state with scope (read|admin):users:auth_state
servers = model['servers'] = {}
for name, spawner in user.spawners.items():
# include 'active' servers, not just ready
# (this includes pending events)
if spawner.active:
servers[name] = self.server_model(
spawner, include_state=include_state
spawner, include_state=include_server_state
)
return model
@@ -287,6 +308,11 @@ class APIHandler(BaseHandler):
scope_filter = self.get_scope_filter(req_scope)
if scope_filter(service, kind='service'):
model['roles'] = [r.name for r in service.roles]
model[
'admin'
] = (
service.admin
) # todo: Remove once we replace admin flag with role check
return model
_user_model_types = {'name': str, 'admin': bool, 'groups': list, 'auth_state': dict}

View File

@@ -105,7 +105,7 @@ class UserListAPIHandler(APIHandler):
for u in query:
if post_filter is None or post_filter(u):
user_model = self.user_model(
u, include_servers=True, include_state=True
u, include_servers=True, include_server_state=True
)
if user_model:
data.append(user_model)
@@ -187,18 +187,22 @@ def admin_or_self(method):
class UserAPIHandler(APIHandler):
@needs_scope('read:users')
@needs_scope(
'read:users'
) # Todo: Add the same list of scopes as at UserListAPIHandler
async def get(self, user_name):
user = self.find_user(user_name)
model = self.user_model(
user, include_servers=True, include_state=self.current_user.admin
user,
include_servers=True,
include_server_state=True,
include_auth_state=True,
)
# auth state will only be shown if the requester is an admin
# this means users can't see their own auth state unless they
# are admins, Hub admins often are also marked as admins so they
# will see their auth state but normal users won't
requester = self.current_user
if requester.admin:
if 'auth_state' in model:
model['auth_state'] = await user.get_auth_state()
self.write(json.dumps(model))

View File

@@ -93,10 +93,9 @@ def get_scope_hierarchy():
'read:users:groups',
'read:users:activity',
'read:users:servers',
'read:users:auth_state',
],
'users:tokens': ['read:users:tokens'],
'admin:users': None,
'admin:users': ['read:users:auth_state', 'read:users:server_state'],
'admin:users:servers': None,
'groups': ['read:groups'],
'admin:groups': None,

View File

@@ -421,32 +421,3 @@ async def test_get_new_token_via_api(app, headers, role_list, status):
# verify deletion
r = await api_request(app, 'users/user/tokens', token_id)
assert r.status_code == 404
@mark.role
@mark.parametrize(
"kind, has_user_scopes",
[
('users', True),
('services', False),
],
)
async def test_self_expansion(app, kind, has_user_scopes):
Class = orm.get_class(kind)
orm_obj = Class(name=f'test_{kind}')
app.db.add(orm_obj)
app.db.commit()
test_role = orm.Role(name='test_role', scopes=['self'])
orm_obj.roles.append(test_role)
# test expansion of user/service scopes
scopes = roles.expand_roles_to_scopes(orm_obj)
assert bool(scopes) == has_user_scopes
# test expansion of token scopes
orm_obj.new_api_token()
print(orm_obj.api_tokens[0])
token_scopes = scopes.get_scopes_for(orm_obj.api_tokens[0])
print(token_scopes)
assert bool(token_scopes) == has_user_scopes
app.db.delete(orm_obj)
app.db.delete(test_role)