Giter Club home page Giter Club logo

nativeauthenticator's Introduction

Native Authenticator

Latest PyPI version Documentation build status GitHub Workflow Status - Test Code coverage
GitHub Discourse Gitter Contribute

This is a relatively simple authenticator for small or medium-sized JupyterHub applications. Signup and authentication are implemented as native to JupyterHub without relying on external services.

NativeAuthenticator provides the following features:

  • New users can signup on the system;
  • New users can be blocked from accessing the system awaiting admin authorization;
  • Option of enforcing password security by disallowing common passwords or requiring a minimum password length;
  • Option to block users after a set number of failed login attempts;
  • Option of open signup without need for initial authorization;
  • Option of asking more information about users on signup (e-mail).
  • Option of requiring users to agree with given Terms of Service;
  • Option of protection against scripting attacks via reCAPTCHA;
  • Option for users with an org-internal e-mail address to self-approve via secure link;

Documentation

The latest documentation is always on readTheDocs, available here.

Running tests

To run the tests locally, you can install the development dependencies like so:

pip install -e ".[test]"

Then run tests with pytest:

pytest

nativeauthenticator's People

Contributors

00kai0 avatar agostof avatar consideratio avatar csears-hg avatar databasedav avatar dependabot[bot] avatar djangoliv avatar fbessou avatar johnpaton avatar lambdatotoro avatar leportella avatar marc-marcos avatar mayswind avatar meownoid avatar minrk avatar ogiorgis avatar pre-commit-ci[bot] avatar raethlein avatar savvan0h avatar yapatta avatar yuvipanda avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nativeauthenticator's Issues

NativeAuthenticator doesn't work with LocalProcessSpawner

My use case:

  • I'm running jupyterhub in a containerized production environment as a service in amazon ECS
  • I'm using an NFS to persist user's home directories, which is great
  • I'd like to persist which users exist and their password hashes between new builds of the container so I don't have to recreate users everytime I redeploy my service
  • I'd like to use NativeAuthenticator as my persisted user/user_info store to solve that 👆problem

The problem:

  • When a user is created they are only created in the db and not on the host machine itself
  • This means that when the process spawner tries to spawn a process it cannot because it can't find the user to spawn the process under

Error Message:

Error in Authenticator.pre_spawn_start: KeyError "getpwnam(): name not found

Signup with taken username doesn't error

If a user signs up with a username that is already in the database, they will see the usual successful signup page ("Your data has been sent to the admin.") as if everything went correctly.
However, there will be no new entry in the admin or authorize-panel and no notification to either the user or the admins that something has gone wrong.

Password and Email of the first account are not being overwritten, as they shouldn't, but I think the user should see an error (like the one for weak passwords) that the username is taken and be asked to supply another.

Better error message on unauthorized login attempts.

Currently, if you create a new account through normal sign-up, and immediately try to log in, this will fail due to the account not being authorized yet, but the error message will read "Invalid username or password". That gives users an incorrect idea about why they are unable to login and may lead to frustration.

It would be better if failed login attempts would distinguish between "correct credentials but no authorization" and "wrong credentials" and displayed an appropriate error message.

Crash after 935 calls of login page

Bug description

It is only possible to call the login page 935 times. The 936th attempt fails, leading to a white (completely empty) login page.

Expected behaviour

I want to be able to login (or load the login page) an infinite number of times.

Actual behaviour

White login page when trying to reload the login page the 936th time.

How to reproduce

Either by clicking 936 times on browser refresh, or by using apache benchmark tool e.g. like so:

ab -c100 -n936 http://0.0.0.0:8000/hub/login

The page load frequency does not affect crash behavior. Only the number of login attempts / page loads.

