Merge pull request #8 from leportella/reset-password-option
Add option to change password
This commit is contained in:
commit
70f831e41b
4 changed files with 99 additions and 3 deletions
|
@ -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.
|
locally in a dbm file, and checked next time they log in.
|
||||||
"""
|
"""
|
||||||
import dbm
|
import dbm
|
||||||
|
import os
|
||||||
|
from jinja2 import ChoiceLoader, FileSystemLoader
|
||||||
from jupyterhub.auth import Authenticator
|
from jupyterhub.auth import Authenticator
|
||||||
|
from jupyterhub.handlers import BaseHandler
|
||||||
from jupyterhub.orm import User
|
from jupyterhub.orm import User
|
||||||
|
|
||||||
from tornado import gen
|
from tornado import gen, web
|
||||||
from traitlets.traitlets import Unicode, Bool
|
from traitlets.traitlets import Unicode, Bool
|
||||||
|
|
||||||
import bcrypt
|
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):
|
class FirstUseAuthenticator(Authenticator):
|
||||||
"""
|
"""
|
||||||
JupyterHub authenticator that lets users set password on first use.
|
JupyterHub authenticator that lets users set password on first use.
|
||||||
|
@ -63,7 +108,8 @@ class FirstUseAuthenticator(Authenticator):
|
||||||
if bcrypt.hashpw(password.encode(), stored_pw) != stored_pw:
|
if bcrypt.hashpw(password.encode(), stored_pw) != stored_pw:
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
db[username] = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
|
db[username] = bcrypt.hashpw(password.encode(),
|
||||||
|
bcrypt.gensalt())
|
||||||
return username
|
return username
|
||||||
|
|
||||||
def delete_user(self, user):
|
def delete_user(self, user):
|
||||||
|
@ -74,3 +120,16 @@ class FirstUseAuthenticator(Authenticator):
|
||||||
"""
|
"""
|
||||||
with dbm.open(self.dbm_path, 'c', 0o600) as db:
|
with dbm.open(self.dbm_path, 'c', 0o600) as db:
|
||||||
del db[user.name]
|
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)]
|
||||||
|
|
0
firstuseauthenticator/templates/__init__.py
Normal file
0
firstuseauthenticator/templates/__init__.py
Normal file
34
firstuseauthenticator/templates/reset.html
Normal file
34
firstuseauthenticator/templates/reset.html
Normal 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 %}
|
5
setup.py
5
setup.py
|
@ -9,5 +9,8 @@ setup(
|
||||||
author_email='yuvipanda@gmail.com',
|
author_email='yuvipanda@gmail.com',
|
||||||
license='3 Clause BSD',
|
license='3 Clause BSD',
|
||||||
packages=find_packages(),
|
packages=find_packages(),
|
||||||
install_requires=['bcrypt']
|
install_requires=['bcrypt'],
|
||||||
|
package_data={
|
||||||
|
'': ['*.html'],
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
Loading…
Add table
Reference in a new issue