Initial commit

Pretty much all the things work
This commit is contained in:
YuviPanda 2016-10-24 20:31:45 -07:00
commit b1e5804d65
7 changed files with 199 additions and 0 deletions

57
.gitignore vendored Normal file
View File

@ -0,0 +1,57 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# PyBuilder
target/

20
.pylintrc Normal file
View File

@ -0,0 +1,20 @@
[MASTER]
# Ignore git and virtualenv-related folders.
ignore=.git,lib
[MESSAGES CONTROL]
disable=all
# Explicitly whitelist the lint checks we want to have
# Prefer things that catch errors and what not, and not stylistic choices
enable=missing-docstring,empty-docstring,unneeded-not,singleton-comparison,misplaced-comparison-constant,unidiomatic-typecheck,consider-using-enumerate,consider-iterating-dictionary,bad-classmethod-argument,bad-mcs-method-argument,bad-mcs-classmethod-argument,too-many-lines,multiple-statements,superfluous-parens,multiple-imports,ungrouped-imports,syntax-error,init-is-generator,return-in-init,function-redefined,not-in-loop,return-outside-function,yield-outside-function,nonexistent-operator,duplicate-argument-name,abstract-class-instantiated,bad-reversed-sequence,too-many-star-expressions,invalid-star-assignment-target,star-needs-assignment-target,nonlocal-and-global,continue-in-finally,nonlocal-without-binding,method-hidden,access-member-before-definition,no-method-argument,no-self-argument,invalid-slots-object,assigning-non-slot,invalid-slots,inherit-non-class,inconsistent-mro,duplicate-bases,non-iterator-returned,unexpected-special-method-signature,invalid-length-returned,import-error,used-before-assignment,undefined-variable,undefined-all-variable,unbalanced-tuple-unpacking,unpacking-non-sequence,bad-except-order,raising-bad-type,bad-exception-context,misplaced-bare-raise,raising-non-exception,notimplemented-raised,catching-non-exception,bad-super-call,no-member,not-callable,assignment-from-no-return,no-value-for-parameter,too-many-function-args,unexpected-keyword-arg,redundant-keyword-arg,missing-kwoa,invalid-sequence-index,invalid-slice-index,assignment-from-none,not-context-manager,invalid-unary-operand-type,unsupported-binary-operation,repeated-keyword,not-an-iterable,not-a-mapping,unsupported-membership-test,unsubscriptable-object,logging-unsupported-format,logging-format-truncated,logging-too-many-args,logging-too-few-args,bad-format-character,truncated-format-string,mixed-format-string,format-needs-mapping,missing-format-string-key,too-many-format-args,too-few-format-args,bad-str-strip-call,yield-inside-async-function,not-async-context-manager,fatal,astroid-error,parse-error,method-check-failed,bad-inline-option,useless-suppression,deprecated-pragma,unreachable,dangerous-default-value,pointless-statement,expression-not-assigned,unnecessary-pass,unnecessary-lambda,duplicate-key,useless-else-on-loop,eval-used,exec-used,confusing-with-statement,using-constant-test,lost-exception,assert-on-tuple,bad-staticmethod-argument,protected-access,arguments-differ,signature-differs,abstract-method,super-init-not-called,no-init,non-parent-init-called,unnecessary-semicolon,bad-indentation,mixed-indentation,wildcard-import,deprecated-module,reimported,import-self,misplaced-future,global-variable-undefined,global-variable-not-assigned,global-at-module-level,unused-import,unused-variable,unused-argument,unused-wildcard-import,redefined-outer-name,redefined-builtin,redefine-in-handler,undefined-loop-variable,cell-var-from-loop,duplicate-except,broad-except,bare-except,binary-op-exception,logging-not-lazy,logging-format-interpolation,bad-format-string-key,bad-format-string,missing-format-argument-key,format-combined-specification,missing-format-attribute,invalid-format-index,anomalous-backslash-in-string,anomalous-unicode-escape-in-string,bad-open-mode,redundant-unittest-assert,deprecated-method
[REPORTS]
# Do not print a summary report
reports=no
[FORMAT]
# One of the few stylistic things we try to check.
# Modules shouldn't be *too large* - should be broken up
# Feel free to bump this number if you disagree
max-module-lines=2000

27
LICENSE Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2015, Yuvi Panda <yuvipanda@gmail.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of KubeSpawner nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

29
README.md Normal file
View File

@ -0,0 +1,29 @@
# JupyterHub First Use Authenticator #
A JupyterHub Authenticator that lets users set their password when they first login.
Very useful for transient JupyterHubs being used from a single physical location (such as a workshop), where multiple users need to log in but do not have a pre-existing authentication setup. With this, they can just pick a username and password and go!
## Installation ##
You can install this authenticator with:
```bash
pip install jupyterhub-firstuseauthenticator
```
Once installed, you can have JupyterHub use it by adding the following to your `jupyterhub_config.py` file:
```python
c.JupyterHub.authenticator_class = 'firstuseauthenticator.FirstUseAuthenticator'
```
## Configuration ##
It works out of the box as advertized. There is one configuration parameter you can tweak.
### FirstUseAuthenticator.dbm_path ###
Path to the [dbm](https://docs.python.org/3.1/library/dbm.html) file used to store usernames and passwords. Put this somewhere where regular users do not have read/write access to it.
Defaults to `passwords.dbm` in the current directory from which JupyterHub is spawned.

View File

@ -0,0 +1,12 @@
"""
JupyterHub Authenticator to let users set their password on first use.
After installation, you can enable this with:
```
c.JupyterHub.authenticator_class = 'firstuseauthenticator.FirstUseAuthenticator'
```
"""
from firstuseauthenticator.firstuseauthenticator import FirstUseAuthenticator
__all__ = [FirstUseAuthenticator]

View File

@ -0,0 +1,41 @@
"""
JupyterHub Authenticator that lets users set password on first use.
When users first log in, the password they use becomes their
password for that account. It is hashed with bcrypt & stored
locally in a dbm file, and checked next time they log in.
"""
import dbm
from jupyterhub.auth import Authenticator
from tornado import gen
from traitlets.traitlets import Unicode
import bcrypt
class FirstUseAuthenticator(Authenticator):
"""
JupyterHub authenticator that lets users set password on first use.
"""
dbm_path = Unicode(
'passwords.dbm',
config=True,
help="""
Path to store the db file with username / pwd hash in
"""
)
@gen.coroutine
def authenticate(self, handler, data):
# Move everything to bytes
username = data['username'].encode('utf-8')
password = data['password'].encode('utf-8')
with dbm.open(self.dbm_path, 'c', 0o600) as db:
stored_pw = db.get(username, None)
if stored_pw is not None:
if bcrypt.hashpw(password, stored_pw) != stored_pw:
return None
else:
db[username] = bcrypt.hashpw(password, bcrypt.gensalt())
return data['username']

13
setup.py Normal file
View File

@ -0,0 +1,13 @@
from setuptools import setup, find_packages
setup(
name='jupyterhub-firstuseauthenticator',
version='0.9',
description='JupyterHub Authenticator that lets users set passwords on first use',
url='https://github.com/yuvipanda/jupyterhub-firstuseauthenticator',
author='Yuvi Panda',
author_email='yuvipanda@gmail.com',
license='3 Clause BSD',
packages=find_packages(),
install_requires=['bcrypt']
)