##// END OF EJS Templates
Fix failing doctests and post correct example of passwd() usage.
Fernando Perez -
Show More
@@ -1,334 +1,332 b''
1 """A tornado based IPython notebook server.
1 """A tornado based IPython notebook server.
2
2
3 Authors:
3 Authors:
4
4
5 * Brian Granger
5 * Brian Granger
6 """
6 """
7
7
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9 # Copyright (C) 2008-2011 The IPython Development Team
9 # Copyright (C) 2008-2011 The IPython Development Team
10 #
10 #
11 # Distributed under the terms of the BSD License. The full license is in
11 # Distributed under the terms of the BSD License. The full license is in
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Imports
16 # Imports
17 #-----------------------------------------------------------------------------
17 #-----------------------------------------------------------------------------
18
18
19 # stdlib
19 # stdlib
20 import errno
20 import errno
21 import logging
21 import logging
22 import os
22 import os
23 import signal
23 import signal
24 import socket
24 import socket
25 import sys
25 import sys
26 import threading
26 import threading
27 import webbrowser
27 import webbrowser
28
28
29 # Third party
29 # Third party
30 import zmq
30 import zmq
31
31
32 # Install the pyzmq ioloop. This has to be done before anything else from
32 # Install the pyzmq ioloop. This has to be done before anything else from
33 # tornado is imported.
33 # tornado is imported.
34 from zmq.eventloop import ioloop
34 from zmq.eventloop import ioloop
35 import tornado.ioloop
35 import tornado.ioloop
36 tornado.ioloop.IOLoop = ioloop.IOLoop
36 tornado.ioloop.IOLoop = ioloop.IOLoop
37
37
38 from tornado import httpserver
38 from tornado import httpserver
39 from tornado import web
39 from tornado import web
40
40
41 # Our own libraries
41 # Our own libraries
42 from .kernelmanager import MappingKernelManager
42 from .kernelmanager import MappingKernelManager
43 from .handlers import (LoginHandler,
43 from .handlers import (LoginHandler,
44 ProjectDashboardHandler, NewHandler, NamedNotebookHandler,
44 ProjectDashboardHandler, NewHandler, NamedNotebookHandler,
45 MainKernelHandler, KernelHandler, KernelActionHandler, IOPubHandler,
45 MainKernelHandler, KernelHandler, KernelActionHandler, IOPubHandler,
46 ShellHandler, NotebookRootHandler, NotebookHandler, RSTHandler
46 ShellHandler, NotebookRootHandler, NotebookHandler, RSTHandler
47 )
47 )
48 from .notebookmanager import NotebookManager
48 from .notebookmanager import NotebookManager
49
49
50 from IPython.config.application import catch_config_error
50 from IPython.config.application import catch_config_error
51 from IPython.core.application import BaseIPythonApplication
51 from IPython.core.application import BaseIPythonApplication
52 from IPython.core.profiledir import ProfileDir
52 from IPython.core.profiledir import ProfileDir
53 from IPython.zmq.session import Session, default_secure
53 from IPython.zmq.session import Session, default_secure
54 from IPython.zmq.zmqshell import ZMQInteractiveShell
54 from IPython.zmq.zmqshell import ZMQInteractiveShell
55 from IPython.zmq.ipkernel import (
55 from IPython.zmq.ipkernel import (
56 flags as ipkernel_flags,
56 flags as ipkernel_flags,
57 aliases as ipkernel_aliases,
57 aliases as ipkernel_aliases,
58 IPKernelApp
58 IPKernelApp
59 )
59 )
60 from IPython.utils.traitlets import Dict, Unicode, Int, List, Enum, Bool
60 from IPython.utils.traitlets import Dict, Unicode, Int, List, Enum, Bool
61
61
62 #-----------------------------------------------------------------------------
62 #-----------------------------------------------------------------------------
63 # Module globals
63 # Module globals
64 #-----------------------------------------------------------------------------
64 #-----------------------------------------------------------------------------
65
65
66 _kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)"
66 _kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)"
67 _kernel_action_regex = r"(?P<action>restart|interrupt)"
67 _kernel_action_regex = r"(?P<action>restart|interrupt)"
68 _notebook_id_regex = r"(?P<notebook_id>\w+-\w+-\w+-\w+-\w+)"
68 _notebook_id_regex = r"(?P<notebook_id>\w+-\w+-\w+-\w+-\w+)"
69
69
70 LOCALHOST = '127.0.0.1'
70 LOCALHOST = '127.0.0.1'
71
71
72 _examples = """
72 _examples = """
73 ipython notebook # start the notebook
73 ipython notebook # start the notebook
74 ipython notebook --profile=sympy # use the sympy profile
74 ipython notebook --profile=sympy # use the sympy profile
75 ipython notebook --pylab=inline # pylab in inline plotting mode
75 ipython notebook --pylab=inline # pylab in inline plotting mode
76 ipython notebook --certfile=mycert.pem # use SSL/TLS certificate
76 ipython notebook --certfile=mycert.pem # use SSL/TLS certificate
77 ipython notebook --port=5555 --ip=* # Listen on port 5555, all interfaces
77 ipython notebook --port=5555 --ip=* # Listen on port 5555, all interfaces
78 """
78 """
79
79
80 #-----------------------------------------------------------------------------
80 #-----------------------------------------------------------------------------
81 # The Tornado web application
81 # The Tornado web application
82 #-----------------------------------------------------------------------------
82 #-----------------------------------------------------------------------------
83
83
84 class NotebookWebApplication(web.Application):
84 class NotebookWebApplication(web.Application):
85
85
86 def __init__(self, ipython_app, kernel_manager, notebook_manager, log):
86 def __init__(self, ipython_app, kernel_manager, notebook_manager, log):
87 handlers = [
87 handlers = [
88 (r"/", ProjectDashboardHandler),
88 (r"/", ProjectDashboardHandler),
89 (r"/login", LoginHandler),
89 (r"/login", LoginHandler),
90 (r"/new", NewHandler),
90 (r"/new", NewHandler),
91 (r"/%s" % _notebook_id_regex, NamedNotebookHandler),
91 (r"/%s" % _notebook_id_regex, NamedNotebookHandler),
92 (r"/kernels", MainKernelHandler),
92 (r"/kernels", MainKernelHandler),
93 (r"/kernels/%s" % _kernel_id_regex, KernelHandler),
93 (r"/kernels/%s" % _kernel_id_regex, KernelHandler),
94 (r"/kernels/%s/%s" % (_kernel_id_regex, _kernel_action_regex), KernelActionHandler),
94 (r"/kernels/%s/%s" % (_kernel_id_regex, _kernel_action_regex), KernelActionHandler),
95 (r"/kernels/%s/iopub" % _kernel_id_regex, IOPubHandler),
95 (r"/kernels/%s/iopub" % _kernel_id_regex, IOPubHandler),
96 (r"/kernels/%s/shell" % _kernel_id_regex, ShellHandler),
96 (r"/kernels/%s/shell" % _kernel_id_regex, ShellHandler),
97 (r"/notebooks", NotebookRootHandler),
97 (r"/notebooks", NotebookRootHandler),
98 (r"/notebooks/%s" % _notebook_id_regex, NotebookHandler),
98 (r"/notebooks/%s" % _notebook_id_regex, NotebookHandler),
99 (r"/rstservice/render", RSTHandler)
99 (r"/rstservice/render", RSTHandler)
100 ]
100 ]
101 settings = dict(
101 settings = dict(
102 template_path=os.path.join(os.path.dirname(__file__), "templates"),
102 template_path=os.path.join(os.path.dirname(__file__), "templates"),
103 static_path=os.path.join(os.path.dirname(__file__), "static"),
103 static_path=os.path.join(os.path.dirname(__file__), "static"),
104 cookie_secret=os.urandom(1024),
104 cookie_secret=os.urandom(1024),
105 login_url="/login",
105 login_url="/login",
106 )
106 )
107 web.Application.__init__(self, handlers, **settings)
107 web.Application.__init__(self, handlers, **settings)
108
108
109 self.kernel_manager = kernel_manager
109 self.kernel_manager = kernel_manager
110 self.log = log
110 self.log = log
111 self.notebook_manager = notebook_manager
111 self.notebook_manager = notebook_manager
112 self.ipython_app = ipython_app
112 self.ipython_app = ipython_app
113 self.read_only = self.ipython_app.read_only
113 self.read_only = self.ipython_app.read_only
114
114
115
115
116 #-----------------------------------------------------------------------------
116 #-----------------------------------------------------------------------------
117 # Aliases and Flags
117 # Aliases and Flags
118 #-----------------------------------------------------------------------------
118 #-----------------------------------------------------------------------------
119
119
120 flags = dict(ipkernel_flags)
120 flags = dict(ipkernel_flags)
121 flags['no-browser']=(
121 flags['no-browser']=(
122 {'NotebookApp' : {'open_browser' : False}},
122 {'NotebookApp' : {'open_browser' : False}},
123 "Don't open the notebook in a browser after startup."
123 "Don't open the notebook in a browser after startup."
124 )
124 )
125 flags['read-only'] = (
125 flags['read-only'] = (
126 {'NotebookApp' : {'read_only' : True}},
126 {'NotebookApp' : {'read_only' : True}},
127 """Allow read-only access to notebooks.
127 """Allow read-only access to notebooks.
128
128
129 When using a password to protect the notebook server, this flag
129 When using a password to protect the notebook server, this flag
130 allows unauthenticated clients to view the notebook list, and
130 allows unauthenticated clients to view the notebook list, and
131 individual notebooks, but not edit them, start kernels, or run
131 individual notebooks, but not edit them, start kernels, or run
132 code.
132 code.
133
133
134 If no password is set, the server will be entirely read-only.
134 If no password is set, the server will be entirely read-only.
135 """
135 """
136 )
136 )
137
137
138 # the flags that are specific to the frontend
138 # the flags that are specific to the frontend
139 # these must be scrubbed before being passed to the kernel,
139 # these must be scrubbed before being passed to the kernel,
140 # or it will raise an error on unrecognized flags
140 # or it will raise an error on unrecognized flags
141 notebook_flags = ['no-browser', 'read-only']
141 notebook_flags = ['no-browser', 'read-only']
142
142
143 aliases = dict(ipkernel_aliases)
143 aliases = dict(ipkernel_aliases)
144
144
145 aliases.update({
145 aliases.update({
146 'ip': 'NotebookApp.ip',
146 'ip': 'NotebookApp.ip',
147 'port': 'NotebookApp.port',
147 'port': 'NotebookApp.port',
148 'keyfile': 'NotebookApp.keyfile',
148 'keyfile': 'NotebookApp.keyfile',
149 'certfile': 'NotebookApp.certfile',
149 'certfile': 'NotebookApp.certfile',
150 'notebook-dir': 'NotebookManager.notebook_dir',
150 'notebook-dir': 'NotebookManager.notebook_dir',
151 })
151 })
152
152
153 # remove ipkernel flags that are singletons, and don't make sense in
153 # remove ipkernel flags that are singletons, and don't make sense in
154 # multi-kernel evironment:
154 # multi-kernel evironment:
155 aliases.pop('f', None)
155 aliases.pop('f', None)
156
156
157 notebook_aliases = [u'port', u'ip', u'keyfile', u'certfile',
157 notebook_aliases = [u'port', u'ip', u'keyfile', u'certfile',
158 u'notebook-dir']
158 u'notebook-dir']
159
159
160 #-----------------------------------------------------------------------------
160 #-----------------------------------------------------------------------------
161 # NotebookApp
161 # NotebookApp
162 #-----------------------------------------------------------------------------
162 #-----------------------------------------------------------------------------
163
163
164 class NotebookApp(BaseIPythonApplication):
164 class NotebookApp(BaseIPythonApplication):
165
165
166 name = 'ipython-notebook'
166 name = 'ipython-notebook'
167 default_config_file_name='ipython_notebook_config.py'
167 default_config_file_name='ipython_notebook_config.py'
168
168
169 description = """
169 description = """
170 The IPython HTML Notebook.
170 The IPython HTML Notebook.
171
171
172 This launches a Tornado based HTML Notebook Server that serves up an
172 This launches a Tornado based HTML Notebook Server that serves up an
173 HTML5/Javascript Notebook client.
173 HTML5/Javascript Notebook client.
174 """
174 """
175 examples = _examples
175 examples = _examples
176
176
177 classes = [IPKernelApp, ZMQInteractiveShell, ProfileDir, Session,
177 classes = [IPKernelApp, ZMQInteractiveShell, ProfileDir, Session,
178 MappingKernelManager, NotebookManager]
178 MappingKernelManager, NotebookManager]
179 flags = Dict(flags)
179 flags = Dict(flags)
180 aliases = Dict(aliases)
180 aliases = Dict(aliases)
181
181
182 kernel_argv = List(Unicode)
182 kernel_argv = List(Unicode)
183
183
184 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
184 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
185 default_value=logging.INFO,
185 default_value=logging.INFO,
186 config=True,
186 config=True,
187 help="Set the log level by value or name.")
187 help="Set the log level by value or name.")
188
188
189 # Network related information.
189 # Network related information.
190
190
191 ip = Unicode(LOCALHOST, config=True,
191 ip = Unicode(LOCALHOST, config=True,
192 help="The IP address the notebook server will listen on."
192 help="The IP address the notebook server will listen on."
193 )
193 )
194
194
195 def _ip_changed(self, name, old, new):
195 def _ip_changed(self, name, old, new):
196 if new == u'*': self.ip = u''
196 if new == u'*': self.ip = u''
197
197
198 port = Int(8888, config=True,
198 port = Int(8888, config=True,
199 help="The port the notebook server will listen on."
199 help="The port the notebook server will listen on."
200 )
200 )
201
201
202 certfile = Unicode(u'', config=True,
202 certfile = Unicode(u'', config=True,
203 help="""The full path to an SSL/TLS certificate file."""
203 help="""The full path to an SSL/TLS certificate file."""
204 )
204 )
205
205
206 keyfile = Unicode(u'', config=True,
206 keyfile = Unicode(u'', config=True,
207 help="""The full path to a private key file for usage with SSL/TLS."""
207 help="""The full path to a private key file for usage with SSL/TLS."""
208 )
208 )
209
209
210 password = Unicode(u'', config=True,
210 password = Unicode(u'', config=True,
211 help="""Hashed password to use for web authentication.
211 help="""Hashed password to use for web authentication.
212
212
213 To generate, do:
213 To generate, type in a python/IPython shell:
214
214
215 from IPython.lib import passwd
215 from IPython.lib import passwd; passwd()
216
217 passwd('mypassphrase')
218
216
219 The string should be of the form type:salt:hashed-password.
217 The string should be of the form type:salt:hashed-password.
220 """
218 """
221 )
219 )
222
220
223 open_browser = Bool(True, config=True,
221 open_browser = Bool(True, config=True,
224 help="Whether to open in a browser after starting.")
222 help="Whether to open in a browser after starting.")
225
223
226 read_only = Bool(False, config=True,
224 read_only = Bool(False, config=True,
227 help="Whether to prevent editing/execution of notebooks."
225 help="Whether to prevent editing/execution of notebooks."
228 )
226 )
229
227
230 def parse_command_line(self, argv=None):
228 def parse_command_line(self, argv=None):
231 super(NotebookApp, self).parse_command_line(argv)
229 super(NotebookApp, self).parse_command_line(argv)
232 if argv is None:
230 if argv is None:
233 argv = sys.argv[1:]
231 argv = sys.argv[1:]
234
232
235 self.kernel_argv = list(argv) # copy
233 self.kernel_argv = list(argv) # copy
236 # Kernel should inherit default config file from frontend
234 # Kernel should inherit default config file from frontend
237 self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name)
235 self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name)
238 # Scrub frontend-specific flags
236 # Scrub frontend-specific flags
239 for a in argv:
237 for a in argv:
240 if a.startswith('-') and a.lstrip('-') in notebook_flags:
238 if a.startswith('-') and a.lstrip('-') in notebook_flags:
241 self.kernel_argv.remove(a)
239 self.kernel_argv.remove(a)
242 swallow_next = False
240 swallow_next = False
243 for a in argv:
241 for a in argv:
244 if swallow_next:
242 if swallow_next:
245 self.kernel_argv.remove(a)
243 self.kernel_argv.remove(a)
246 swallow_next = False
244 swallow_next = False
247 continue
245 continue
248 if a.startswith('-'):
246 if a.startswith('-'):
249 split = a.lstrip('-').split('=')
247 split = a.lstrip('-').split('=')
250 alias = split[0]
248 alias = split[0]
251 if alias in notebook_aliases:
249 if alias in notebook_aliases:
252 self.kernel_argv.remove(a)
250 self.kernel_argv.remove(a)
253 if len(split) == 1:
251 if len(split) == 1:
254 # alias passed with arg via space
252 # alias passed with arg via space
255 swallow_next = True
253 swallow_next = True
256
254
257 def init_configurables(self):
255 def init_configurables(self):
258 # Don't let Qt or ZMQ swallow KeyboardInterupts.
256 # Don't let Qt or ZMQ swallow KeyboardInterupts.
259 signal.signal(signal.SIGINT, signal.SIG_DFL)
257 signal.signal(signal.SIGINT, signal.SIG_DFL)
260
258
261 # force Session default to be secure
259 # force Session default to be secure
262 default_secure(self.config)
260 default_secure(self.config)
263 # Create a KernelManager and start a kernel.
261 # Create a KernelManager and start a kernel.
264 self.kernel_manager = MappingKernelManager(
262 self.kernel_manager = MappingKernelManager(
265 config=self.config, log=self.log, kernel_argv=self.kernel_argv,
263 config=self.config, log=self.log, kernel_argv=self.kernel_argv,
266 connection_dir = self.profile_dir.security_dir,
264 connection_dir = self.profile_dir.security_dir,
267 )
265 )
268 self.notebook_manager = NotebookManager(config=self.config, log=self.log)
266 self.notebook_manager = NotebookManager(config=self.config, log=self.log)
269 self.notebook_manager.list_notebooks()
267 self.notebook_manager.list_notebooks()
270
268
271 def init_logging(self):
269 def init_logging(self):
272 super(NotebookApp, self).init_logging()
270 super(NotebookApp, self).init_logging()
273 # This prevents double log messages because tornado use a root logger that
271 # This prevents double log messages because tornado use a root logger that
274 # self.log is a child of. The logging module dipatches log messages to a log
272 # self.log is a child of. The logging module dipatches log messages to a log
275 # and all of its ancenstors until propagate is set to False.
273 # and all of its ancenstors until propagate is set to False.
276 self.log.propagate = False
274 self.log.propagate = False
277
275
278 @catch_config_error
276 @catch_config_error
279 def initialize(self, argv=None):
277 def initialize(self, argv=None):
280 super(NotebookApp, self).initialize(argv)
278 super(NotebookApp, self).initialize(argv)
281 self.init_configurables()
279 self.init_configurables()
282 self.web_app = NotebookWebApplication(
280 self.web_app = NotebookWebApplication(
283 self, self.kernel_manager, self.notebook_manager, self.log
281 self, self.kernel_manager, self.notebook_manager, self.log
284 )
282 )
285 if self.certfile:
283 if self.certfile:
286 ssl_options = dict(certfile=self.certfile)
284 ssl_options = dict(certfile=self.certfile)
287 if self.keyfile:
285 if self.keyfile:
288 ssl_options['keyfile'] = self.keyfile
286 ssl_options['keyfile'] = self.keyfile
289 else:
287 else:
290 ssl_options = None
288 ssl_options = None
291 self.web_app.password = self.password
289 self.web_app.password = self.password
292 self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options)
290 self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options)
293 if ssl_options is None and not self.ip:
291 if ssl_options is None and not self.ip:
294 self.log.critical('WARNING: the notebook server is listening on all IP addresses '
292 self.log.critical('WARNING: the notebook server is listening on all IP addresses '
295 'but not using any encryption or authentication. This is highly '
293 'but not using any encryption or authentication. This is highly '
296 'insecure and not recommended.')
294 'insecure and not recommended.')
297
295
298 # Try random ports centered around the default.
296 # Try random ports centered around the default.
299 from random import randint
297 from random import randint
300 n = 50 # Max number of attempts, keep reasonably large.
298 n = 50 # Max number of attempts, keep reasonably large.
301 for port in range(self.port, self.port+5) + [self.port + randint(-2*n, 2*n) for i in range(n-5)]:
299 for port in range(self.port, self.port+5) + [self.port + randint(-2*n, 2*n) for i in range(n-5)]:
302 try:
300 try:
303 self.http_server.listen(port, self.ip)
301 self.http_server.listen(port, self.ip)
304 except socket.error, e:
302 except socket.error, e:
305 if e.errno != errno.EADDRINUSE:
303 if e.errno != errno.EADDRINUSE:
306 raise
304 raise
307 self.log.info('The port %i is already in use, trying another random port.' % port)
305 self.log.info('The port %i is already in use, trying another random port.' % port)
308 else:
306 else:
309 self.port = port
307 self.port = port
310 break
308 break
311
309
312 def start(self):
310 def start(self):
313 ip = self.ip if self.ip else '[all ip addresses on your system]'
311 ip = self.ip if self.ip else '[all ip addresses on your system]'
314 proto = 'https' if self.certfile else 'http'
312 proto = 'https' if self.certfile else 'http'
315 self.log.info("The IPython Notebook is running at: %s://%s:%i" % (proto,
313 self.log.info("The IPython Notebook is running at: %s://%s:%i" % (proto,
316 ip,
314 ip,
317 self.port))
315 self.port))
318 if self.open_browser:
316 if self.open_browser:
319 ip = self.ip or '127.0.0.1'
317 ip = self.ip or '127.0.0.1'
320 b = lambda : webbrowser.open("%s://%s:%i" % (proto, ip, self.port),
318 b = lambda : webbrowser.open("%s://%s:%i" % (proto, ip, self.port),
321 new=2)
319 new=2)
322 threading.Thread(target=b).start()
320 threading.Thread(target=b).start()
323
321
324 ioloop.IOLoop.instance().start()
322 ioloop.IOLoop.instance().start()
325
323
326 #-----------------------------------------------------------------------------
324 #-----------------------------------------------------------------------------
327 # Main entry point
325 # Main entry point
328 #-----------------------------------------------------------------------------
326 #-----------------------------------------------------------------------------
329
327
330 def launch_new_instance():
328 def launch_new_instance():
331 app = NotebookApp()
329 app = NotebookApp()
332 app.initialize()
330 app.initialize()
333 app.start()
331 app.start()
334
332
@@ -1,102 +1,117 b''
1 """
1 """
2 Password generation for the IPython notebook.
2 Password generation for the IPython notebook.
3 """
3 """
4
4 #-----------------------------------------------------------------------------
5 # Imports
6 #-----------------------------------------------------------------------------
7 # Stdlib
8 import getpass
5 import hashlib
9 import hashlib
6 import random
10 import random
7 import getpass
8
11
12 # Our own
9 from IPython.core.error import UsageError
13 from IPython.core.error import UsageError
14 from IPython.testing.skipdoctest import skip_doctest
15
16 #-----------------------------------------------------------------------------
17 # Globals
18 #-----------------------------------------------------------------------------
10
19
11 # Length of the salt in nr of hex chars, which implies salt_len * 4
20 # Length of the salt in nr of hex chars, which implies salt_len * 4
12 # bits of randomness.
21 # bits of randomness.
13 salt_len = 12
22 salt_len = 12
14
23
24 #-----------------------------------------------------------------------------
25 # Functions
26 #-----------------------------------------------------------------------------
27
28 @skip_doctest
15 def passwd(passphrase=None, algorithm='sha1'):
29 def passwd(passphrase=None, algorithm='sha1'):
16 """Generate hashed password and salt for use in notebook configuration.
30 """Generate hashed password and salt for use in notebook configuration.
17
31
18 In the notebook configuration, set `c.NotebookApp.password` to
32 In the notebook configuration, set `c.NotebookApp.password` to
19 the generated string.
33 the generated string.
20
34
21 Parameters
35 Parameters
22 ----------
36 ----------
23 passphrase : str
37 passphrase : str
24 Password to hash. If unspecified, the user is asked to input
38 Password to hash. If unspecified, the user is asked to input
25 and verify a password.
39 and verify a password.
26 algorithm : str
40 algorithm : str
27 Hashing algorithm to use (e.g, 'sha1' or any argument supported
41 Hashing algorithm to use (e.g, 'sha1' or any argument supported
28 by :func:`hashlib.new`).
42 by :func:`hashlib.new`).
29
43
30 Returns
44 Returns
31 -------
45 -------
32 hashed_passphrase : str
46 hashed_passphrase : str
33 Hashed password, in the format 'hash_algorithm:salt:passphrase_hash'.
47 Hashed password, in the format 'hash_algorithm:salt:passphrase_hash'.
34
48
35 Examples
49 Examples
36 --------
50 --------
37 In [1]: passwd('mypassword')
51 In [1]: passwd('mypassword')
38 Out[1]: 'sha1:7cf3:b7d6da294ea9592a9480c8f52e63cd42cfb9dd12'
52 Out[1]: 'sha1:7cf3:b7d6da294ea9592a9480c8f52e63cd42cfb9dd12'
39
53
40 """
54 """
41 if passphrase is None:
55 if passphrase is None:
42 for i in range(3):
56 for i in range(3):
43 p0 = getpass.getpass('Enter password: ')
57 p0 = getpass.getpass('Enter password: ')
44 p1 = getpass.getpass('Verify password: ')
58 p1 = getpass.getpass('Verify password: ')
45 if p0 == p1:
59 if p0 == p1:
46 passphrase = p0
60 passphrase = p0
47 break
61 break
48 else:
62 else:
49 print('Passwords do not match.')
63 print('Passwords do not match.')
50 else:
64 else:
51 raise UsageError('No matching passwords found. Giving up.')
65 raise UsageError('No matching passwords found. Giving up.')
52
66
53 h = hashlib.new(algorithm)
67 h = hashlib.new(algorithm)
54 salt = ('%0' + str(salt_len) + 'x') % random.getrandbits(4 * salt_len)
68 salt = ('%0' + str(salt_len) + 'x') % random.getrandbits(4 * salt_len)
55 h.update(passphrase + salt)
69 h.update(passphrase + salt)
56
70
57 return ':'.join((algorithm, salt, h.hexdigest()))
71 return ':'.join((algorithm, salt, h.hexdigest()))
58
72
73
59 def passwd_check(hashed_passphrase, passphrase):
74 def passwd_check(hashed_passphrase, passphrase):
60 """Verify that a given passphrase matches its hashed version.
75 """Verify that a given passphrase matches its hashed version.
61
76
62 Parameters
77 Parameters
63 ----------
78 ----------
64 hashed_passphrase : str
79 hashed_passphrase : str
65 Hashed password, in the format returned by `passwd`.
80 Hashed password, in the format returned by `passwd`.
66 passphrase : str
81 passphrase : str
67 Passphrase to validate.
82 Passphrase to validate.
68
83
69 Returns
84 Returns
70 -------
85 -------
71 valid : bool
86 valid : bool
72 True if the passphrase matches the hash.
87 True if the passphrase matches the hash.
73
88
74 Examples
89 Examples
75 --------
90 --------
76 In [1]: from IPython.lib.security import passwd_check
91 In [1]: from IPython.lib.security import passwd_check
77
92
78 In [2]: passwd_check('sha1:7cf3:b7d6da294ea9592a9480c8f52e63cd42cfb9dd12',
93 In [2]: passwd_check('sha1:0e112c3ddfce:a68df677475c2b47b6e86d0467eec97ac5f4b85a',
79 ...: 'mypassword')
94 ...: 'mypassword')
80 Out[2]: True
95 Out[2]: True
81
96
82 In [3]: passwd_check('sha1:7cf3:b7d6da294ea9592a9480c8f52e63cd42cfb9dd12',
97 In [3]: passwd_check('sha1:0e112c3ddfce:a68df677475c2b47b6e86d0467eec97ac5f4b85a',
83 ...: 'anotherpassword')
98 ...: 'anotherpassword')
84 Out[3]: False
99 Out[3]: False
85
100
86 """
101 """
87 try:
102 try:
88 algorithm, salt, pw_digest = hashed_passphrase.split(':', 2)
103 algorithm, salt, pw_digest = hashed_passphrase.split(':', 2)
89 except (ValueError, TypeError):
104 except (ValueError, TypeError):
90 return False
105 return False
91
106
92 try:
107 try:
93 h = hashlib.new(algorithm)
108 h = hashlib.new(algorithm)
94 except ValueError:
109 except ValueError:
95 return False
110 return False
96
111
97 if len(pw_digest) == 0 or len(salt) != salt_len:
112 if len(pw_digest) == 0 or len(salt) != salt_len:
98 return False
113 return False
99
114
100 h.update(passphrase + salt)
115 h.update(passphrase + salt)
101
116
102 return h.hexdigest() == pw_digest
117 return h.hexdigest() == pw_digest
General Comments 0
You need to be logged in to leave comments. Login now