Compare commits

..

14 commits

Author SHA1 Message Date
3623a55c78 add missing parameter to call of validate_user() 2018-11-03 08:38:12 +01:00
Min RK
c1c4ce8e94
Merge pull request #11 from leportella/add-name-sanitization
add name sanitization
2018-10-15 11:37:17 +02:00
Leticia Portella
1816ba38bb add name sanitization 2018-10-12 11:25:01 -03:00
Yuvi Panda
f68deb3168
Merge pull request #10 from leportella/add-docs-password-change
add question on how to change password
2018-10-02 13:45:04 -07:00
Leticia Portella
4329420d30 add question on how to change password 2018-10-02 16:09:33 -03:00
Yuvi Panda
70f831e41b
Merge pull request #8 from leportella/reset-password-option
Add option to change password
2018-10-01 16:22:17 -07:00
Leticia Portella
12a652976a change handler to user get_body_argument 2018-09-26 19:00:42 -03:00
Leticia Portella
64c4f7b886 change success message on result message 2018-09-26 18:46:09 -03:00
Leticia Portella
49a080f9e8 change styling on template reset.html 2018-09-26 18:45:47 -03:00
Leticia Portella
1e6c7adcbb make post on ResetPasswordHandler demand authentication 2018-09-26 13:26:52 -03:00
Leticia Portella
3ab98fa0dc add post method for change password 2018-09-25 20:02:56 -03:00
Leticia Portella
5da66ecd32 add template locally 2018-09-25 19:19:04 -03:00
Leticia Portella
fdb3608ddb initial implementation on reset password url 2018-09-25 01:12:43 -03:00
Yuvi Panda
a61f7102d5
Merge pull request #7 from yuvipanda/deleteuser
Clean password db when user is deleted
2018-09-04 11:20:52 -07:00
5 changed files with 116 additions and 3 deletions

View file

@ -47,9 +47,20 @@ For security Reasons. Users are likely to set an, insecure password at
login time, and you do not want a brute-force/dictionary attack to manage to
login by attacking via ssh or another mean.
#### How can I change my password?
To change your password, you should login in your jupyterhub account,
go to `<your_server_ip>/hub/auth/change-password` and change the password.
#### I'm getting an error when creating my username
Usernames cannot contain spaces or commas. Please check if your username is free
of these characters.
## Security
When using `FirstUseAuthenticator` it is advised to automatically prepend the
name of the user with a known-prefix (for example `jupyter`). This would prevent
for example, someone to log-in as `root`, as the created user would be
`jupyter-root`.

View file

@ -6,15 +6,60 @@ password for that account. It is hashed with bcrypt & stored
locally in a dbm file, and checked next time they log in.
"""
import dbm
import os
from jinja2 import ChoiceLoader, FileSystemLoader
from jupyterhub.auth import Authenticator
from jupyterhub.handlers import BaseHandler
from jupyterhub.orm import User
from tornado import gen
from tornado import gen, web
from traitlets.traitlets import Unicode, Bool
import bcrypt
TEMPLATE_DIR = os.path.join(os.path.dirname(__file__), 'templates')
class ResetPasswordHandler(BaseHandler):
"""Render the reset password page."""
def __init__(self, *args, **kwargs):
self._loaded = False
super().__init__(*args, **kwargs)
def _register_template_path(self):
if self._loaded:
return
self.log.debug('Adding %s to template path', TEMPLATE_DIR)
loader = FileSystemLoader([TEMPLATE_DIR])
env = self.settings['jinja2_env']
previous_loader = env.loader
env.loader = ChoiceLoader([previous_loader, loader])
self._loaded = True
@web.authenticated
async def get(self):
self._register_template_path()
html = self.render_template('reset.html')
self.finish(html)
@web.authenticated
async def post(self):
user = self.get_current_user()
new_password = self.get_body_argument('password', strip=False)
self.authenticator.reset_password(user.name, new_password)
html = self.render_template(
'reset.html',
result=True,
result_message='your password has been changed successfully',
)
self.finish(html)
class FirstUseAuthenticator(Authenticator):
"""
JupyterHub authenticator that lets users set password on first use.
@ -48,6 +93,12 @@ class FirstUseAuthenticator(Authenticator):
"""
return self.db.query(User).filter_by(name=username).first() is not None
def validate_username(self, name):
invalid_chars = [',', ' ']
if any((char in name) for char in invalid_chars):
return False
return super().validate_username(name)
@gen.coroutine
def authenticate(self, handler, data):
username = data['username']
@ -63,7 +114,8 @@ class FirstUseAuthenticator(Authenticator):
if bcrypt.hashpw(password.encode(), stored_pw) != stored_pw:
return None
else:
db[username] = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
db[username] = bcrypt.hashpw(password.encode(),
bcrypt.gensalt())
return username
def delete_user(self, user):
@ -74,3 +126,16 @@ class FirstUseAuthenticator(Authenticator):
"""
with dbm.open(self.dbm_path, 'c', 0o600) as db:
del db[user.name]
def reset_password(self, username, new_password):
"""
This allow to change password of a logged user.
"""
with dbm.open(self.dbm_path, 'c', 0o600) as db:
db[username] = bcrypt.hashpw(new_password.encode(),
bcrypt.gensalt())
return username
def get_handlers(self, app):
return super().get_handlers(app) + [(r'/auth/change-password',
ResetPasswordHandler)]

View file

@ -0,0 +1,34 @@
{% extends "page.html" %}
{% block main %}
<div class="container">
<form action="{{post_url}}" method="post" role="form">
<h2>
Change Password
</h2>
<div>
<div class="form-group">
<label for='password_input'>New Password:</label>
<input
type="password"
class="form-control"
name="password"
id="password_input"
tabindex="2"
/>
</div>
<div class="form-group">
<input
type="submit"
id="login_submit"
class='btn btn-jupyter'
value='Change Password'
tabindex="3"
/>
</div>
</div>
</form>
{% if result %}
<div class="alert alert-success" role="alert">{{result_message}}</div>
{% endif %}
</div>
{% endblock %}

View file

@ -9,5 +9,8 @@ setup(
author_email='yuvipanda@gmail.com',
license='3 Clause BSD',
packages=find_packages(),
install_requires=['bcrypt']
install_requires=['bcrypt'],
package_data={
'': ['*.html'],
}
)