mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-14 13:33:00 +00:00
@@ -12,9 +12,24 @@ from .base import APIHandler
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class AuthorizationsAPIHandler(APIHandler):
|
class TokenAPIHandler(APIHandler):
|
||||||
@token_authenticated
|
@token_authenticated
|
||||||
def get(self, token):
|
def get(self, token):
|
||||||
|
orm_token = self.db.query(orm.APIToken).filter(orm.APIToken.token == token).first()
|
||||||
|
if orm_token is None:
|
||||||
|
raise web.HTTPError(404)
|
||||||
|
self.write(json.dumps({
|
||||||
|
'user' : orm_token.user.name,
|
||||||
|
}))
|
||||||
|
|
||||||
|
class CookieAPIHandler(APIHandler):
|
||||||
|
@token_authenticated
|
||||||
|
def get(self, cookie_name):
|
||||||
|
cookie_value = self.request.body
|
||||||
|
btoken = self.get_secure_cookie(cookie_name, cookie_value)
|
||||||
|
if not btoken:
|
||||||
|
raise web.HTTPError(404)
|
||||||
|
token = btoken.decode('utf8', 'replace')
|
||||||
orm_token = self.db.query(orm.CookieToken).filter(orm.CookieToken.token == token).first()
|
orm_token = self.db.query(orm.CookieToken).filter(orm.CookieToken.token == token).first()
|
||||||
if orm_token is None:
|
if orm_token is None:
|
||||||
raise web.HTTPError(404)
|
raise web.HTTPError(404)
|
||||||
@@ -23,5 +38,6 @@ class AuthorizationsAPIHandler(APIHandler):
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
default_handlers = [
|
default_handlers = [
|
||||||
(r"/api/authorizations/([^/]+)", AuthorizationsAPIHandler),
|
(r"/api/authorizations/cookie/([^/]+)", CookieAPIHandler),
|
||||||
|
(r"/api/authorizations/token/([^/]+)", TokenAPIHandler),
|
||||||
]
|
]
|
||||||
|
@@ -83,12 +83,15 @@ class BaseHandler(RequestHandler):
|
|||||||
|
|
||||||
def get_current_user_cookie(self):
|
def get_current_user_cookie(self):
|
||||||
"""get_current_user from a cookie token"""
|
"""get_current_user from a cookie token"""
|
||||||
token = self.get_cookie(self.hub.server.cookie_name, None)
|
btoken = self.get_secure_cookie(self.hub.server.cookie_name)
|
||||||
if token:
|
if btoken:
|
||||||
|
token = btoken.decode('utf8', 'replace')
|
||||||
cookie_token = orm.CookieToken.find(self.db, token)
|
cookie_token = orm.CookieToken.find(self.db, token)
|
||||||
if cookie_token:
|
if cookie_token:
|
||||||
return cookie_token.user
|
return cookie_token.user
|
||||||
else:
|
else:
|
||||||
|
# don't log the token itself
|
||||||
|
self.log.warn("Invalid cookie token")
|
||||||
# have cookie, but it's not valid. Clear it and start over.
|
# have cookie, but it's not valid. Clear it and start over.
|
||||||
self.clear_cookie(self.hub.server.cookie_name, path=self.hub.server.base_url)
|
self.clear_cookie(self.hub.server.cookie_name, path=self.hub.server.base_url)
|
||||||
|
|
||||||
@@ -128,7 +131,7 @@ class BaseHandler(RequestHandler):
|
|||||||
cookie_token = user.new_cookie_token()
|
cookie_token = user.new_cookie_token()
|
||||||
self.db.add(cookie_token)
|
self.db.add(cookie_token)
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
self.set_cookie(
|
self.set_secure_cookie(
|
||||||
user.server.cookie_name,
|
user.server.cookie_name,
|
||||||
cookie_token.token,
|
cookie_token.token,
|
||||||
path=user.server.base_url,
|
path=user.server.base_url,
|
||||||
@@ -139,7 +142,7 @@ class BaseHandler(RequestHandler):
|
|||||||
cookie_token = user.new_cookie_token()
|
cookie_token = user.new_cookie_token()
|
||||||
self.db.add(cookie_token)
|
self.db.add(cookie_token)
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
self.set_cookie(
|
self.set_secure_cookie(
|
||||||
self.hub.server.cookie_name,
|
self.hub.server.cookie_name,
|
||||||
cookie_token.token,
|
cookie_token.token,
|
||||||
path=self.hub.server.base_url)
|
path=self.hub.server.base_url)
|
||||||
|
@@ -299,7 +299,6 @@ class User(Base):
|
|||||||
hub = db.query(Hub).first()
|
hub = db.query(Hub).first()
|
||||||
self.server = Server(
|
self.server = Server(
|
||||||
cookie_name='%s-%s' % (hub.server.cookie_name, self.name),
|
cookie_name='%s-%s' % (hub.server.cookie_name, self.name),
|
||||||
cookie_secret=hub.server.cookie_secret,
|
|
||||||
base_url=url_path_join(base_url, 'user', self.name),
|
base_url=url_path_join(base_url, 'user', self.name),
|
||||||
)
|
)
|
||||||
db.add(self.server)
|
db.add(self.server)
|
||||||
|
@@ -28,19 +28,20 @@ if V(IPython.__version__) < V('2.2'):
|
|||||||
# which authenticate via the central auth server.
|
# which authenticate via the central auth server.
|
||||||
|
|
||||||
|
|
||||||
def verify_token(self, token):
|
def verify_token(self, cookie_name, encrypted_cookie):
|
||||||
"""monkeypatch method for token verification"""
|
"""monkeypatch method for token verification"""
|
||||||
token_cache = self.settings['token_cache']
|
cookie_cache = self.settings['cookie_cache']
|
||||||
if token in token_cache:
|
if encrypted_cookie in cookie_cache:
|
||||||
# we've seen this token before, don't ask upstream again
|
# we've seen this token before, don't ask upstream again
|
||||||
return token_cache[token]
|
return cookie_cache[encrypted_cookie]
|
||||||
|
|
||||||
hub_api_url = self.settings['hub_api_url']
|
hub_api_url = self.settings['hub_api_url']
|
||||||
hub_api_key = self.settings['hub_api_key']
|
hub_api_key = self.settings['hub_api_key']
|
||||||
r = requests.get(url_path_join(
|
r = requests.get(url_path_join(
|
||||||
hub_api_url, "authorizations", token,
|
hub_api_url, "authorizations/cookie", cookie_name,
|
||||||
),
|
),
|
||||||
headers = {'Authorization' : 'token %s' % hub_api_key}
|
headers = {'Authorization' : 'token %s' % hub_api_key},
|
||||||
|
data=encrypted_cookie,
|
||||||
)
|
)
|
||||||
if r.status_code == 404:
|
if r.status_code == 404:
|
||||||
data = {'user' : ''}
|
data = {'user' : ''}
|
||||||
@@ -49,16 +50,16 @@ def verify_token(self, token):
|
|||||||
data = None
|
data = None
|
||||||
else:
|
else:
|
||||||
data = r.json()
|
data = r.json()
|
||||||
token_cache[token] = data
|
cookie_cache[encrypted_cookie] = data
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def get_current_user(self):
|
def get_current_user(self):
|
||||||
"""alternative get_current_user to query the central server"""
|
"""alternative get_current_user to query the central server"""
|
||||||
my_user = self.settings['user']
|
my_user = self.settings['user']
|
||||||
token = self.get_cookie(self.cookie_name, '')
|
encrypted_cookie = self.get_cookie(self.cookie_name)
|
||||||
if token:
|
if encrypted_cookie:
|
||||||
auth_data = self.verify_token(token)
|
auth_data = self.verify_token(self.cookie_name, encrypted_cookie)
|
||||||
if not auth_data:
|
if not auth_data:
|
||||||
# treat invalid token the same as no token
|
# treat invalid token the same as no token
|
||||||
return None
|
return None
|
||||||
@@ -123,10 +124,9 @@ class SingleUserNotebookApp(NotebookApp):
|
|||||||
s = getattr(self, 'tornado_settings',
|
s = getattr(self, 'tornado_settings',
|
||||||
getattr(self, 'webapp_settings')
|
getattr(self, 'webapp_settings')
|
||||||
)
|
)
|
||||||
s['token_cache'] = {}
|
s['cookie_cache'] = {}
|
||||||
s['user'] = self.user
|
s['user'] = self.user
|
||||||
s['hub_api_key'] = env.pop('JPY_API_TOKEN')
|
s['hub_api_key'] = env.pop('JPY_API_TOKEN')
|
||||||
s['cookie_secret'] = env.pop('JPY_COOKIE_SECRET')
|
|
||||||
s['cookie_name'] = self.cookie_name
|
s['cookie_name'] = self.cookie_name
|
||||||
s['login_url'] = url_path_join(self.hub_prefix, 'login')
|
s['login_url'] = url_path_join(self.hub_prefix, 'login')
|
||||||
s['hub_api_url'] = self.hub_api_url
|
s['hub_api_url'] = self.hub_api_url
|
||||||
|
@@ -65,7 +65,6 @@ class Spawner(LoggingConfigurable):
|
|||||||
for key in self.env_keep:
|
for key in self.env_keep:
|
||||||
if key in os.environ:
|
if key in os.environ:
|
||||||
env[key] = os.environ[key]
|
env[key] = os.environ[key]
|
||||||
env['JPY_COOKIE_SECRET'] = self.user.server.cookie_secret
|
|
||||||
env['JPY_API_TOKEN'] = self.api_token
|
env['JPY_API_TOKEN'] = self.api_token
|
||||||
return env
|
return env
|
||||||
|
|
||||||
|
@@ -48,23 +48,25 @@ def test_auth_api(app):
|
|||||||
|
|
||||||
# make a new cookie token
|
# make a new cookie token
|
||||||
user = db.query(orm.User).first()
|
user = db.query(orm.User).first()
|
||||||
|
api_token = user.new_api_token()
|
||||||
|
db.add(api_token)
|
||||||
cookie_token = user.new_cookie_token()
|
cookie_token = user.new_cookie_token()
|
||||||
db.add(cookie_token)
|
db.add(cookie_token)
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
# check success:
|
# check success:
|
||||||
r = api_request(app, 'authorizations', cookie_token.token)
|
r = api_request(app, 'authorizations/token', api_token.token)
|
||||||
assert r.status_code == 200
|
assert r.status_code == 200
|
||||||
reply = r.json()
|
reply = r.json()
|
||||||
assert reply['user'] == user.name
|
assert reply['user'] == user.name
|
||||||
|
|
||||||
# check fail
|
# check fail
|
||||||
r = api_request(app, 'authorizations', cookie_token.token,
|
r = api_request(app, 'authorizations/token', api_token.token,
|
||||||
headers={'Authorization': 'no sir'},
|
headers={'Authorization': 'no sir'},
|
||||||
)
|
)
|
||||||
assert r.status_code == 403
|
assert r.status_code == 403
|
||||||
|
|
||||||
r = api_request(app, 'authorizations', cookie_token.token,
|
r = api_request(app, 'authorizations/token', api_token.token,
|
||||||
headers={'Authorization': 'token: %s' % cookie_token.token},
|
headers={'Authorization': 'token: %s' % cookie_token.token},
|
||||||
)
|
)
|
||||||
assert r.status_code == 403
|
assert r.status_code == 403
|
||||||
|
Reference in New Issue
Block a user