Your personal set up

  • Create container image with the latest jupyterhub image and install nativeauthenticator.
    Dockerfile:
    ARG JUPYTERHUB_VERSION=latest
    FROM jupyterhub/jupyterhub:${JUPYTERHUB_VERSION}
    RUN pip install --no-cache dockerspawner
    RUN pip install --no-cache jupyterhub-nativeauthenticator
    
  • Configure JupyterHub + Authenticator. Relevant entries are:
    c.JupyterHub.authenticator_class = 'nativeauthenticator.NativeAuthenticator'
    c.Authenticator.open_signup = True
    
  • Start JupyterHub (in swarm mode in my case)
    • docker-compose.yaml
      version: "3"
      services:
        hub:
          image: myHub:latest
          build:
            context: "."
            dockerfile: "./Dockerfile"
          volumes:
            - "/var/run/docker.sock:/var/run/docker.sock"
            - "./jupyterhub_srv/:/srv/jupyterhub/"
            - "./jupyterhub_config.py:/srv/jupyterhub/jupyterhub_config.py"
          networks:
            - jupyterhub-net
          ports:
            - "8000:8000"
            - "8081:8081"
      networks:
        jupyterhub-net:
          driver: overlay
      
    • Start
      docker swarm init
      docker-compose up
      
  • OS: Linux
  • Version: jupyterhub --version 1.2.1

Attachments

  • JupyterHub log starting at 933th page load
    logfile.txt

Unable to change password with JupyterHub 1.0.0

Hello, when trying to change a password, I get the following error:

