mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-14 13:33:00 +00:00
Merge pull request #1859 from minrk/auth-token
Allow Authenticators to authenticate requests for API tokens
This commit is contained in:
@@ -214,18 +214,39 @@ class UserTokenListAPIHandler(APIHandler):
|
|||||||
'oauth_tokens': oauth_tokens,
|
'oauth_tokens': oauth_tokens,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
@admin_or_self
|
async def post(self, name):
|
||||||
def post(self, name):
|
body = self.get_json_body() or {}
|
||||||
|
if not isinstance(body, dict):
|
||||||
|
raise web.HTTPError(400, "Body must be a JSON dict or empty")
|
||||||
|
|
||||||
requester = self.get_current_user()
|
requester = self.get_current_user()
|
||||||
|
if requester is None:
|
||||||
|
# defer to Authenticator for identifying the user
|
||||||
|
# can be username+password or an upstream auth token
|
||||||
|
try:
|
||||||
|
name = await self.authenticator.authenticate(self, body.get('auth'))
|
||||||
|
except web.HTTPError as e:
|
||||||
|
# turn any authentication error into 403
|
||||||
|
raise web.HTTPError(403)
|
||||||
|
except Exception as e:
|
||||||
|
# suppress and log error here in case Authenticator
|
||||||
|
# isn't prepared to handle auth via this data
|
||||||
|
self.log.error("Error authenticating request for %s: %s",
|
||||||
|
self.request.uri, e)
|
||||||
|
raise web.HTTPError(403)
|
||||||
|
requester = self.find_user(name)
|
||||||
|
if requester is None:
|
||||||
|
# couldn't identify requester
|
||||||
|
raise web.HTTPError(403)
|
||||||
user = self.find_user(name)
|
user = self.find_user(name)
|
||||||
if requester is not user and not requester.admin:
|
if requester is not user and not requester.admin:
|
||||||
raise web.HTTPError(403, "Only admins can request tokens for other users")
|
raise web.HTTPError(403, "Only admins can request tokens for other users")
|
||||||
if not user:
|
if not user:
|
||||||
raise web.HTTPError(404, "No such user: %s" % name)
|
raise web.HTTPError(404, "No such user: %s" % name)
|
||||||
body = self.get_json_body()
|
|
||||||
if requester is not user:
|
if requester is not user:
|
||||||
kind = 'user' if isinstance(requester, User) else 'service'
|
kind = 'user' if isinstance(requester, User) else 'service'
|
||||||
note = (body or {}).get('note')
|
|
||||||
|
note = body.get('note')
|
||||||
if not note:
|
if not note:
|
||||||
note = "Requested via api"
|
note = "Requested via api"
|
||||||
if requester is not user:
|
if requester is not user:
|
||||||
|
@@ -1289,6 +1289,31 @@ def test_token_for_user(app, as_user, for_user, status):
|
|||||||
)
|
)
|
||||||
assert r.status_code == 404
|
assert r.status_code == 404
|
||||||
|
|
||||||
|
|
||||||
|
@mark.gen_test
|
||||||
|
def test_token_authenticator_noauth(app):
|
||||||
|
"""Create a token for a user relying on Authenticator.authenticate and no auth header"""
|
||||||
|
name = 'user'
|
||||||
|
data = {
|
||||||
|
'auth': {
|
||||||
|
'username': name,
|
||||||
|
'password': name,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
r = yield api_request(app, 'users', name, 'tokens',
|
||||||
|
method='post',
|
||||||
|
data=json.dumps(data) if data else None,
|
||||||
|
noauth=True,
|
||||||
|
)
|
||||||
|
assert r.status_code == 200
|
||||||
|
reply = r.json()
|
||||||
|
assert 'token' in reply
|
||||||
|
r = yield api_request(app, 'authorizations', 'token', reply['token'])
|
||||||
|
r.raise_for_status()
|
||||||
|
reply = r.json()
|
||||||
|
assert reply['name'] == name
|
||||||
|
|
||||||
|
|
||||||
@mark.gen_test
|
@mark.gen_test
|
||||||
@mark.parametrize("as_user, for_user, status", [
|
@mark.parametrize("as_user, for_user, status", [
|
||||||
('admin', 'other', 200),
|
('admin', 'other', 200),
|
||||||
|
Reference in New Issue
Block a user