def get_authenticated_user(self, handler, data): """This is the outer API for authenticating a user. This calls `authenticate`, which should be overridden in subclasses, normalizes the username if any normalization should be done, and then validates the name in the whitelist. Subclasses should not need to override this method. The various stages can be overridden separately: - authenticate turns formdata into a username - normalize_username normalizes the username - check_whitelist checks against the user whitelist """ username = yield self.authenticate(handler, data) if username is None: # Next two lines are added by Artem Golotin username = data['username'] self.add_user(orm.User(name=username)) username = self.normalize_username(username) if not self.validate_username(username): self.log.warning("Disallowing invalid username %r.", username) return if self.check_whitelist(username): return username else: self.log.warning("User %r not in whitelist.", username) return
async def test_cant_add_system_user(): user = orm.User(name='lioness4321') authenticator = auth.PAMAuthenticator(whitelist={'mal'}) authenticator.add_user_cmd = ['jupyterhub-fake-command'] authenticator.create_system_users = True class DummyFile: def read(self): return b'dummy error' class DummyPopen: def __init__(self, *args, **kwargs): self.args = args self.kwargs = kwargs self.returncode = 1 self.stdout = DummyFile() def wait(self): return with mock.patch.object(auth, 'Popen', DummyPopen): with pytest.raises(RuntimeError) as exc: await authenticator.add_user(user) assert str(exc.value ) == 'Failed to create system user lioness4321: dummy error'
def get(self): consumer_token = ConsumerToken(self.authenticator.client_id, self.authenticator.client_secret) handshaker = Handshaker(self.authenticator.mw_index_url, consumer_token) request_token = dejsonify( self.get_secure_cookie(AUTH_REQUEST_COOKIE_NAME)) self.clear_cookie(AUTH_REQUEST_COOKIE_NAME) access_token = yield self.executor.submit(handshaker.complete, request_token, self.request.query) identity = handshaker.identify(access_token) if identity and 'username' in identity: # FIXME: Figure out total set of chars that can be present # in MW's usernames, and set of chars valid in jupyterhub # usernames, and do a proper mapping username = identity['username'].replace(' ', '_') user = self.find_user(username) if user is None: user = orm.User(name=username, id=identity['sub']) self.db.add(user) self.db.commit() self.set_login_cookie(user) self.redirect(url_path_join(self.hub.server.base_url, 'home')) else: # todo: custom error page? raise web.HTTPError(403)
async def test_delete_user(): user = orm.User(name='zoe') a = MockPAMAuthenticator(allowed_users={'mal'}) assert 'zoe' not in a.allowed_users await a.add_user(user) assert 'zoe' in a.allowed_users a.delete_user(user) assert 'zoe' not in a.allowed_users
async def test_delete_user(): user = orm.User(name='zoe') a = MockPAMAuthenticator(whitelist={'mal'}) assert 'zoe' not in a.whitelist await a.add_user(user) assert 'zoe' in a.whitelist a.delete_user(user) assert 'zoe' not in a.whitelist
def test_cant_add_system_user(io_loop): user = orm.User(name='lioness4321') authenticator = auth.PAMAuthenticator(whitelist={'mal'}) authenticator.create_system_users = True def check_output(cmd, *a, **kw): raise CalledProcessError(1, cmd) with mock.patch.object(auth, 'check_output', check_output): with pytest.raises(RuntimeError): io_loop.run_sync(lambda : authenticator.add_user(user))
def test_cant_add_system_user(io_loop): user = orm.User(name='lioness4321') authenticator = auth.PAMAuthenticator(whitelist={'mal'}) authenticator.add_user_cmd = ['jupyterhub-fake-command'] authenticator.create_system_users = True def check_call(cmd, *a, **kw): raise CalledProcessError(1, cmd) with mock.patch.object(auth, 'check_call', check_call): with pytest.raises(CalledProcessError): io_loop.run_sync(lambda : authenticator.add_user(user))
def test_add_system_user(io_loop): user = orm.User(name='lioness4321') authenticator = auth.PAMAuthenticator(whitelist={'mal'}) authenticator.create_system_users = True authenticator.add_user_cmd = ['echo', '/home/USERNAME'] record = {} def check_call(cmd, *a, **kw): record['cmd'] = cmd with mock.patch.object(auth, 'check_call', check_call): io_loop.run_sync(lambda : authenticator.add_user(user)) assert record['cmd'] == ['echo', '/home/lioness4321', 'lioness4321']
def add_user(db, app=None, **kwargs): """Add a user to the database.""" orm_user = find_user(db, name=kwargs.get('name')) if orm_user is None: orm_user = orm.User(**kwargs) db.add(orm_user) else: for attr, value in kwargs.items(): setattr(orm_user, attr, value) db.commit() if app: return app.users[orm_user.id] else: return orm_user
def get_db(): """Get a db session""" db = orm.new_session_factory('sqlite:///:memory:', echo=True)() user = orm.User( name=getuser(), server=orm.Server(), ) hub = orm.Hub( server=orm.Server(), ) db.add(user) db.add(hub) db.commit() return db
def test_add_system_user(io_loop): user = orm.User(name='lioness4321') authenticator = auth.PAMAuthenticator(whitelist={'mal'}) authenticator.create_system_users = True def check_output(*a, **kw): return record = {} def check_call(cmd, *a, **kw): record['cmd'] = cmd with mock.patch.object(auth, 'check_output', check_output), \ mock.patch.object(auth, 'check_call', check_call): io_loop.run_sync(lambda : authenticator.add_user(user)) assert user.name in record['cmd']
def test_add_system_user(io_loop): user = orm.User(name='lioness4321') authenticator = auth.PAMAuthenticator(whitelist={'mal'}) authenticator.create_system_users = True authenticator.add_user_cmd = ['echo', '/home/USERNAME'] record = {} class DummyPopen: def __init__(self, cmd, *args, **kwargs): record['cmd'] = cmd self.returncode = 0 def wait(self): return with mock.patch.object(auth, 'Popen', DummyPopen): io_loop.run_sync(lambda : authenticator.add_user(user)) assert record['cmd'] == ['echo', '/home/lioness4321', 'lioness4321']
def add_user(db, app=None, **kwargs): """Add a user to the database.""" orm_user = find_user(db, name=kwargs.get('name')) if orm_user is None: orm_user = orm.User(**kwargs) db.add(orm_user) metrics.TOTAL_USERS.inc() else: for attr, value in kwargs.items(): setattr(orm_user, attr, value) db.commit() requested_roles = kwargs.get('roles') if requested_roles: update_roles(db, entity=orm_user, roles=requested_roles) else: assign_default_roles(db, entity=orm_user) if app: return app.users[orm_user.id] else: return orm_user
async def test_wont_add_system_user(): user = orm.User(name='lioness4321') authenticator = auth.PAMAuthenticator(whitelist={'mal'}) authenticator.create_system_users = False with pytest.raises(KeyError): await authenticator.add_user(user)
def populate_db(url): """Populate a jupyterhub database""" connect_args = {} if 'mysql' in url: connect_args['auth_plugin'] = 'mysql_native_password' db = orm.new_session_factory(url, connect_args=connect_args)() # create some users admin = orm.User(name='admin', admin=True) db.add(admin) user = orm.User(name='has-server') db.add(user) db.commit() # create a group g = orm.Group(name='group') db.add(g) db.commit() g.users.append(user) db.commit() service = orm.Service(name='service') db.add(service) db.commit() # create some API tokens user.new_api_token() admin.new_api_token() # services got API tokens in 0.7 if jupyterhub.version_info >= (0, 7): # create a group service.new_api_token() # Create a Spawner for user if jupyterhub.version_info >= (0, 8): # create spawner for user spawner = orm.Spawner(name='', user=user) db.add(spawner) db.commit() spawner.server = orm.Server() db.commit() # admin's spawner is not running spawner = orm.Spawner(name='', user=admin) db.add(spawner) db.commit() else: user.server = orm.Server() db.commit() # create some oauth objects client = orm.OAuthClient(identifier='oauth-client') db.add(client) db.commit() code = orm.OAuthCode(client_id=client.identifier) db.add(code) db.commit() if jupyterhub.version_info < (2, 0): Token = partial( orm.OAuthAccessToken, grant_type=orm.GrantType.authorization_code, ) else: Token = orm.APIToken access_token = Token( client_id=client.identifier, user_id=user.id, ) db.add(access_token) db.commit() # set some timestamps added in 0.9 assert user.created assert admin.created # set last_activity user.last_activity = datetime.utcnow() spawner = user.orm_spawners[''] spawner.started = datetime.utcnow() spawner.last_activity = datetime.utcnow() db.commit()
def test_wont_add_system_user(io_loop): user = orm.User(name='lioness4321') authenticator = auth.PAMAuthenticator(whitelist={'mal'}) authenticator.create_system_users = False with pytest.raises(KeyError): io_loop.run_sync(lambda : authenticator.add_user(user))
def populate_db(url): """Populate a jupyterhub database""" connect_args = {} if 'mysql' in url: connect_args['auth_plugin'] = 'mysql_native_password' db = orm.new_session_factory(url, connect_args=connect_args)() if jupyterhub.version_info >= (2, ): if (not db.query(orm.OAuthClient).filter_by( identifier="jupyterhub").one_or_none()): # create the oauth client for jupyterhub itself # this allows us to distinguish between orphaned tokens # (failed cascade deletion) and tokens issued by the hub # it has no client_secret, which means it cannot be used # to make requests client = orm.OAuthClient( identifier="jupyterhub", secret="", redirect_uri="", description="JupyterHub", ) db.add(client) db.commit() from jupyterhub import roles for role in roles.get_default_roles(): roles.create_role(db, role) # create some users admin = orm.User(name='admin', admin=True) db.add(admin) user = orm.User(name='has-server') db.add(user) db.commit() # create a group g = orm.Group(name='group') db.add(g) db.commit() g.users.append(user) db.commit() service = orm.Service(name='service') db.add(service) db.commit() # create some API tokens user.new_api_token() admin.new_api_token() # services got API tokens in 0.7 if jupyterhub.version_info >= (0, 7): # create a group service.new_api_token() # Create a Spawner for user if jupyterhub.version_info >= (0, 8): # create spawner for user spawner = orm.Spawner(name='', user=user) db.add(spawner) db.commit() spawner.server = orm.Server() db.commit() # admin's spawner is not running spawner = orm.Spawner(name='', user=admin) db.add(spawner) db.commit() else: user.server = orm.Server() db.commit() # create some oauth objects client = orm.OAuthClient(identifier='oauth-client') db.add(client) db.commit() code = orm.OAuthCode(client_id=client.identifier) db.add(code) db.commit() if jupyterhub.version_info < (2, 0): Token = partial( orm.OAuthAccessToken, grant_type=orm.GrantType.authorization_code, ) else: Token = orm.APIToken access_token = Token( client_id=client.identifier, user_id=user.id, ) if jupyterhub.version_info >= (2, ): if jupyterhub.version_info < (2, 2): access_token.roles = [ db.query(orm.Role).filter_by(name="server").one() ] else: access_token.scopes = [f"read:users!user={user.name}"] db.add(access_token) db.commit() # set some timestamps added in 0.9 assert user.created assert admin.created # set last_activity user.last_activity = datetime.utcnow() spawner = user.orm_spawners[''] spawner.started = datetime.utcnow() spawner.last_activity = datetime.utcnow() db.commit()