mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-13 13:03:01 +00:00
@@ -12,9 +12,24 @@ from .base import APIHandler
|
||||
|
||||
|
||||
|
||||
class AuthorizationsAPIHandler(APIHandler):
|
||||
class TokenAPIHandler(APIHandler):
|
||||
@token_authenticated
|
||||
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()
|
||||
if orm_token is None:
|
||||
raise web.HTTPError(404)
|
||||
@@ -23,5 +38,6 @@ class AuthorizationsAPIHandler(APIHandler):
|
||||
}))
|
||||
|
||||
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):
|
||||
"""get_current_user from a cookie token"""
|
||||
token = self.get_cookie(self.hub.server.cookie_name, None)
|
||||
if token:
|
||||
btoken = self.get_secure_cookie(self.hub.server.cookie_name)
|
||||
if btoken:
|
||||
token = btoken.decode('utf8', 'replace')
|
||||
cookie_token = orm.CookieToken.find(self.db, token)
|
||||
if cookie_token:
|
||||
return cookie_token.user
|
||||
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.
|
||||
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()
|
||||
self.db.add(cookie_token)
|
||||
self.db.commit()
|
||||
self.set_cookie(
|
||||
self.set_secure_cookie(
|
||||
user.server.cookie_name,
|
||||
cookie_token.token,
|
||||
path=user.server.base_url,
|
||||
@@ -139,7 +142,7 @@ class BaseHandler(RequestHandler):
|
||||
cookie_token = user.new_cookie_token()
|
||||
self.db.add(cookie_token)
|
||||
self.db.commit()
|
||||
self.set_cookie(
|
||||
self.set_secure_cookie(
|
||||
self.hub.server.cookie_name,
|
||||
cookie_token.token,
|
||||
path=self.hub.server.base_url)
|
||||
|
@@ -299,7 +299,6 @@ class User(Base):
|
||||
hub = db.query(Hub).first()
|
||||
self.server = Server(
|
||||
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),
|
||||
)
|
||||
db.add(self.server)
|
||||
|
@@ -28,19 +28,20 @@ if V(IPython.__version__) < V('2.2'):
|
||||
# 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"""
|
||||
token_cache = self.settings['token_cache']
|
||||
if token in token_cache:
|
||||
cookie_cache = self.settings['cookie_cache']
|
||||
if encrypted_cookie in cookie_cache:
|
||||
# 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_key = self.settings['hub_api_key']
|
||||
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:
|
||||
data = {'user' : ''}
|
||||
@@ -49,16 +50,16 @@ def verify_token(self, token):
|
||||
data = None
|
||||
else:
|
||||
data = r.json()
|
||||
token_cache[token] = data
|
||||
cookie_cache[encrypted_cookie] = data
|
||||
return data
|
||||
|
||||
|
||||
def get_current_user(self):
|
||||
"""alternative get_current_user to query the central server"""
|
||||
my_user = self.settings['user']
|
||||
token = self.get_cookie(self.cookie_name, '')
|
||||
if token:
|
||||
auth_data = self.verify_token(token)
|
||||
encrypted_cookie = self.get_cookie(self.cookie_name)
|
||||
if encrypted_cookie:
|
||||
auth_data = self.verify_token(self.cookie_name, encrypted_cookie)
|
||||
if not auth_data:
|
||||
# treat invalid token the same as no token
|
||||
return None
|
||||
@@ -123,10 +124,9 @@ class SingleUserNotebookApp(NotebookApp):
|
||||
s = getattr(self, 'tornado_settings',
|
||||
getattr(self, 'webapp_settings')
|
||||
)
|
||||
s['token_cache'] = {}
|
||||
s['cookie_cache'] = {}
|
||||
s['user'] = self.user
|
||||
s['hub_api_key'] = env.pop('JPY_API_TOKEN')
|
||||
s['cookie_secret'] = env.pop('JPY_COOKIE_SECRET')
|
||||
s['cookie_name'] = self.cookie_name
|
||||
s['login_url'] = url_path_join(self.hub_prefix, 'login')
|
||||
s['hub_api_url'] = self.hub_api_url
|
||||
|
@@ -65,7 +65,6 @@ class Spawner(LoggingConfigurable):
|
||||
for key in self.env_keep:
|
||||
if key in os.environ:
|
||||
env[key] = os.environ[key]
|
||||
env['JPY_COOKIE_SECRET'] = self.user.server.cookie_secret
|
||||
env['JPY_API_TOKEN'] = self.api_token
|
||||
return env
|
||||
|
||||
|
@@ -48,23 +48,25 @@ def test_auth_api(app):
|
||||
|
||||
# make a new cookie token
|
||||
user = db.query(orm.User).first()
|
||||
api_token = user.new_api_token()
|
||||
db.add(api_token)
|
||||
cookie_token = user.new_cookie_token()
|
||||
db.add(cookie_token)
|
||||
db.commit()
|
||||
|
||||
# check success:
|
||||
r = api_request(app, 'authorizations', cookie_token.token)
|
||||
r = api_request(app, 'authorizations/token', api_token.token)
|
||||
assert r.status_code == 200
|
||||
reply = r.json()
|
||||
assert reply['user'] == user.name
|
||||
|
||||
# check fail
|
||||
r = api_request(app, 'authorizations', cookie_token.token,
|
||||
r = api_request(app, 'authorizations/token', api_token.token,
|
||||
headers={'Authorization': 'no sir'},
|
||||
)
|
||||
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},
|
||||
)
|
||||
assert r.status_code == 403
|
||||
|
Reference in New Issue
Block a user