Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add authentication based on userinfo #25

Merged
merged 3 commits into from
Jan 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ flake8
pytest
pytest-asyncio
notebook==5.7.2
bcrypt
8 changes: 6 additions & 2 deletions nativeauthenticator/nativeauthenticator.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import bcrypt
from jupyterhub.orm import User
from jupyterhub.auth import Authenticator

Expand All @@ -19,15 +20,18 @@ def __init__(self, *args, **kwargs):

@gen.coroutine
def authenticate(self, handler, data):
return data['username']
user = UserInfo.find(self.db, data['username'])
if user and user.is_valid_password(data['password']):
return data['username']

def get_or_create_user(self, username, password):
user = User.find(self.db, username)
if not user:
user = User(name=username, admin=False)
self.db.add(user)

user_info = UserInfo(username=username, password=password)
encoded_pw = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
user_info = UserInfo(username=username, password=encoded_pw)
self.db.add(user_info)
return user

Expand Down
5 changes: 5 additions & 0 deletions nativeauthenticator/orm.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import bcrypt
from sqlalchemy import (
Column, Integer, String
)
Expand All @@ -18,3 +19,7 @@ def find(cls, db, username):
Returns None if not found.
"""
return db.query(cls).filter(cls.username == username).first()

def is_valid_password(self, password):
encoded_pw = bcrypt.hashpw(password.encode(), self.password)
return encoded_pw == self.password
41 changes: 36 additions & 5 deletions nativeauthenticator/tests/test_authenticator.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import pytest
from unittest.mock import Mock
from jupyterhub.orm import User
from jupyterhub.tests.mocking import MockHub

from nativeauthenticator import NativeAuthenticator
from ..orm import UserInfo


@pytest.fixture
Expand All @@ -23,14 +24,44 @@ def app():
pytestmark = pytestmark(pytest.mark.usefixtures("tmpcwd"))


async def test_basic(tmpcwd, app):
async def test_auth_get_or_create(tmpcwd, app):
'''Test if method get_or_create_user creates a new user'''
auth = NativeAuthenticator(db=app.db)
response = await auth.authenticate(Mock(), {'username': 'name',
'password': '123'})
assert response == 'name'
user = auth.get_or_create_user('John Snow', 'password')
main_user = User.find(app.db, 'John Snow')
user_info = UserInfo.find(app.db, 'John Snow')
assert user == main_user
assert user_info.username == 'John Snow'


async def test_failed_authentication_user_doesnt_exist(tmpcwd, app):
'''Test if authentication fails with a unexistent user'''
auth = NativeAuthenticator(db=app.db)
response = await auth.authenticate(app, {'username': 'name',
'password': '123'})
assert not response


async def test_failed_authentication_wrong_password(tmpcwd, app):
'''Test if authentication fails with a wrong password'''
auth = NativeAuthenticator(db=app.db)
auth.get_or_create_user('John Snow', 'password')
response = await auth.authenticate(app, {'username': 'John Snow',
'password': '123'})
assert not response


async def test_succeded_authentication(tmpcwd, app):
'''Test a successfull authentication'''
auth = NativeAuthenticator(db=app.db)
user = auth.get_or_create_user('John Snow', 'password')
response = await auth.authenticate(app, {'username': 'John Snow',
'password': 'password'})
assert response == user.name


async def test_handlers(app):
'''Test if all handlers are available on the Authenticator'''
auth = NativeAuthenticator(db=app.db)
handlers = auth.get_handlers(app)
assert handlers[1][0] == '/signup'