diff --git a/notebook/auth/__main__.py b/notebook/auth/__main__.py new file mode 100644 index 000000000..023983975 --- /dev/null +++ b/notebook/auth/__main__.py @@ -0,0 +1,42 @@ +from notebook.auth import passwd +from getpass import getpass +from traitlets.config.manager import BaseJSONConfigManager +from jupyter_core.paths import jupyter_config_dir +import argparse +import sys + +def set_password(args): + password = args.password + while not password : + password1 = getpass("" if args.quiet else "Provide password: ") + password_repeat = getpass("" if args.quiet else "Repeat password: ") + if password1 != password_repeat: + print("Passwords do not match, try again") + elif len(password1) < 4: + print("Please provide at least 4 characters") + else: + password = password1 + + password_hash = passwd(password) + cfg = BaseJSONConfigManager(config_dir=jupyter_config_dir()) + cfg.update('jupyter_notebook_config', { + 'NotebookApp': { + 'password': password_hash, + } + }) + if not args.quiet: + print("password stored in config dir: %s" % jupyter_config_dir()) + +def main(argv): + parser = argparse.ArgumentParser(argv[0]) + subparsers = parser.add_subparsers() + parser_password = subparsers.add_parser('password', help='sets a password for your notebook server') + parser_password.add_argument("password", help="password to set, if not given, a password will be queried for (NOTE: this may not be safe)", + nargs="?") + parser_password.add_argument("--quiet", help="suppress messages", action="store_true") + parser_password.set_defaults(function=set_password) + args = parser.parse_args(argv[1:]) + args.function(args) + +if __name__ == "__main__": + main(sys.argv) \ No newline at end of file diff --git a/notebook/notebookapp.py b/notebook/notebookapp.py index 4f112d500..48deca9fc 100644 --- a/notebook/notebookapp.py +++ b/notebook/notebookapp.py @@ -58,6 +58,15 @@ from notebook import ( DEFAULT_TEMPLATE_PATH_LIST, __version__, ) +from .auth import passwd +from getpass import getpass + +# py23 compatibility +try: + raw_input = raw_input +except NameError: + raw_input = input + from .base.handlers import Template404 from .log import log_request from .services.kernels.kernelmanager import MappingKernelManager @@ -570,6 +579,17 @@ class NotebookApp(JupyterApp): """ ) + password_required = Bool(False, config=True, + help="""Forces users to use a password for the Notebook server. + This is useful in a multi user environment, for instance when + everybody in the LAN can access each other's machine though ssh. + + In such a case, server the notebook server on localhost is not secure + since any user can connect to the notebook server via ssh. + + """ + ) + open_browser = Bool(True, config=True, help="""Whether to open in a browser after starting. The specific browser used is platform dependent and @@ -917,7 +937,13 @@ class NotebookApp(JupyterApp): # ensure default_url starts with base_url if not self.default_url.startswith(self.base_url): self.default_url = url_path_join(self.base_url, self.default_url) - + + if self.password_required and (not self.password): + self.log.critical("Notebook servers are configured to only be run with a password.") + self.log.critical("Hint: run the following command to set a password") + self.log.critical("\t$ python -m notebook.auth password") + sys.exit(1) + self.web_app = NotebookWebApplication( self, self.kernel_manager, self.contents_manager, self.session_manager, self.kernel_spec_manager, diff --git a/notebook/tests/test_notebookapp.py b/notebook/tests/test_notebookapp.py index 270ec1b0f..afb6d921a 100644 --- a/notebook/tests/test_notebookapp.py +++ b/notebook/tests/test_notebookapp.py @@ -14,6 +14,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 NotebookApp = notebookapp.NotebookApp @@ -81,7 +82,6 @@ def test_generate_config(): app.start() assert os.path.exists(os.path.join(td, 'jupyter_notebook_config.py')) - #test if the version testin function works def test_pep440_version():