Merge pull request #3008 from Carreau/autopawd

When login-in via token, let a chance for user to set the password
This commit is contained in:
Thomas Kluyver 2017-11-15 15:51:32 +00:00 committed by GitHub
commit 74fbc5b578
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 81 additions and 10 deletions

View File

@ -63,15 +63,28 @@ using the following command::
$ jupyter notebook --generate-config
.. _hashed-pw:
Preparing a hashed password
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Automatic Password setup
~~~~~~~~~~~~~~~~~~~~~~~~
As of notebook version 5.0, you can enter and store a password for your
notebook server with a single command.
:command:`jupyter notebook password` will prompt you for your password
and record the hashed password in your :file:`jupyter_notebook_config.json`.
As of notebook 5.3, the first time you log-in using a token, the notebook server
should give you the opportunity to setup a password from the user interface.
You will be presented with a form asking for the current _token_, as well as
your _new_ _password_ ; enter both and click on ``Login and setup new password``.
Next time you need to log in you'll be able to use the new password instead of
the login token, otherwise follow the procedure to set a password from the
command line.
The ability to change the password at first login time may be disabled by
integrations by setting the ``--NotebookApp.allow_password_change=False``
Starting at notebook version 5.0, you can enter and store a password for your
notebook server with a single command. :command:`jupyter notebook password` will
prompt you for your password and record the hashed password in your
:file:`jupyter_notebook_config.json`.
.. code-block:: bash
@ -80,6 +93,15 @@ and record the hashed password in your :file:`jupyter_notebook_config.json`.
Verify password: ****
[NotebookPasswordApp] Wrote hashed password to /Users/you/.jupyter/jupyter_notebook_config.json
This can be used to reset a lost password; or if you believe your credentials
have been leaked and desire to change your password. Changing your password will
invalidate all logged-in sessions after a server restart.
.. _hashed-pw:
Preparing a hashed password
~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can prepare a hashed password manually, using the function
:func:`notebook.auth.security.passwd`:
@ -109,6 +131,12 @@ directory, ``~/.jupyter``, e.g.::
c.NotebookApp.password = u'sha1:67c9e60bb8b6:9ffede0825894254b2e042ea597d771089e11aed'
Automatic password setup will store the hash in ``jupyter_notebook_config.json``
while this method store in in ``jupyter_notebook_config.py``. The ``.json``
configuration options take precedence over the ``.py`` one, thus the manual
password may not take effect if the Json file as a password set.
Using SSL for encrypted communication
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When using a password, it is a good idea to also use SSL with a web

View File

@ -4,6 +4,7 @@
# Distributed under the terms of the Modified BSD License.
import re
import os
try:
from urllib.parse import urlparse # Py 3
@ -13,7 +14,7 @@ import uuid
from tornado.escape import url_escape
from ..auth.security import passwd_check
from .security import passwd_check, set_password
from ..base.handlers import IPythonHandler
@ -72,16 +73,26 @@ class LoginHandler(IPythonHandler):
def post(self):
typed_password = self.get_argument('password', default=u'')
new_password = self.get_argument('new_password', default=u'')
if self.get_login_available(self.settings):
if self.passwd_check(self.hashed_password, typed_password):
if self.passwd_check(self.hashed_password, typed_password) and not new_password:
self.set_login_cookie(self, uuid.uuid4().hex)
elif self.token and self.token == typed_password:
self.set_login_cookie(self, uuid.uuid4().hex)
if self.new_password and self.settings.get('allow_password_change'):
config_dir = self.settings.get('config_dir')
config_file = os.path.join(config_dir, 'jupyter_notebook_config.json')
set_password(new_password, config_file=config_file)
self.log.info("Wrote hashed password to %s" % config_file)
else:
self.set_status(401)
self._render(message={'error': 'Invalid password'})
self._render(message={'error': 'Invalid credentials'})
return
next_url = self.get_argument('next', default=self.base_url)
self._redirect_safe(next_url)

View File

@ -400,6 +400,7 @@ class IPythonHandler(AuthenticatedHandler):
default_url=self.default_url,
ws_url=self.ws_url,
logged_in=self.logged_in,
allow_password_change=self.settings.get('allow_password_change'),
login_available=self.login_available,
token_available=bool(self.token or self.one_time_token),
static_url=self.static_url,

View File

@ -268,6 +268,7 @@ class NotebookWebApplication(web.Application):
mathjax_config=jupyter_app.mathjax_config,
config=jupyter_app.config,
config_dir=jupyter_app.config_dir,
allow_password_change=jupyter_app.allow_password_change,
server_root_dir=root_dir,
jinja2_env=env,
terminals_available=False, # Set later if terminals are available
@ -756,6 +757,18 @@ class NotebookApp(JupyterApp):
"""
)
allow_password_change = Bool(True, config=True,
help="""Allow password to be changed at login for the notebook server.
While loggin in with a token, the notebook server UI will give the opportunity to
the user to enter a new password at the same time that will replace
the token login mechanism.
This can be set to false to prevent changing password from the UI/API.
"""
)
disable_check_xsrf = Bool(False, config=True,
help="""Disable cross-site-request-forgery protection

View File

@ -85,6 +85,24 @@ http://localhost:8888/?token=c8de56fa... :: /Users/you/notebooks
<p>
Cookies are required for authenticated access to notebooks.
</p>
{% if allow_password_change %}
<h3>{% trans %}Setup a Password{% endtrans %}</h3>
<p> You can also setup a password by entering your token and a new password
on the fields below:</p>
<form action="{{base_url}}login?next={{next}}" method="post" class="">
{{ xsrf_form_html() | safe }}
<div class="form-group">
<input type="password" name="password" id="password_input" class="form-control" placeholder="Token">
</div>
<div class="form-group">
<input type="password" name="new_password" id="new_password_input"
class="form-control" placeholder="New password" required>
</div>
<div class="form-group">
<button type="submit" id="login_submit">{% trans %}Log in and set new password{% endtrans %}</button>
</div>
</form>
{% endif %}
</div>
{% endblock token_message %}