##// END OF EJS Templates
restrict login redirect to notebook app...
Min RK -
Show More
@@ -1,101 +1,109 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 next_url = self.get_argument('next', default=self.base_url)
29 if not next_url.startswith(self.base_url):
30 # require that next_url be absolute path within our path
31 next_url = self.base_url
32 self.redirect(next_url)
29 else:
33 else:
30 self._render()
34 self._render()
31
35
32 @property
36 @property
33 def hashed_password(self):
37 def hashed_password(self):
34 return self.password_from_settings(self.settings)
38 return self.password_from_settings(self.settings)
35
39
36 def post(self):
40 def post(self):
37 typed_password = self.get_argument('password', default=u'')
41 typed_password = self.get_argument('password', default=u'')
38 if self.login_available(self.settings):
42 if self.login_available(self.settings):
39 if passwd_check(self.hashed_password, typed_password):
43 if passwd_check(self.hashed_password, typed_password):
40 # tornado <4.2 have a bug that consider secure==True as soon as
44 # tornado <4.2 have a bug that consider secure==True as soon as
41 # 'secure' kwarg is passed to set_secure_cookie
45 # 'secure' kwarg is passed to set_secure_cookie
42 if self.settings.get('secure_cookie', self.request.protocol == 'https'):
46 if self.settings.get('secure_cookie', self.request.protocol == 'https'):
43 kwargs = {'secure':True}
47 kwargs = {'secure':True}
44 else:
48 else:
45 kwargs = {}
49 kwargs = {}
46 self.set_secure_cookie(self.cookie_name, str(uuid.uuid4()), **kwargs)
50 self.set_secure_cookie(self.cookie_name, str(uuid.uuid4()), **kwargs)
47 else:
51 else:
48 self._render(message={'error': 'Invalid password'})
52 self._render(message={'error': 'Invalid password'})
49 return
53 return
50
54
51 self.redirect(self.get_argument('next', default=self.base_url))
55 next_url = self.get_argument('next', default=self.base_url)
56 if not next_url.startswith(self.base_url):
57 # require that next_url be absolute path within our path
58 next_url = self.base_url
59 self.redirect(next_url)
52
60
53 @classmethod
61 @classmethod
54 def get_user(cls, handler):
62 def get_user(cls, handler):
55 """Called by handlers.get_current_user for identifying the current user.
63 """Called by handlers.get_current_user for identifying the current user.
56
64
57 See tornado.web.RequestHandler.get_current_user for details.
65 See tornado.web.RequestHandler.get_current_user for details.
58 """
66 """
59 # Can't call this get_current_user because it will collide when
67 # Can't call this get_current_user because it will collide when
60 # called on LoginHandler itself.
68 # called on LoginHandler itself.
61
69
62 user_id = handler.get_secure_cookie(handler.cookie_name)
70 user_id = handler.get_secure_cookie(handler.cookie_name)
63 # For now the user_id should not return empty, but it could, eventually.
71 # For now the user_id should not return empty, but it could, eventually.
64 if user_id == '':
72 if user_id == '':
65 user_id = 'anonymous'
73 user_id = 'anonymous'
66 if user_id is None:
74 if user_id is None:
67 # prevent extra Invalid cookie sig warnings:
75 # prevent extra Invalid cookie sig warnings:
68 handler.clear_login_cookie()
76 handler.clear_login_cookie()
69 if not handler.login_available:
77 if not handler.login_available:
70 user_id = 'anonymous'
78 user_id = 'anonymous'
71 return user_id
79 return user_id
72
80
73
81
74 @classmethod
82 @classmethod
75 def validate_security(cls, app, ssl_options=None):
83 def validate_security(cls, app, ssl_options=None):
76 """Check the notebook application's security.
84 """Check the notebook application's security.
77
85
78 Show messages, or abort if necessary, based on the security configuration.
86 Show messages, or abort if necessary, based on the security configuration.
79 """
87 """
80 if not app.ip:
88 if not app.ip:
81 warning = "WARNING: The notebook server is listening on all IP addresses"
89 warning = "WARNING: The notebook server is listening on all IP addresses"
82 if ssl_options is None:
90 if ssl_options is None:
83 app.log.warning(warning + " and not using encryption. This "
91 app.log.warning(warning + " and not using encryption. This "
84 "is not recommended.")
92 "is not recommended.")
85 if not app.password:
93 if not app.password:
86 app.log.warning(warning + " and not using authentication. "
94 app.log.warning(warning + " and not using authentication. "
87 "This is highly insecure and not recommended.")
95 "This is highly insecure and not recommended.")
88
96
89 @classmethod
97 @classmethod
90 def password_from_settings(cls, settings):
98 def password_from_settings(cls, settings):
91 """Return the hashed password from the tornado settings.
99 """Return the hashed password from the tornado settings.
92
100
93 If there is no configured password, an empty string will be returned.
101 If there is no configured password, an empty string will be returned.
94 """
102 """
95 return settings.get('password', u'')
103 return settings.get('password', u'')
96
104
97 @classmethod
105 @classmethod
98 def login_available(cls, settings):
106 def login_available(cls, settings):
99 """Whether this LoginHandler is needed - and therefore whether the login page should be displayed."""
107 """Whether this LoginHandler is needed - and therefore whether the login page should be displayed."""
100 return bool(cls.password_from_settings(settings))
108 return bool(cls.password_from_settings(settings))
101
109
General Comments 0
You need to be logged in to leave comments. Login now