##// END OF EJS Templates
Set secure cookie by default if login handler is hit....
Matthias Bussonnier -
Show More
@@ -1,95 +1,101 b''
1 """Tornado handlers for logging into the notebook."""
1 """Tornado handlers for logging into the notebook."""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 import uuid
6 import uuid
7
7
8 from tornado.escape import url_escape
8 from tornado.escape import url_escape
9
9
10 from IPython.lib.security import passwd_check
10 from IPython.lib.security import passwd_check
11
11
12 from ..base.handlers import IPythonHandler
12 from ..base.handlers import IPythonHandler
13
13
14
14
15 class LoginHandler(IPythonHandler):
15 class LoginHandler(IPythonHandler):
16 """The basic tornado login handler
16 """The basic tornado login handler
17
17
18 authenticates with a hashed password from the configuration.
18 authenticates with a hashed password from the configuration.
19 """
19 """
20 def _render(self, message=None):
20 def _render(self, message=None):
21 self.write(self.render_template('login.html',
21 self.write(self.render_template('login.html',
22 next=url_escape(self.get_argument('next', default=self.base_url)),
22 next=url_escape(self.get_argument('next', default=self.base_url)),
23 message=message,
23 message=message,
24 ))
24 ))
25
25
26 def get(self):
26 def get(self):
27 if self.current_user:
27 if self.current_user:
28 self.redirect(self.get_argument('next', default=self.base_url))
28 self.redirect(self.get_argument('next', default=self.base_url))
29 else:
29 else:
30 self._render()
30 self._render()
31
31
32 @property
32 @property
33 def hashed_password(self):
33 def hashed_password(self):
34 return self.password_from_settings(self.settings)
34 return self.password_from_settings(self.settings)
35
35
36 def post(self):
36 def post(self):
37 typed_password = self.get_argument('password', default=u'')
37 typed_password = self.get_argument('password', default=u'')
38 if self.login_available(self.settings):
38 if self.login_available(self.settings):
39 if passwd_check(self.hashed_password, typed_password):
39 if passwd_check(self.hashed_password, typed_password):
40 self.set_secure_cookie(self.cookie_name, str(uuid.uuid4()))
40 # tornado <4.2 have a bug that consider secure==True as soon as
41 # 'secure' kwarg is passed to set_secure_cookie
42 if self.settings.get('secure_cookie', self.request.protocol == 'https'):
43 kwargs = {'secure':True}
44 else:
45 kwargs = {}
46 self.set_secure_cookie(self.cookie_name, str(uuid.uuid4()), **kwargs)
41 else:
47 else:
42 self._render(message={'error': 'Invalid password'})
48 self._render(message={'error': 'Invalid password'})
43 return
49 return
44
50
45 self.redirect(self.get_argument('next', default=self.base_url))
51 self.redirect(self.get_argument('next', default=self.base_url))
46
52
47 @classmethod
53 @classmethod
48 def get_user(cls, handler):
54 def get_user(cls, handler):
49 """Called by handlers.get_current_user for identifying the current user.
55 """Called by handlers.get_current_user for identifying the current user.
50
56
51 See tornado.web.RequestHandler.get_current_user for details.
57 See tornado.web.RequestHandler.get_current_user for details.
52 """
58 """
53 # Can't call this get_current_user because it will collide when
59 # Can't call this get_current_user because it will collide when
54 # called on LoginHandler itself.
60 # called on LoginHandler itself.
55
61
56 user_id = handler.get_secure_cookie(handler.cookie_name)
62 user_id = handler.get_secure_cookie(handler.cookie_name)
57 # For now the user_id should not return empty, but it could, eventually.
63 # For now the user_id should not return empty, but it could, eventually.
58 if user_id == '':
64 if user_id == '':
59 user_id = 'anonymous'
65 user_id = 'anonymous'
60 if user_id is None:
66 if user_id is None:
61 # prevent extra Invalid cookie sig warnings:
67 # prevent extra Invalid cookie sig warnings:
62 handler.clear_login_cookie()
68 handler.clear_login_cookie()
63 if not handler.login_available:
69 if not handler.login_available:
64 user_id = 'anonymous'
70 user_id = 'anonymous'
65 return user_id
71 return user_id
66
72
67
73
68 @classmethod
74 @classmethod
69 def validate_security(cls, app, ssl_options=None):
75 def validate_security(cls, app, ssl_options=None):
70 """Check the notebook application's security.
76 """Check the notebook application's security.
71
77
72 Show messages, or abort if necessary, based on the security configuration.
78 Show messages, or abort if necessary, based on the security configuration.
73 """
79 """
74 if not app.ip:
80 if not app.ip:
75 warning = "WARNING: The notebook server is listening on all IP addresses"
81 warning = "WARNING: The notebook server is listening on all IP addresses"
76 if ssl_options is None:
82 if ssl_options is None:
77 app.log.warning(warning + " and not using encryption. This "
83 app.log.warning(warning + " and not using encryption. This "
78 "is not recommended.")
84 "is not recommended.")
79 if not app.password:
85 if not app.password:
80 app.log.warning(warning + " and not using authentication. "
86 app.log.warning(warning + " and not using authentication. "
81 "This is highly insecure and not recommended.")
87 "This is highly insecure and not recommended.")
82
88
83 @classmethod
89 @classmethod
84 def password_from_settings(cls, settings):
90 def password_from_settings(cls, settings):
85 """Return the hashed password from the tornado settings.
91 """Return the hashed password from the tornado settings.
86
92
87 If there is no configured password, an empty string will be returned.
93 If there is no configured password, an empty string will be returned.
88 """
94 """
89 return settings.get('password', u'')
95 return settings.get('password', u'')
90
96
91 @classmethod
97 @classmethod
92 def login_available(cls, settings):
98 def login_available(cls, settings):
93 """Whether this LoginHandler is needed - and therefore whether the login page should be displayed."""
99 """Whether this LoginHandler is needed - and therefore whether the login page should be displayed."""
94 return bool(cls.password_from_settings(settings))
100 return bool(cls.password_from_settings(settings))
95
101
General Comments 0
You need to be logged in to leave comments. Login now