mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-15 05:53:00 +00:00
Expose auth_state via user API
This commit is contained in:
@@ -18,14 +18,14 @@ from .base import BaseHandler, APIHandler
|
|||||||
|
|
||||||
class TokenAPIHandler(APIHandler):
|
class TokenAPIHandler(APIHandler):
|
||||||
@token_authenticated
|
@token_authenticated
|
||||||
def get(self, token):
|
async def get(self, token):
|
||||||
orm_token = orm.APIToken.find(self.db, token)
|
orm_token = orm.APIToken.find(self.db, token)
|
||||||
if orm_token is None:
|
if orm_token is None:
|
||||||
orm_token = orm.OAuthAccessToken.find(self.db, token)
|
orm_token = orm.OAuthAccessToken.find(self.db, token)
|
||||||
if orm_token is None:
|
if orm_token is None:
|
||||||
raise web.HTTPError(404)
|
raise web.HTTPError(404)
|
||||||
if orm_token.user:
|
if orm_token.user:
|
||||||
model = self.user_model(self.users[orm_token.user])
|
model = await self.user_model(self.users[orm_token.user])
|
||||||
elif orm_token.service:
|
elif orm_token.service:
|
||||||
model = self.service_model(orm_token.service)
|
model = self.service_model(orm_token.service)
|
||||||
else:
|
else:
|
||||||
@@ -71,13 +71,13 @@ class TokenAPIHandler(APIHandler):
|
|||||||
api_token = user.new_api_token(note=note)
|
api_token = user.new_api_token(note=note)
|
||||||
self.write(json.dumps({
|
self.write(json.dumps({
|
||||||
'token': api_token,
|
'token': api_token,
|
||||||
'user': self.user_model(user),
|
'user': await self.user_model(user),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
||||||
class CookieAPIHandler(APIHandler):
|
class CookieAPIHandler(APIHandler):
|
||||||
@token_authenticated
|
@token_authenticated
|
||||||
def get(self, cookie_name, cookie_value=None):
|
async def get(self, cookie_name, cookie_value=None):
|
||||||
cookie_name = quote(cookie_name, safe='')
|
cookie_name = quote(cookie_name, safe='')
|
||||||
if cookie_value is None:
|
if cookie_value is None:
|
||||||
self.log.warning("Cookie values in request body is deprecated, use `/cookie_name/cookie_value`")
|
self.log.warning("Cookie values in request body is deprecated, use `/cookie_name/cookie_value`")
|
||||||
@@ -87,12 +87,12 @@ class CookieAPIHandler(APIHandler):
|
|||||||
user = self._user_for_cookie(cookie_name, cookie_value)
|
user = self._user_for_cookie(cookie_name, cookie_value)
|
||||||
if user is None:
|
if user is None:
|
||||||
raise web.HTTPError(404)
|
raise web.HTTPError(404)
|
||||||
self.write(json.dumps(self.user_model(user)))
|
self.write(json.dumps(await self.user_model(user)))
|
||||||
|
|
||||||
|
|
||||||
class OAuthHandler(BaseHandler, OAuth2Handler):
|
class OAuthHandler(BaseHandler, OAuth2Handler):
|
||||||
"""Implement OAuth provider handlers
|
"""Implement OAuth provider handlers
|
||||||
|
|
||||||
OAuth2Handler sets `self.provider` in initialize,
|
OAuth2Handler sets `self.provider` in initialize,
|
||||||
but we are already passing the Provider object via settings.
|
but we are already passing the Provider object via settings.
|
||||||
"""
|
"""
|
||||||
|
@@ -71,7 +71,7 @@ class APIHandler(BaseHandler):
|
|||||||
self.log.error("Couldn't parse JSON", exc_info=True)
|
self.log.error("Couldn't parse JSON", exc_info=True)
|
||||||
raise web.HTTPError(400, 'Invalid JSON in body of request')
|
raise web.HTTPError(400, 'Invalid JSON in body of request')
|
||||||
return model
|
return model
|
||||||
|
|
||||||
def write_error(self, status_code, **kwargs):
|
def write_error(self, status_code, **kwargs):
|
||||||
"""Write JSON errors instead of HTML"""
|
"""Write JSON errors instead of HTML"""
|
||||||
exc_info = kwargs.get('exc_info')
|
exc_info = kwargs.get('exc_info')
|
||||||
@@ -94,7 +94,7 @@ class APIHandler(BaseHandler):
|
|||||||
'message': message or status_message,
|
'message': message or status_message,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
def user_model(self, user):
|
async def user_model(self, user):
|
||||||
"""Get the JSON model for a User object"""
|
"""Get the JSON model for a User object"""
|
||||||
if isinstance(user, orm.User):
|
if isinstance(user, orm.User):
|
||||||
user = self.users[user.id]
|
user = self.users[user.id]
|
||||||
@@ -107,6 +107,7 @@ class APIHandler(BaseHandler):
|
|||||||
'server': user.url if user.running else None,
|
'server': user.url if user.running else None,
|
||||||
'pending': None,
|
'pending': None,
|
||||||
'last_activity': user.last_activity.isoformat(),
|
'last_activity': user.last_activity.isoformat(),
|
||||||
|
'auth_state': await user.get_auth_state(),
|
||||||
}
|
}
|
||||||
if '' in user.spawners:
|
if '' in user.spawners:
|
||||||
model['pending'] = user.spawners[''].pending or None
|
model['pending'] = user.spawners[''].pending or None
|
||||||
@@ -151,7 +152,7 @@ class APIHandler(BaseHandler):
|
|||||||
|
|
||||||
def _check_model(self, model, model_types, name):
|
def _check_model(self, model, model_types, name):
|
||||||
"""Check a model provided by a REST API request
|
"""Check a model provided by a REST API request
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
model (dict): user-provided model
|
model (dict): user-provided model
|
||||||
model_types (dict): dict of key:type used to validate types and keys
|
model_types (dict): dict of key:type used to validate types and keys
|
||||||
|
@@ -17,20 +17,20 @@ class SelfAPIHandler(APIHandler):
|
|||||||
|
|
||||||
Based on the authentication info. Acts as a 'whoami' for auth tokens.
|
Based on the authentication info. Acts as a 'whoami' for auth tokens.
|
||||||
"""
|
"""
|
||||||
def get(self):
|
async def get(self):
|
||||||
user = self.get_current_user()
|
user = self.get_current_user()
|
||||||
if user is None:
|
if user is None:
|
||||||
# whoami can be accessed via oauth token
|
# whoami can be accessed via oauth token
|
||||||
user = self.get_current_user_oauth_token()
|
user = self.get_current_user_oauth_token()
|
||||||
if user is None:
|
if user is None:
|
||||||
raise web.HTTPError(403)
|
raise web.HTTPError(403)
|
||||||
self.write(json.dumps(self.user_model(user)))
|
self.write(json.dumps(await self.user_model(user)))
|
||||||
|
|
||||||
|
|
||||||
class UserListAPIHandler(APIHandler):
|
class UserListAPIHandler(APIHandler):
|
||||||
@admin_only
|
@admin_only
|
||||||
def get(self):
|
async def get(self):
|
||||||
data = [ self.user_model(u) for u in self.db.query(orm.User) ]
|
data = [ await self.user_model(u) for u in self.db.query(orm.User) ]
|
||||||
self.write(json.dumps(data))
|
self.write(json.dumps(data))
|
||||||
|
|
||||||
@admin_only
|
@admin_only
|
||||||
@@ -44,7 +44,7 @@ class UserListAPIHandler(APIHandler):
|
|||||||
# admin is set for all users
|
# admin is set for all users
|
||||||
# to create admin and non-admin users requires at least two API requests
|
# to create admin and non-admin users requires at least two API requests
|
||||||
admin = data.get('admin', False)
|
admin = data.get('admin', False)
|
||||||
|
|
||||||
to_create = []
|
to_create = []
|
||||||
invalid_names = []
|
invalid_names = []
|
||||||
for name in usernames:
|
for name in usernames:
|
||||||
@@ -83,7 +83,7 @@ class UserListAPIHandler(APIHandler):
|
|||||||
else:
|
else:
|
||||||
created.append(user)
|
created.append(user)
|
||||||
|
|
||||||
self.write(json.dumps([ self.user_model(u) for u in created ]))
|
self.write(json.dumps([ await self.user_model(u) for u in created ]))
|
||||||
self.set_status(201)
|
self.set_status(201)
|
||||||
|
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ def admin_or_self(method):
|
|||||||
raise web.HTTPError(403)
|
raise web.HTTPError(403)
|
||||||
if not (current.name == name or current.admin):
|
if not (current.name == name or current.admin):
|
||||||
raise web.HTTPError(403)
|
raise web.HTTPError(403)
|
||||||
|
|
||||||
# raise 404 if not found
|
# raise 404 if not found
|
||||||
if not self.find_user(name):
|
if not self.find_user(name):
|
||||||
raise web.HTTPError(404)
|
raise web.HTTPError(404)
|
||||||
@@ -104,10 +104,12 @@ def admin_or_self(method):
|
|||||||
|
|
||||||
class UserAPIHandler(APIHandler):
|
class UserAPIHandler(APIHandler):
|
||||||
|
|
||||||
|
#@gen.coroutine
|
||||||
@admin_or_self
|
@admin_or_self
|
||||||
def get(self, name):
|
async def get(self, name):
|
||||||
user = self.find_user(name)
|
user = self.find_user(name)
|
||||||
self.write(json.dumps(self.user_model(user)))
|
user = await self.user_model(user)
|
||||||
|
self.write(json.dumps(user))
|
||||||
|
|
||||||
@admin_only
|
@admin_only
|
||||||
async def post(self, name):
|
async def post(self, name):
|
||||||
@@ -131,7 +133,7 @@ class UserAPIHandler(APIHandler):
|
|||||||
self.users.delete(user)
|
self.users.delete(user)
|
||||||
raise web.HTTPError(400, "Failed to create user: %s" % name)
|
raise web.HTTPError(400, "Failed to create user: %s" % name)
|
||||||
|
|
||||||
self.write(json.dumps(self.user_model(user)))
|
self.write(json.dumps(await self.user_model(user)))
|
||||||
self.set_status(201)
|
self.set_status(201)
|
||||||
|
|
||||||
@admin_only
|
@admin_only
|
||||||
@@ -155,7 +157,7 @@ class UserAPIHandler(APIHandler):
|
|||||||
self.set_status(204)
|
self.set_status(204)
|
||||||
|
|
||||||
@admin_only
|
@admin_only
|
||||||
def patch(self, name):
|
async def patch(self, name):
|
||||||
user = self.find_user(name)
|
user = self.find_user(name)
|
||||||
if user is None:
|
if user is None:
|
||||||
raise web.HTTPError(404)
|
raise web.HTTPError(404)
|
||||||
@@ -168,7 +170,7 @@ class UserAPIHandler(APIHandler):
|
|||||||
for key, value in data.items():
|
for key, value in data.items():
|
||||||
setattr(user, key, value)
|
setattr(user, key, value)
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
self.write(json.dumps(self.user_model(user)))
|
self.write(json.dumps(await self.user_model(user)))
|
||||||
|
|
||||||
|
|
||||||
class UserServerAPIHandler(APIHandler):
|
class UserServerAPIHandler(APIHandler):
|
||||||
|
@@ -201,6 +201,7 @@ def test_get_users(app):
|
|||||||
'admin': True,
|
'admin': True,
|
||||||
'server': None,
|
'server': None,
|
||||||
'pending': None,
|
'pending': None,
|
||||||
|
'auth_state': None,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'kind': 'user',
|
'kind': 'user',
|
||||||
@@ -209,6 +210,7 @@ def test_get_users(app):
|
|||||||
'admin': False,
|
'admin': False,
|
||||||
'server': None,
|
'server': None,
|
||||||
'pending': None,
|
'pending': None,
|
||||||
|
'auth_state': None,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -280,6 +282,7 @@ def test_get_user(app):
|
|||||||
'admin': False,
|
'admin': False,
|
||||||
'server': None,
|
'server': None,
|
||||||
'pending': None,
|
'pending': None,
|
||||||
|
'auth_state': None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -593,7 +596,7 @@ def test_spawn_limit(app, no_patience, slow_spawn, request):
|
|||||||
user.spawner._start_future = Future()
|
user.spawner._start_future = Future()
|
||||||
r = yield api_request(app, 'users', name, 'server', method='post')
|
r = yield api_request(app, 'users', name, 'server', method='post')
|
||||||
assert r.status_code == 429
|
assert r.status_code == 429
|
||||||
|
|
||||||
# allow ykka to start
|
# allow ykka to start
|
||||||
users[0].spawner._start_future.set_result(None)
|
users[0].spawner._start_future.set_result(None)
|
||||||
# wait for ykka to finish
|
# wait for ykka to finish
|
||||||
|
@@ -36,6 +36,7 @@ def test_default_server(app, named_servers):
|
|||||||
'kind': 'user',
|
'kind': 'user',
|
||||||
'admin': False,
|
'admin': False,
|
||||||
'pending': None,
|
'pending': None,
|
||||||
|
'auth_state': None,
|
||||||
'server': user.url,
|
'server': user.url,
|
||||||
'servers': {
|
'servers': {
|
||||||
'': {
|
'': {
|
||||||
@@ -63,6 +64,7 @@ def test_default_server(app, named_servers):
|
|||||||
'pending': None,
|
'pending': None,
|
||||||
'server': None,
|
'server': None,
|
||||||
'servers': {},
|
'servers': {},
|
||||||
|
'auth_state': None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -99,6 +101,7 @@ def test_create_named_server(app, named_servers):
|
|||||||
'kind': 'user',
|
'kind': 'user',
|
||||||
'admin': False,
|
'admin': False,
|
||||||
'pending': None,
|
'pending': None,
|
||||||
|
'auth_state': None,
|
||||||
'server': None,
|
'server': None,
|
||||||
'servers': {
|
'servers': {
|
||||||
servername: {
|
servername: {
|
||||||
@@ -136,6 +139,7 @@ def test_delete_named_server(app, named_servers):
|
|||||||
'kind': 'user',
|
'kind': 'user',
|
||||||
'admin': False,
|
'admin': False,
|
||||||
'pending': None,
|
'pending': None,
|
||||||
|
'auth_state': None,
|
||||||
'server': None,
|
'server': None,
|
||||||
'servers': {
|
'servers': {
|
||||||
name: {
|
name: {
|
||||||
|
Reference in New Issue
Block a user