Merge pull request #2007 from minrk/password

add `jupyter notebook password` entrypoint
pull/2041/head
Kyle Kelley 9 years ago committed by GitHub
commit f5f97d1f93

@ -53,6 +53,7 @@ configuring the :attr:`NotebookApp.password` setting in
Prerequisite: A notebook configuration file
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Check to see if you have a notebook configuration file,
:file:`jupyter_notebook_config.py`. The default location for this file
is your Jupyter folder in your home directory, ``~/.jupyter``.
@ -66,7 +67,20 @@ using the following command::
Preparing a hashed password
~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can prepare a hashed password using the function
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`.
.. code-block:: bash
$ jupyter notebook password
Enter password: ****
Verify password: ****
[NotebookPasswordApp] Wrote hashed password to /Users/you/.jupyter/jupyter_notebook_config.json
You can prepare a hashed password manually, using the function
:func:`notebook.auth.security.passwd`:
.. code-block:: ipython

@ -58,8 +58,20 @@ Once you have visited this URL,
a cookie will be set in your browser and you won't need to use the token again,
unless you switch browsers, clear your cookies, or start a notebook server on a new port.
Alternatives to token authentication
------------------------------------
You can disable authentication altogether by setting the token and password to empty strings,
If a generated token doesn't work well for you,
you can set a password for your notebook.
:command:`jupyter notebook password` will prompt you for a password,
and store the hashed password in your :file:`jupyter_notebook_config.json`.
.. versionadded:: 5.0
:command:`jupyter notebook password` command is added.
It is possible disable authentication altogether by setting the token and password to empty strings,
but this is **NOT RECOMMENDED**, unless authentication or access restrictions are handled at a different layer in your web application:
.. sourcecode:: python

@ -1,11 +1,20 @@
"""
Password generation for the Notebook.
"""
from contextlib import contextmanager
import getpass
import hashlib
import io
import json
import os
import random
import traceback
import warnings
from ipython_genutils.py3compat import cast_bytes, str_to_bytes
from ipython_genutils.py3compat import cast_bytes, str_to_bytes, cast_unicode
from traitlets.config import Config, ConfigFileNotFound, JSONFileConfigLoader
from jupyter_core.paths import jupyter_config_dir
# Length of the salt in nr of hex chars, which implies salt_len * 4
# bits of randomness.
@ -99,3 +108,41 @@ def passwd_check(hashed_passphrase, passphrase):
h.update(cast_bytes(passphrase, 'utf-8') + cast_bytes(salt, 'ascii'))
return h.hexdigest() == pw_digest
@contextmanager
def persist_config(config_file=None, mode=0o600):
"""Context manager that can be used to modify a config object
On exit of the context manager, the config will be written back to disk,
by default with user-only (600) permissions.
"""
if config_file is None:
config_file = os.path.join(jupyter_config_dir(), 'jupyter_notebook_config.json')
loader = JSONFileConfigLoader(os.path.basename(config_file), os.path.dirname(config_file))
try:
config = loader.load_config()
except ConfigFileNotFound:
config = Config()
yield config
with io.open(config_file, 'w', encoding='utf8') as f:
f.write(cast_unicode(json.dumps(config, indent=2)))
try:
os.chmod(config_file, mode)
except Exception as e:
tb = traceback.format_exc()
warnings.warn("Failed to set permissions on %s:\n%s" % (config_file, tb),
RuntimeWarning)
def set_password(password=None, config_file=None):
"""Ask user for password, store it in notebook json configuration file"""
hashed_password = passwd(password)
with persist_config(config_file) as config:
config.NotebookApp.password = hashed_password

@ -106,6 +106,7 @@ from .utils import url_path_join, check_pid, url_escape
_examples = """
jupyter notebook # start the notebook
jupyter notebook --certfile=mycert.pem # use SSL/TLS certificate
jupyter notebook password # enter a password to protect the server
"""
DEV_NOTE_NPM = """It looks like you're running the notebook from source.
@ -325,6 +326,24 @@ class NotebookWebApplication(web.Application):
return new_handlers
class NotebookPasswordApp(JupyterApp):
"""Set a password for the notebook server.
Setting a password secures the notebook server
and removes the need for token-based authentication.
"""
description = __doc__
def _config_file_default(self):
return os.path.join(self.config_dir, 'jupyter_notebook_config.json')
def start(self):
from .auth.security import set_password
set_password(config_file=self.config_file)
self.log.info("Wrote hashed password to %s" % self.config_file)
class NbserverListApp(JupyterApp):
version = __version__
description="List currently running notebook servers."
@ -428,6 +447,7 @@ class NotebookApp(JupyterApp):
subcommands = dict(
list=(NbserverListApp, NbserverListApp.description.splitlines()[0]),
password=(NotebookPasswordApp, NotebookPasswordApp.description.splitlines()[0]),
)
_log_formatter_cls = LogFormatter

@ -1,11 +1,18 @@
"""Test NotebookApp"""
import getpass
import logging
import os
import re
from subprocess import Popen, PIPE, STDOUT
import sys
from tempfile import NamedTemporaryFile
try:
from unittest.mock import patch
except ImportError:
from mock import patch # py2
import nose.tools as nt
from traitlets.tests.utils import check_help_all_output
@ -14,7 +21,7 @@ from jupyter_core.application import NoStart
from ipython_genutils.tempdir import TemporaryDirectory
from traitlets import TraitError
from notebook import notebookapp, __version__
from notebook import notebookapp
from notebook.auth.security import passwd_check
NotebookApp = notebookapp.NotebookApp
@ -117,3 +124,17 @@ def raise_on_bad_version(version):
def test_current_version():
raise_on_bad_version(__version__)
def test_notebook_password():
password = 'secret'
with TemporaryDirectory() as td:
with patch.dict('os.environ', {
'JUPYTER_CONFIG_DIR': td,
}), patch.object(getpass, 'getpass', return_value=password):
app = notebookapp.NotebookPasswordApp(log_level=logging.ERROR)
app.initialize([])
app.start()
nb = NotebookApp()
nb.load_config_file()
nt.assert_not_equal(nb.password, '')
passwd_check(nb.password, password)

Loading…
Cancel
Save