Skip to content

Commit 74fbc5b

Browse files
authored
Merge pull request #3008 from Carreau/autopawd
When login-in via token, let a chance for user to set the password
2 parents c097387 + a40ab05 commit 74fbc5b

File tree

5 files changed

+81
-10
lines changed

5 files changed

+81
-10
lines changed

docs/source/public_server.rst

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,28 @@ using the following command::
6363

6464
$ jupyter notebook --generate-config
6565

66-
.. _hashed-pw:
6766

68-
Preparing a hashed password
69-
~~~~~~~~~~~~~~~~~~~~~~~~~~~
67+
Automatic Password setup
68+
~~~~~~~~~~~~~~~~~~~~~~~~
69+
70+
As of notebook 5.3, the first time you log-in using a token, the notebook server
71+
should give you the opportunity to setup a password from the user interface.
72+
73+
You will be presented with a form asking for the current _token_, as well as
74+
your _new_ _password_ ; enter both and click on ``Login and setup new password``.
75+
76+
Next time you need to log in you'll be able to use the new password instead of
77+
the login token, otherwise follow the procedure to set a password from the
78+
command line.
79+
80+
The ability to change the password at first login time may be disabled by
81+
integrations by setting the ``--NotebookApp.allow_password_change=False``
82+
7083

71-
As of notebook version 5.0, you can enter and store a password for your
72-
notebook server with a single command.
73-
:command:`jupyter notebook password` will prompt you for your password
74-
and record the hashed password in your :file:`jupyter_notebook_config.json`.
84+
Starting at notebook version 5.0, you can enter and store a password for your
85+
notebook server with a single command. :command:`jupyter notebook password` will
86+
prompt you for your password and record the hashed password in your
87+
:file:`jupyter_notebook_config.json`.
7588

7689
.. code-block:: bash
7790
@@ -80,6 +93,15 @@ and record the hashed password in your :file:`jupyter_notebook_config.json`.
8093
Verify password: ****
8194
[NotebookPasswordApp] Wrote hashed password to /Users/you/.jupyter/jupyter_notebook_config.json
8295
96+
This can be used to reset a lost password; or if you believe your credentials
97+
have been leaked and desire to change your password. Changing your password will
98+
invalidate all logged-in sessions after a server restart.
99+
100+
.. _hashed-pw:
101+
102+
Preparing a hashed password
103+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
104+
83105
You can prepare a hashed password manually, using the function
84106
:func:`notebook.auth.security.passwd`:
85107

@@ -109,6 +131,12 @@ directory, ``~/.jupyter``, e.g.::
109131

110132
c.NotebookApp.password = u'sha1:67c9e60bb8b6:9ffede0825894254b2e042ea597d771089e11aed'
111133

134+
Automatic password setup will store the hash in ``jupyter_notebook_config.json``
135+
while this method store in in ``jupyter_notebook_config.py``. The ``.json``
136+
configuration options take precedence over the ``.py`` one, thus the manual
137+
password may not take effect if the Json file as a password set.
138+
139+
112140
Using SSL for encrypted communication
113141
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
114142
When using a password, it is a good idea to also use SSL with a web

notebook/auth/login.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# Distributed under the terms of the Modified BSD License.
55

66
import re
7+
import os
78

89
try:
910
from urllib.parse import urlparse # Py 3
@@ -13,7 +14,7 @@
1314

1415
from tornado.escape import url_escape
1516

16-
from ..auth.security import passwd_check
17+
from .security import passwd_check, set_password
1718

1819
from ..base.handlers import IPythonHandler
1920

@@ -72,16 +73,26 @@ def passwd_check(self, a, b):
7273

7374
def post(self):
7475
typed_password = self.get_argument('password', default=u'')
76+
new_password = self.get_argument('new_password', default=u'')
77+
78+
79+
7580
if self.get_login_available(self.settings):
76-
if self.passwd_check(self.hashed_password, typed_password):
81+
if self.passwd_check(self.hashed_password, typed_password) and not new_password:
7782
self.set_login_cookie(self, uuid.uuid4().hex)
7883
elif self.token and self.token == typed_password:
7984
self.set_login_cookie(self, uuid.uuid4().hex)
85+
if self.new_password and self.settings.get('allow_password_change'):
86+
config_dir = self.settings.get('config_dir')
87+
config_file = os.path.join(config_dir, 'jupyter_notebook_config.json')
88+
set_password(new_password, config_file=config_file)
89+
self.log.info("Wrote hashed password to %s" % config_file)
8090
else:
8191
self.set_status(401)
82-
self._render(message={'error': 'Invalid password'})
92+
self._render(message={'error': 'Invalid credentials'})
8393
return
8494

95+
8596
next_url = self.get_argument('next', default=self.base_url)
8697
self._redirect_safe(next_url)
8798

notebook/base/handlers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ def template_namespace(self):
400400
default_url=self.default_url,
401401
ws_url=self.ws_url,
402402
logged_in=self.logged_in,
403+
allow_password_change=self.settings.get('allow_password_change'),
403404
login_available=self.login_available,
404405
token_available=bool(self.token or self.one_time_token),
405406
static_url=self.static_url,

notebook/notebookapp.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ def init_settings(self, jupyter_app, kernel_manager, contents_manager,
268268
mathjax_config=jupyter_app.mathjax_config,
269269
config=jupyter_app.config,
270270
config_dir=jupyter_app.config_dir,
271+
allow_password_change=jupyter_app.allow_password_change,
271272
server_root_dir=root_dir,
272273
jinja2_env=env,
273274
terminals_available=False, # Set later if terminals are available
@@ -756,6 +757,18 @@ def _token_changed(self, change):
756757
"""
757758
)
758759

760+
allow_password_change = Bool(True, config=True,
761+
help="""Allow password to be changed at login for the notebook server.
762+
763+
While loggin in with a token, the notebook server UI will give the opportunity to
764+
the user to enter a new password at the same time that will replace
765+
the token login mechanism.
766+
767+
This can be set to false to prevent changing password from the UI/API.
768+
"""
769+
)
770+
771+
759772
disable_check_xsrf = Bool(False, config=True,
760773
help="""Disable cross-site-request-forgery protection
761774

notebook/templates/login.html

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,24 @@ <h3>
8585
<p>
8686
Cookies are required for authenticated access to notebooks.
8787
</p>
88+
{% if allow_password_change %}
89+
<h3>{% trans %}Setup a Password{% endtrans %}</h3>
90+
<p> You can also setup a password by entering your token and a new password
91+
on the fields below:</p>
92+
<form action="{{base_url}}login?next={{next}}" method="post" class="">
93+
{{ xsrf_form_html() | safe }}
94+
<div class="form-group">
95+
<input type="password" name="password" id="password_input" class="form-control" placeholder="Token">
96+
</div>
97+
<div class="form-group">
98+
<input type="password" name="new_password" id="new_password_input"
99+
class="form-control" placeholder="New password" required>
100+
</div>
101+
<div class="form-group">
102+
<button type="submit" id="login_submit">{% trans %}Log in and set new password{% endtrans %}</button>
103+
</div>
104+
</form>
105+
{% endif %}
88106

89107
</div>
90108
{% endblock token_message %}

0 commit comments

Comments
 (0)