[I 2019-07-10 15:10:34.667 JupyterHub log:174] 200 GET /hub/change-password ([email protected]) 49.34ms
[E 2019-07-10 15:10:37.989 JupyterHub web:1788] Uncaught exception POST /hub/change-password (127.0.0.1)
HTTPServerRequest(protocol='http', host='xxx', method='POST', uri='/hub/change-password', version='HTTP/1
Traceback (most recent call last):
File "/opt/miniconda3/envs/py37/lib/python3.7/site-packages/tornado/web.py", line 1699, in _execute
result = await result
File "/root/src/jupyterhub-nativeauthenticator/nativeauthenticator/handlers.py", line 128, in post
self.authenticator.change_password(user.name, new_password)
AttributeError: 'coroutine' object has no attribute 'name'
...
[E 2019-07-10 15:10:38.008 JupyterHub log:174] 500 POST /hub/change-password ([email protected]) 31.08ms

It seems self.get_current_user() in handlers.py needs await since the latest JupyterHub's get_current_user() is async now.

class ChangePasswordHandler(LocalBase):
    ...
    @web.authenticated
    async def post(self):
        #user = self.get_current_user()
        user = await self.get_current_user()

Authorize user does not work when using c.JupyterHub.base_url

Hi there 👋

I set up TLJH and configured the nativeauthenticator and also the c.JupyterHub.base_url="jupyter". Hence Jupyterhub is running under ../jupyter/hub/...
Everything is working except, that I (as an admin) can not authorize users via /jupyter/hub/authorize as in the autorization-area.html
the path is hardcoded and does not respect the base path:

<a class="btn btn-default" href="/hub/authorize/{{ user.username }}" role="button">Unauthorize</a>
</td>
{% else %}
<tr>
<td>{{ user.username }}</td>
{% if ask_email %}
<td>{{ user.email }}</td>
{% endif %}
<td>{{ user.has_2fa }}</td>
<td>No</td>
<td>
<a class="btn btn-jupyter" href="/hub/authorize/{{ user.username }}" role="button">Authorize</a>

Even if i add the base_url by hand I will be redirected to /authorize which can also not be found:

self.redirect('/authorize')

Best Regards,
Florian

Setup authenticator similar to DummyAuthenticator

Let's start by setting up a simple authenticator that lets in any users with any password. This is primarily to help set up structure for authenticator to help get it started.

  • Copy code from DummyAuthenticator
  • Write appropriate setup.py
  • Write simple unit tests

TLJH Signup and login customizations not working

Having few issues with login and signup custom pages not displaying after enabling Native Authentication - #69 suggestions do not seem to work for me and having trouble figuring out what the issues are.

Ran pytest ad getting 2 error and 2 warning messages. Also not sure if these errors are related to the issue or not.

platform linux -- Python 3.7.6, pytest-5.3.5, py-1.8.1, pluggy-0.13.1
rootdir: /opt/tljh/nativeauthenticator
plugins: asyncio-0.10.0
collected 27 items

nativeauthenticator/tests/test_authenticator.py ...................FF.. [ 85%]
nativeauthenticator/tests/test_orm.py .... [100%]

================================================================================================ FAILURES =================================================================================================
_____________________________________________________________________________ test_import_from_firstuse_dont_delete_db_after ______________________________________________________________________________

tmpcwd = None, app = <jupyterhub.tests.mocking.MockHub object at 0x7fa01d7ce490>

async def test_import_from_firstuse_dont_delete_db_after(tmpcwd, app):
    with dbm.open('passwords.dbm', 'c', 0o600) as db:
        db['user1'] = 'password'

    auth = NativeAuthenticator(db=app.db)
    auth.add_data_from_firstuse()

    files = os.listdir()
    assert UserInfo.find(app.db, 'user1')

      assert ('passwords.dbm' in files) or ('passwords.dbm.db' in files)

E AssertionError: assert ('passwords.dbm' in ['passwords.dbm.dat', 'passwords.dbm.dir', 'jupyterhub.sqlite', 'passwords.dbm.bak'] or 'passwords.dbm.db' in ['passwords.dbm.dat', 'passwords.dbm.dir', 'jupyterhub.sqlite', 'passwords.dbm.bak'])

/opt/tljh/nativeauthenticator/nativeauthenticator/tests/test_authenticator.py:182: AssertionError
------------------------------------------------------------------------------------------ Captured stderr setup ------------------------------------------------------------------------------------------
[I 2020-02-17 18:30:31.724 alembic.runtime.migration migration:154] Context impl SQLiteImpl.
[I 2020-02-17 18:30:31.725 alembic.runtime.migration migration:161] Will assume non-transactional DDL.
[I 2020-02-17 18:30:31.742 alembic.runtime.migration migration:513] Running stamp_revision -> 4dc2d5a8c53c
________________________________________________________________________________ test_import_from_firstuse_delete_db_after ________________________________________________________________________________

tmpcwd = None, app = <jupyterhub.tests.mocking.MockHub object at 0x7fa01d8dc910>

async def test_import_from_firstuse_delete_db_after(tmpcwd, app):
    with dbm.open('passwords.dbm', 'c', 0o600) as db:
        db['user1'] = 'password'

    auth = NativeAuthenticator(db=app.db)
    auth.delete_firstuse_db_after_import = True

      auth.add_data_from_firstuse()

/opt/tljh/nativeauthenticator/nativeauthenticator/tests/test_authenticator.py:192:

/opt/tljh/nativeauthenticator/nativeauthenticator/nativeauthenticator.py:246: in add_data_from_firstuse
self.delete_dbm_db()

self = <nativeauthenticator.nativeauthenticator.NativeAuthenticator object at 0x7fa01d8dca90>

def delete_dbm_db(self):
    db_path = Path(self.firstuse_db_path)
    db_dir = db_path.cwd()
    db_name = db_path.name
    db_complete_path = str(db_path.absolute())

    # necessary for BSD implementation of dbm lib
    if db_name + '.db' in os.listdir(db_dir):
        os.remove(db_complete_path + '.db')
    else:

          os.remove(db_complete_path)

E FileNotFoundError: [Errno 2] No such file or directory: '/tmp/pytest-of-root/pytest-3/test_import_from_firstuse_dele0/passwords.dbm'

/opt/tljh/nativeauthenticator/nativeauthenticator/nativeauthenticator.py:232: FileNotFoundError
------------------------------------------------------------------------------------------ Captured stderr setup ------------------------------------------------------------------------------------------
[I 2020-02-17 18:30:32.429 alembic.runtime.migration migration:154] Context impl SQLiteImpl.
[I 2020-02-17 18:30:32.429 alembic.runtime.migration migration:161] Will assume non-transactional DDL.
[I 2020-02-17 18:30:32.446 alembic.runtime.migration migration:513] Running stamp_revision -> 4dc2d5a8c53c
============================================================================================ warnings summary =============================================================================================
nativeauthenticator/nativeauthenticator.py:23
/opt/tljh/nativeauthenticator/nativeauthenticator/nativeauthenticator.py:23: DeprecationWarning: metadata {'default': False} was set from the constructor. With traitlets 4.1, metadata should be set using the .tag() method, e.g., Int().tag(key1='value1', key2='value2')
help=("Creates a verification of password strength "

/opt/tljh/user/lib/python3.7/site-packages/notebook/notebookapp.py:47
/opt/tljh/user/lib/python3.7/site-packages/notebook/notebookapp.py:47: DeprecationWarning: zmq.eventloop.ioloop is deprecated in pyzmq 17. pyzmq now works with default tornado and asyncio eventloops.
ioloop.install()

-- Docs: https://docs.pytest.org/en/latest/warnings.html
================================================================================ 2 failed, 25 passed, 2 warnings in 29.47s ================================================================================

Report error in case of duplicated user on DB

When you have duplicated in the system it returns a 500 error with a traceback such as:

sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) UNIQUE constraint failed: users.name [SQL: 'INSERT INTO users (name, admin, created, last_activity, cookie_id, state, encrypted_auth_state) VALUES (?, ?, ?, ?, ?, ?, ?)'] [parameters: ('johnsnow', 0, '2019-02-13 16:12:47.223572', None, 'ff5efbcf60fc42b18b0200f98d99f865', None, None)] (Background on this error at: http://sqlalche.me/e/gkpj)

unable to import nativeauthenticator.NativeAuthenticator

I've been trying to integrate nativeauthenticator for the past couple of hours inside a kubernetes setup, but I keep getting messages like the following when the pod containing jhub is launched:

[C ... JupyterHub application:91] The 'authenticator_class' trait of <jupyterhub.app.JupyterHub object at 0x7fa9ff9fb208> instance must be a type, but 'nativeauthenticator.NativeAuthenticator' could not be imported

The Dockerfile I used to build this jhub is:

FROM jupyterhub-k8s-hub-hotfix:722712477dd0
ARG  PKGUSER=jupyterhub
ARG  PKGNAME=nativeauthenticator
ARG  COMMIT=2fede2bfc109c9107064eb4a7c48dd4e4d6a79ee

# The image changes user to 1000, but we need to edit stuff as root.
USER root
RUN  apt update && apt install -y curl && apt-get clean \
       && curl -sL https://github.com/${PKGUSER}/${PKGNAME}/archive/${COMMIT}.tar.gz |tar -xz \
       && cd ${PKGNAME}-${COMMIT} \
       && pip3 --no-cache-dir install --upgrade wheel pip \
       && pip3 --no-cache-dir install --src /usr/local/lib/python3.6/dist-packages/ -e .

COPY jupyter_config.py /srv/jupyterhub_config.py

USER 1000

The base image ("hotfix") I'm using is:

FROM jupyterhub/k8s-hub:0.8.2
# The image changes user to 1000, but we need to edit stuff as root.
USER root
COPY jupyterhub-hotfix.patch /
RUN  patch /usr/local/lib/python3.6/dist-packages/kubespawner/spawner.py /jupyterhub-hotfix.patch && rm /jupyterhub-hotfix.patch
USER 1000

This is due to a bug when jhub is used on k8s 1.16, see patch here: jupyterhub/kubespawner#354 (comment), which I also report here:

72c72
<             key=lambda x: x.last_timestamp,
---
>             key=lambda x: x.last_timestamp and x.last_timestamp.timestamp() or 0.,

The jupyter_config.py has not been touched, and the helm configuration for the deployment is:

hub:
  # Image will manage the user login and jupyterlab creation.
  image:
    name: jupyterhub-k8s-hub-native
    tag: 722712477dd0
  imagePullPolicy: Never

auth:
  type: "custom"
  custom:
    className: "nativeauthenticator.NativeAuthenticator"

Any idea why that error comes up?
If I run a shell in the "native" container I'm able to do python3 -c 'import nativeauthenticator' as well as e.g. python3 -c 'import oauthenticator.

Add `allowed_users` to authorized_users automatically?

Hi everyone,
I am currently using nativeauthentication for a large number of users, it would be easier to just automatically add whitelist(deprecated) or allowed_users of jupyterhub users to the authorized users.
I will make a PR this makes sense for the nativeauthenticator.

Cheers

UserInfo can't have a ForeignKey with JupyterHub User model

So, I created a class called UserInfo to store extra information on the user that the default JupyterHub User class won't. The UserInfo class can be seen here.

This table (user_info) is created on the Authenticator __init__ method by the following way:
UserInfo.__table__.create(self.db) where self.db is a SQLAlchemy Engine instance.

However, when I try to add a relationship between UserInfo and User, this method won't work. Usually I get this error: NoReferencedTableError: Foreign key associated with column 'product.user_id' could not find table 'user' with which to generate a foreign key to target column 'id'

I created a simple example and the main problem that I found is that, if I create both tables at the same time (using Base.metadata.create_all(engine)) everything works fine. The problem is creating the relationship after the User table has already been created.

Since I am not changing anything on JupyterHub, the User table is always created before the moment I create the UserInfo table, so I can't change this for now.

Some things I tried on the process:

  • I tried to add the relationship to the User class before the creation of the new table by using this command: User.__mapper__.add_property('products', relationship("product", collection_class=set))
  • I tried using a automap_base instead of a declarative_base, then created the UserInfo table before by using self.db.execute(..SQL..) and then get the table using automap.

For now, my UserInfo is not related to User, and it only uses the same username in the momento of creation since I have no idea how to fix this.

Block user after X logins failed

  • Allow blocking user from system
  • Add feature on admin panel to set number of trials
  • Add list of blocked users on admin panel
  • Add verification of number of trials on login

Unable to sign in alfter sign up

Bug description

WHen i integrate nativeauthenticator and jupyterhub,and jupyterhub's version is 1.1.0,nativeauthenticator 's version is lastest,i can create a new admin user from sign up page,but can not sign in.Error msg is Invalid username or password.

image

And i rebuild the docker image by using Dockerfile:
FROM jupyterhub/k8s-hub:0.9.1
RUN pip install git+https://github.com/jupyterhub/nativeauthenticator.git

Any suggestions would be greatly appreciated!

Expected behaviour

success to sign in

Actual behaviour

How to reproduce

Your personal set up

Setup CI for unit tests with CircleCI

#1 should give us some basic unit tests. We should set up CI that runs these tests on every PR on CircleCI.

  • Create project on CircleCI
  • Set up .circleci/config.yml to build & run unit tests
  • Set up automated code coverage with codecov.io
  • Add badges for CircleCI & codecov.io to README

Log user in automatically after sign-up

Right now, when a user signs up, they are then asked to manually go to the login page and log in.

If they don't need explicit admin approval, we should log them in automatically.

How to initialize UNIX system users - is there a LocalNativeAuthenticator?

Hi,

Maybe there are some elements I don't understand...

  1. I had to signup with my already existing admin user to be able to login.

  2. When I create a user with the admin panel, I have an error 500 because the nativeauthenticator.NativeAuthenticator does not allow to pass an option like : c.LocalAuthenticator.create_system_users = True
    /home/{new_user} is not created.

Am I missing someting ?
Thanks in advance :)

User info in database inconsistent

When users sign up, the usernames they chose that end up in the user_info don't appear to be normalised, which can introduce bugs, such as being unable to delete a user (see this bug report).

To reproduce, just sign up with a username that includes capital letters, such as exampleUser. They will be noted down in the users table as exampleuser and in the users_info table as exampleUser, giving a 500 Error when trying to delete the account via the admin interface.

This should probably be corrected.

Endpoint to reset passwords?

I'm using jupyterHub with nativeauthenticator and I have a user who apparently mistyped their password on signup and now doesn't know what to do.
I know there is an endpoint to change your own password when logged in (#33), but I cannot find one for admins to change / reset a user's password.

As a workaround, I think deleting the user and having them sign up with the same name should be an option, but a reset/change password option for admins should potentially also be considered (especially while #73 remains open).

Runtime Error: maximum recursion depth

Bug description

I have a Jupyterhub configured to use Native Auth, with DockerSpawner.

After running for a while (months or weeks, a time which I suspect depends on how many users are active), the server experiences a runtime error RecursionError: maximum recursion depth exceeded while calling a Python object

Expected behaviour

I would expect that it would just run.

Actual behaviour

After some period of time, it triggers runtime errors:

Looking in the error message output, it seems that this might be related to the Native Auth authenticator:

    HTTPServerRequest(protocol='https', host='jupyterhub-steelelab.tnw.tudelft.nl', method='GET', uri='/hub/login?next=%2Fhub%2Fuser%2Flieuwelocht%2Fmetrics', version='HTTP/1.1', remote_ip='::ffff:1
45.94.145.117')
    Traceback (most recent call last):
      File "/root/miniconda3/lib/python3.7/site-packages/tornado/web.py", line 1703, in _execute
        result = await result
      File "/root/miniconda3/lib/python3.7/site-packages/jupyterhub/handlers/login.py", line 135, in get
        self.finish(self._render(username=username))
      File "/root/native_auth/nativeauthenticator/nativeauthenticator/handlers.py", line 151, in _render
        {'next': self.get_argument('next', '')},
      File "/root/miniconda3/lib/python3.7/site-packages/jupyterhub/handlers/base.py", line 1044, in render_template
        return template.render(**template_ns)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/environment.py", line 1090, in render
        self.environment.handle_exception()
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/environment.py", line 832, in handle_exception
        reraise(*rewrite_traceback_stack(source=source))
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/_compat.py", line 28, in reraise
        raise value.with_traceback(tb)
      File "/root/native_auth/nativeauthenticator/nativeauthenticator/templates/native-login.html", line 1, in top-level template code
        {% extends "page.html" %}
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/environment.py", line 592, in _generate
        optimized=self.optimized,
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/compiler.py", line 87, in generate
        generator.visit(node)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 32, in visit
        return f(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/compiler.py", line 774, in visit_Template
        self.blockvisit(node.body, frame)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/compiler.py", line 381, in blockvisit
        self.visit(node, frame)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 32, in visit
        return f(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/compiler.py", line 1233, in visit_Macro
        macro_frame, macro_ref = self.macro_body(node, frame)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/compiler.py", line 580, in macro_body
        self.blockvisit(node.body, frame)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/compiler.py", line 381, in blockvisit
        self.visit(node, frame)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 32, in visit
        return f(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/compiler.py", line 1458, in visit_Assign
        self.visit(node.node, frame)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 32, in visit
        return f(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/compiler.py", line 70, in new_func
        new_node = self.optimizer.visit(node, frame.eval_ctx)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 33, in visit
        return self.generic_visit(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/optimizer.py", line 27, in generic_visit
        node = super(Optimizer, self).generic_visit(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 67, in generic_visit
        new_node = self.visit(old_value, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 33, in visit
        return self.generic_visit(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/optimizer.py", line 27, in generic_visit
        node = super(Optimizer, self).generic_visit(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 67, in generic_visit
        new_node = self.visit(old_value, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 33, in visit
        return self.generic_visit(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/optimizer.py", line 27, in generic_visit
        node = super(Optimizer, self).generic_visit(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 67, in generic_visit
        new_node = self.visit(old_value, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 33, in visit
        return self.generic_visit(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/optimizer.py", line 27, in generic_visit
        node = super(Optimizer, self).generic_visit(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 67, in generic_visit
        new_node = self.visit(old_value, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 33, in visit
        return self.generic_visit(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/optimizer.py", line 27, in generic_visit
        node = super(Optimizer, self).generic_visit(node, *args, **kwargs)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/visitor.py", line 66, in generic_visit
        elif isinstance(old_value, Node):
    RecursionError: maximum recursion depth exceeded while calling a Python object

In particular, I am suspicious that this may be triggered by the line:

      File "/root/native_auth/nativeauthenticator/nativeauthenticator/templates/native-login.html", line 1, in top-level template code
        {% extends "page.html" %}

After this initial error message, the logfiles are filled with tracebacks like this one:

    Traceback (most recent call last):
      File "/root/miniconda3/lib/python3.7/site-packages/tornado/web.py", line 1703, in _execute
        result = await result
      File "/root/miniconda3/lib/python3.7/site-packages/jupyterhub/handlers/login.py", line 135, in get
        self.finish(self._render(username=username))
      File "/root/native_auth/nativeauthenticator/nativeauthenticator/handlers.py", line 151, in _render
        {'next': self.get_argument('next', '')},
      File "/root/miniconda3/lib/python3.7/site-packages/jupyterhub/handlers/base.py", line 1043, in render_template
        template = self.get_template(name)
      File "/root/miniconda3/lib/python3.7/site-packages/jupyterhub/handlers/base.py", line 1037, in get_template
        return self.settings['jinja2_env'].get_template(name)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/environment.py", line 883, in get_template
        return self._load_template(name, self.make_globals(globals))
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/environment.py", line 857, in _load_template
        template = self.loader.load(self, name, globals)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/loaders.py", line 426, in load
        return loader.load(environment, name, globals)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/loaders.py", line 426, in load
        return loader.load(environment, name, globals)
      File "/root/miniconda3/lib/python3.7/site-packages/jinja2/loaders.py", line 426, in load
        return loader.load(environment, name, globals)
      [Previous line repeated 982 more times]
    RecursionError: maximum recursion depth exceeded

How to reproduce

  1. Start jupyterhub server with NativeAuth
  2. Allow ~15 users to connect and run things for a few months. Or possibly by having the browser of a user call an HTTP GET about 1900 times.
  3. First recursion depth error occurs as described above, followed by the second recursion depth error as described above
  4. Server can no longer be connected to by new connects (existing connections do persist, but if I open a link to server in an incogento tab, I cannot connect).

Your personal set up

  • OS:
    Linux
  • Version:

jupyterhub version 1.0.0

  • Configuration:

Dockerspawner

issue with hub/authorize page and user login

Hi

i having an issue with hub/authorize page when i go to authorize a user i get an error 403 forbidden and then also when i try to log in with a user created i get the following error
500 : Internal Server Error
Error in Authenticator.pre_spawn_start: KeyError "getpwnam(): name not found: 'amit'"
You can try restarting your server from the home page.
is there a way to resolve this

Some questions in normal installation

@leportella
When I install this module (not develop install), I find some questions.
1.
After pip install ., I use from nativeauthenticator import NativeAuthenticator.It shows some error

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/kai/work/embark3_env/venv/lib/python3.5/site-packages/nativeauthenticator/__init__.py", line 4, in <module>
    from nativeauthenticator.nativeauthenticator import NativeAuthenticator
  File "/home/kai/work/embark3_env/venv/lib/python3.5/site-packages/nativeauthenticator/nativeauthenticator.py", line 1, in <module>
    import bcrypt
ImportError: No module named 'bcrypt'

I saw you put bcrypt into dev-requirements.txt, I think you should put it into setup.py's install_requires. (It just my suggestions).
2.
It's about f-string.

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/kai/work/embark3_env/venv/lib/python3.5/site-packages/nativeauthenticator/__init__.py", line 4, in <module>
    from nativeauthenticator.nativeauthenticator import NativeAuthenticator
  File "/home/kai/work/embark3_env/venv/lib/python3.5/site-packages/nativeauthenticator/nativeauthenticator.py", line 10, in <module>
    from .handlers import (AuthorizationHandler, ChangeAuthorizationHandler,
  File "/home/kai/work/embark3_env/venv/lib/python3.5/site-packages/nativeauthenticator/handlers.py", line 53
    f"at least {pw_len} characters, doesn't have "
    ^
SyntaxError: invalid syntax

This is a new string format in python3.6 (I usually use python3.5). If you just want to support python>=3.6, you need set python_requires=">=3.6" in setup.py. The other way is changing the format style to support 3.4 or 3.5.
This is all my questions. Thank you.
If you wanne help, I can have a try.

How to customize login page and other templates?

I'm trying to customize the login page with some additional information for users. Adding my own directory containing a native-login.html to c.JupyterHub.template_paths isn't enough apparently.

Example:

<!-- /custom/template/directory/native-login.html -->
{% extends "native-login.html" %}

{% block login %}
<p><strong>It worked!</strong></p>
{{ super() }}
{% endblock %}
# jupyterhub_config.py
...
c.JupyterHub.template_paths = ["/custom/template/directory/"]
...

Delete users from authorize page

It would be nice to have a button to permanently discard unauthorized users that you know you do not intend to authorize in the future so they don't clutter up the page (and would have to re-sign-up to be authorized again). This should also remove them from the database.

As a workaround, you can add the user to JupyterHub and then delete them again, which will (seemingly?) also remove them from the authorize page, but probably doesn't remove them from the database. I'll investigate this further.

Easy to fix docs corrections

Bug description

in the jupyterhub_config.py, I set c.Authenticator.add_two_factor_authentication = True. However,
while I start jupyterhub service, a warning occurs that Config option add_two_factor_authentication not recognized by NativeAuthenticator. Anyone who knows where I went wrong?

Expected behaviour

I except the configuration that c.Authenticator.add_two_factor_authentication = True would take effect.

Actual behaviour

As a result, a warning occurs that Config option add_two_factor_authentication not recognized by NativeAuthenticator.

Project naming question

What is "native" about this authenticator? For me "native" and "first-class" are words we should avoid because they often imply a ranking "Native is better than not native" or "'first class X support' is better than 'we support X'". It reminds me discussions like "we need a kubernetes native multi user jupyter solution" which even when it isn't meant to confer a value judgement does often imply a judgement.

I hadn't given this much thought but did think of it when reading a draft blog post about the project.

Error on user deletion

As a workaround to #90 I hit this exception:

[E 2020-01-13 19:51:34.834 JupyterHub web:1788] Uncaught exception DELETE /hub/api/users/SOMEUSER (*.*.*.*)
    HTTPServerRequest(protocol='https', host='', method='DELETE', uri='/hub/api/users/SOMEUSER', version='HTTP/1.1', remote_ip='10.0.45.103')
    Traceback (most recent call last):
      File "/usr/local/lib/python3.6/dist-packages/tornado/web.py", line 1699, in _execute
        result = await result
      File "/usr/local/lib/python3.6/dist-packages/jupyterhub/apihandlers/users.py", line 184, in delete
        await maybe_future(self.authenticator.delete_user(user))
      File "/home/jovyan/.local/lib/python3.6/site-packages/nativeauthenticator/nativeauthenticator.py", line 217, in delete_user
        self.db.delete(user_info)
      File "/usr/local/lib/python3.6/dist-packages/sqlalchemy/orm/session.py", line 1992, in delete
        raise exc.UnmappedInstanceError(instance)
    sqlalchemy.orm.exc.UnmappedInstanceError: Class 'builtins.NoneType' is not mapped

Add a signup hook

Proposed change

Since the users are not added to the Jupyterhub User table before logging in, it would be nice to be able to associate an action with the signup.

(Optional): Suggest a solution

In the jupyterhub_config.py:

c.Authenticator.post_signup_hook = mySignupAction

Regards

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.