From 709fdd637a47be343ef55fda5ec8fc4892340771 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 2 Nov 2017 11:49:11 -0700 Subject: [PATCH 1/3] When login-in via token, let a chance for user to set the password When token is enabled, the login page will present a form to the user asking them if they want to set a password at the same time. This is almost equivalent to running `jupyter notebook password` on the command line. The experience can likely be better, but just submitting that as a POC for feedback --- notebook/auth/login.py | 17 ++++++++++++++--- notebook/templates/login.html | 16 ++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/notebook/auth/login.py b/notebook/auth/login.py index dc624fa2ce..2478fc96a6 100644 --- a/notebook/auth/login.py +++ b/notebook/auth/login.py @@ -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 @@ 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 @@ def passwd_check(self, a, b): 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: + 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) diff --git a/notebook/templates/login.html b/notebook/templates/login.html index 75aee8de79..c30af5acf0 100644 --- a/notebook/templates/login.html +++ b/notebook/templates/login.html @@ -85,6 +85,22 @@

Cookies are required for authenticated access to notebooks.

+

{% trans %}Setup a Password{% endtrans %}

+

You can setup a password by entering your token and a new password + on the fields below:

+
+ {{ xsrf_form_html() | safe }} +
+ +
+
+ +
+
+ +
+
{% endblock token_message %} From a8971410c1cb44c4fad82fc122eb2f20f6a6917b Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sat, 11 Nov 2017 09:32:54 -0800 Subject: [PATCH 2/3] Add option disabled changing password at login. Document the changing of password. --- docs/source/public_server.rst | 42 +++++++++++++++++++++++++++++------ notebook/auth/login.py | 2 +- notebook/base/handlers.py | 1 + notebook/notebookapp.py | 13 +++++++++++ notebook/templates/login.html | 34 +++++++++++++++------------- 5 files changed, 68 insertions(+), 24 deletions(-) diff --git a/docs/source/public_server.rst b/docs/source/public_server.rst index e22e43cb61..004ca14218 100644 --- a/docs/source/public_server.rst +++ b/docs/source/public_server.rst @@ -63,15 +63,28 @@ using the following command:: $ jupyter notebook --generate-config -.. _hashed-pw: -Preparing a hashed password -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Automatic Password setup +~~~~~~~~~~~~~~~~~~~~~~~~ + +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=True`` + -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`. +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 diff --git a/notebook/auth/login.py b/notebook/auth/login.py index 2478fc96a6..9404b8947c 100644 --- a/notebook/auth/login.py +++ b/notebook/auth/login.py @@ -82,7 +82,7 @@ def post(self): 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: + 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) diff --git a/notebook/base/handlers.py b/notebook/base/handlers.py index 798456caec..c57082fd49 100755 --- a/notebook/base/handlers.py +++ b/notebook/base/handlers.py @@ -400,6 +400,7 @@ def template_namespace(self): 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, diff --git a/notebook/notebookapp.py b/notebook/notebookapp.py index 1fff75e514..2a8cf932ca 100755 --- a/notebook/notebookapp.py +++ b/notebook/notebookapp.py @@ -267,6 +267,7 @@ def init_settings(self, jupyter_app, kernel_manager, contents_manager, 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 @@ -750,6 +751,18 @@ def _token_changed(self, change): """ ) + 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 diff --git a/notebook/templates/login.html b/notebook/templates/login.html index c30af5acf0..08e5bd1db0 100644 --- a/notebook/templates/login.html +++ b/notebook/templates/login.html @@ -85,22 +85,24 @@

Cookies are required for authenticated access to notebooks.

-

{% trans %}Setup a Password{% endtrans %}

-

You can setup a password by entering your token and a new password - on the fields below:

-
- {{ xsrf_form_html() | safe }} -
- -
-
- -
-
- -
-
+ {% if allow_password_change %} +

{% trans %}Setup a Password{% endtrans %}

+

You can also setup a password by entering your token and a new password + on the fields below:

+
+ {{ xsrf_form_html() | safe }} +
+ +
+
+ +
+
+ +
+
+ {% endif %} {% endblock token_message %} From a40ab056d84adc88dc234c2b977c02bd6a8c9c8b Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 15 Nov 2017 06:43:25 -0800 Subject: [PATCH 3/3] Fix docs intructions True->Flase --- docs/source/public_server.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/public_server.rst b/docs/source/public_server.rst index 004ca14218..cfcc7216e7 100644 --- a/docs/source/public_server.rst +++ b/docs/source/public_server.rst @@ -78,7 +78,7 @@ 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=True`` +integrations by setting the ``--NotebookApp.allow_password_change=False`` Starting at notebook version 5.0, you can enter and store a password for your