mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-16 14:33:00 +00:00
add a notion of admin users
and an @admin_only decorator for restricted methods
This commit is contained in:
@@ -158,6 +158,12 @@ class JupyterHubApp(Application):
|
||||
debug_db = Bool(False)
|
||||
db = Any()
|
||||
|
||||
admin_users = Set(config=True,
|
||||
help="""list of usernames of admin users
|
||||
|
||||
If unspecified, all users are admin.
|
||||
"""
|
||||
)
|
||||
tornado_settings = Dict(config=True)
|
||||
|
||||
handlers = List()
|
||||
@@ -300,6 +306,7 @@ class JupyterHubApp(Application):
|
||||
log=self.log,
|
||||
db=self.db,
|
||||
hub=self.hub,
|
||||
admin_users=self.admin_users,
|
||||
authenticator=import_item(self.authenticator)(config=self.config),
|
||||
spawner_class=import_item(self.spawner_class),
|
||||
base_url=base_url,
|
||||
|
@@ -56,6 +56,10 @@ class BaseHandler(RequestHandler):
|
||||
# Login and cookie-related
|
||||
#---------------------------------------------------------------
|
||||
|
||||
@property
|
||||
def admin_users(self):
|
||||
return self.settings.setdefault('admin_users', set())
|
||||
|
||||
def get_current_user_token(self):
|
||||
"""get_current_user from Authorization header token"""
|
||||
auth_header = self.request.headers.get('Authorization', '')
|
||||
@@ -90,10 +94,10 @@ class BaseHandler(RequestHandler):
|
||||
|
||||
def user_from_username(self, username):
|
||||
"""Get ORM User for username"""
|
||||
|
||||
user = self.db.query(orm.User).filter(orm.User.name==username).first()
|
||||
if user is None:
|
||||
user = orm.User(name=username)
|
||||
admin = (not self.admin_users) or username in self.admin_users
|
||||
user = orm.User(name=username, admin=admin)
|
||||
self.db.add(user)
|
||||
self.db.commit()
|
||||
return user
|
||||
|
@@ -8,7 +8,7 @@ import uuid
|
||||
|
||||
from sqlalchemy.types import TypeDecorator, VARCHAR
|
||||
from sqlalchemy import (
|
||||
Column, Integer, String, ForeignKey, Unicode, Binary,
|
||||
Column, Integer, String, ForeignKey, Unicode, Binary, Boolean,
|
||||
)
|
||||
from sqlalchemy.ext.declarative import declarative_base, declared_attr
|
||||
from sqlalchemy.orm import sessionmaker, relationship, backref
|
||||
@@ -157,6 +157,7 @@ class User(Base):
|
||||
# should we allow multiple servers per user?
|
||||
_server_id = Column(Integer, ForeignKey('servers.id'))
|
||||
server = relationship(Server, primaryjoin=_server_id == Server.id)
|
||||
admin = Column(Boolean, default=False)
|
||||
|
||||
api_tokens = relationship("APIToken", backref="user")
|
||||
cookie_tokens = relationship("CookieToken", backref="user")
|
||||
|
@@ -29,24 +29,42 @@ def wait_for_server(ip, port, timeout=10):
|
||||
else:
|
||||
break
|
||||
|
||||
def auth_decorator(check_auth):
|
||||
"""Make an authentication decorator
|
||||
|
||||
def token_authenticated(method):
|
||||
"""decorator for a method authenticated only by the Authorization token header"""
|
||||
def check_token(self, *args, **kwargs):
|
||||
if self.get_current_user_token() is None:
|
||||
raise web.HTTPError(403)
|
||||
return method(self, *args, **kwargs)
|
||||
check_token.__name__ = method.__name__
|
||||
check_token.__doc__ = method.__doc__
|
||||
return check_token
|
||||
I heard you like decorators, so I put a decorator
|
||||
in your decorator, so you can decorate while you decorate.
|
||||
"""
|
||||
def decorator(method):
|
||||
def decorated(self, *args, **kwargs):
|
||||
check_auth(self)
|
||||
return method(self, *args)
|
||||
decorated.__name__ = method.__name__
|
||||
decorated.__doc__ = method.__doc__
|
||||
return decorated
|
||||
|
||||
decorator.__name__ = check_auth.__name__
|
||||
decorator.__doc__ = check_auth.__doc__
|
||||
return decorator
|
||||
|
||||
def authenticated_403(method):
|
||||
"""decorator like web.authenticated, but raise 403 instead of redirect to login"""
|
||||
def check_user(self, *args, **kwargs):
|
||||
if self.get_current_user() is None:
|
||||
raise web.HTTPError(403)
|
||||
return method(self, *args, **kwargs)
|
||||
check_user.__name__ = method.__name__
|
||||
check_user.__doc__ = method.__doc__
|
||||
return check_user
|
||||
@auth_decorator
|
||||
def token_authenticated(self):
|
||||
"""decorator for a method authenticated only by the Authorization token header
|
||||
|
||||
(no cookies)
|
||||
"""
|
||||
if self.get_current_user_token() is None:
|
||||
raise web.HTTPError(403)
|
||||
|
||||
@auth_decorator
|
||||
def authenticated_403(self):
|
||||
"""like web.authenticated, but raise 403 instead of redirect to login"""
|
||||
if self.get_current_user() is None:
|
||||
raise web.HTTPError(403)
|
||||
|
||||
@auth_decorator
|
||||
def admin_only(self):
|
||||
"""decorator for restricting access to admin users"""
|
||||
user = self.get_current_user()
|
||||
if user is None or not user.admin:
|
||||
raise web.HTTPError(403)
|
||||
|
Reference in New Issue
Block a user