##// END OF EJS Templates
login: Move method to store user in session out of login controller....
johbo -
r28:48f65d03 default
parent child Browse files
Show More
@@ -1,290 +1,291 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 """
22 22 Login controller for rhodeocode
23 23 """
24 24
25 25 import datetime
26 26 import formencode
27 27 import logging
28 28 import urlparse
29 29 import uuid
30 30
31 31 from formencode import htmlfill
32 32 from webob.exc import HTTPFound
33 33 from pylons.i18n.translation import _
34 34 from pylons.controllers.util import redirect
35 35 from pylons import request, session, tmpl_context as c, url
36 36 from recaptcha.client.captcha import submit
37 37
38 38 import rhodecode.lib.helpers as h
39 39 from rhodecode.lib.auth import (
40 40 AuthUser, HasPermissionAnyDecorator, CSRFRequired)
41 41 from rhodecode.authentication.base import loadplugin
42 42 from rhodecode.lib.base import BaseController, render
43 43 from rhodecode.lib.exceptions import UserCreationError
44 44 from rhodecode.lib.utils2 import safe_str
45 45 from rhodecode.model.db import User
46 46 from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm
47 47 from rhodecode.model.login_session import LoginSession
48 48 from rhodecode.model.meta import Session
49 49 from rhodecode.model.settings import SettingsModel
50 50 from rhodecode.model.user import UserModel
51 51
52 52 log = logging.getLogger(__name__)
53 53
54 54
55 def _store_user_in_session(username, remember=False):
56 user = User.get_by_username(username, case_insensitive=True)
57 auth_user = AuthUser(user.user_id)
58 auth_user.set_authenticated()
59 cs = auth_user.get_cookie_store()
60 session['rhodecode_user'] = cs
61 user.update_lastlogin()
62 Session().commit()
63
64 # If they want to be remembered, update the cookie
65 if remember:
66 _year = (datetime.datetime.now() +
67 datetime.timedelta(seconds=60 * 60 * 24 * 365))
68 session._set_cookie_expires(_year)
69
70 session.save()
71
72 log.info('user %s is now authenticated and stored in '
73 'session, session attrs %s', username, cs)
74
75 # dumps session attrs back to cookie
76 session._update_cookie_out()
77 # we set new cookie
78 headers = None
79 if session.request['set_cookie']:
80 # send set-cookie headers back to response to update cookie
81 headers = [('Set-Cookie', session.request['cookie_out'])]
82 return headers
83
84
55 85 class LoginController(BaseController):
56 86
57 87 def __before__(self):
58 88 super(LoginController, self).__before__()
59 89
60 def _store_user_in_session(self, username, remember=False):
61 user = User.get_by_username(username, case_insensitive=True)
62 auth_user = AuthUser(user.user_id)
63 auth_user.set_authenticated()
64 cs = auth_user.get_cookie_store()
65 session['rhodecode_user'] = cs
66 user.update_lastlogin()
67 Session().commit()
68
69 # If they want to be remembered, update the cookie
70 if remember:
71 _year = (datetime.datetime.now() +
72 datetime.timedelta(seconds=60 * 60 * 24 * 365))
73 session._set_cookie_expires(_year)
74
75 session.save()
76
77 log.info('user %s is now authenticated and stored in '
78 'session, session attrs %s', username, cs)
79
80 # dumps session attrs back to cookie
81 session._update_cookie_out()
82 # we set new cookie
83 headers = None
84 if session.request['set_cookie']:
85 # send set-cookie headers back to response to update cookie
86 headers = [('Set-Cookie', session.request['cookie_out'])]
87 return headers
88
89 90 def _validate_came_from(self, came_from):
90 91 if not came_from:
91 92 return came_from
92 93
93 94 parsed = urlparse.urlparse(came_from)
94 95 server_parsed = urlparse.urlparse(url.current())
95 96 allowed_schemes = ['http', 'https']
96 97 if parsed.scheme and parsed.scheme not in allowed_schemes:
97 98 log.error('Suspicious URL scheme detected %s for url %s' %
98 99 (parsed.scheme, parsed))
99 100 came_from = url('home')
100 101 elif server_parsed.netloc != parsed.netloc:
101 102 log.error('Suspicious NETLOC detected %s for url %s server url '
102 103 'is: %s' % (parsed.netloc, parsed, server_parsed))
103 104 came_from = url('home')
104 105 if any(bad_str in parsed.path for bad_str in ('\r', '\n')):
105 106 log.error('Header injection detected `%s` for url %s server url ' %
106 107 (parsed.path, parsed))
107 108 came_from = url('home')
108 109 return came_from
109 110
110 111 def _redirect_to_origin(self, location, headers=None):
111 112 request.GET.pop('came_from', None)
112 113 raise HTTPFound(location=location, headers=headers)
113 114
114 115 def _set_came_from(self):
115 116 _default_came_from = url('home')
116 117 came_from = self._validate_came_from(
117 118 safe_str(request.GET.get('came_from', '')))
118 119 c.came_from = came_from or _default_came_from
119 120
120 121 def index(self):
121 122 self._set_came_from()
122 123
123 124 not_default = c.rhodecode_user.username != User.DEFAULT_USER
124 125 ip_allowed = c.rhodecode_user.ip_allowed
125 126
126 127 # redirect if already logged in
127 128 if c.rhodecode_user.is_authenticated and not_default and ip_allowed:
128 129 raise self._redirect_to_origin(location=c.came_from)
129 130
130 131 if request.POST:
131 132 # import Login Form validator class
132 133 login_form = LoginForm()()
133 134 try:
134 135 session.invalidate()
135 136 c.form_result = login_form.to_python(dict(request.POST))
136 137 # form checks for username/password, now we're authenticated
137 headers = self._store_user_in_session(
138 headers = _store_user_in_session(
138 139 username=c.form_result['username'],
139 140 remember=c.form_result['remember'])
140 141 raise self._redirect_to_origin(
141 142 location=c.came_from, headers=headers)
142 143 except formencode.Invalid as errors:
143 144 defaults = errors.value
144 145 # remove password from filling in form again
145 146 del defaults['password']
146 147 return htmlfill.render(
147 148 render('/login.html'),
148 149 defaults=errors.value,
149 150 errors=errors.error_dict or {},
150 151 prefix_error=False,
151 152 encoding="UTF-8",
152 153 force_defaults=False)
153 154 except UserCreationError as e:
154 155 # container auth or other auth functions that create users on
155 156 # the fly can throw this exception signaling that there's issue
156 157 # with user creation, explanation should be provided in
157 158 # Exception itself
158 159 h.flash(e, 'error')
159 160
160 161 # check if we use container plugin, and try to login using it.
161 162 from rhodecode.authentication.base import authenticate, HTTP_TYPE
162 163 try:
163 164 log.debug('Running PRE-AUTH for container based authentication')
164 165 auth_info = authenticate(
165 166 '', '', request.environ, HTTP_TYPE, skip_missing=True)
166 167 except UserCreationError as e:
167 168 log.error(e)
168 169 h.flash(e, 'error')
169 170 # render login, with flash message about limit
170 171 return render('/login.html')
171 172
172 173 if auth_info:
173 headers = self._store_user_in_session(auth_info.get('username'))
174 headers = _store_user_in_session(auth_info.get('username'))
174 175 raise self._redirect_to_origin(
175 176 location=c.came_from, headers=headers)
176 177 return render('/login.html')
177 178
178 179 @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate',
179 180 'hg.register.manual_activate')
180 181 def register(self):
181 182 c.auto_active = 'hg.register.auto_activate' in User.get_default_user()\
182 183 .AuthUser.permissions['global']
183 184
184 185 settings = SettingsModel().get_all_settings()
185 186 captcha_private_key = settings.get('rhodecode_captcha_private_key')
186 187 c.captcha_active = bool(captcha_private_key)
187 188 c.captcha_public_key = settings.get('rhodecode_captcha_public_key')
188 189 c.register_message = settings.get('rhodecode_register_message') or ''
189 190 c.form_data = {}
190 191
191 192 if request.POST:
192 193 register_form = RegisterForm()()
193 194 try:
194 195 form_result = register_form.to_python(dict(request.POST))
195 196 form_result['active'] = c.auto_active
196 197
197 198 if c.captcha_active:
198 199 response = submit(
199 200 request.POST.get('recaptcha_challenge_field'),
200 201 request.POST.get('recaptcha_response_field'),
201 202 private_key=captcha_private_key,
202 203 remoteip=self.ip_addr)
203 204 if c.captcha_active and not response.is_valid:
204 205 _value = form_result
205 206 _msg = _('bad captcha')
206 207 error_dict = {'recaptcha_field': _msg}
207 208 raise formencode.Invalid(_msg, _value, None,
208 209 error_dict=error_dict)
209 210
210 211 UserModel().create_registration(form_result)
211 212 h.flash(_('You have successfully registered with RhodeCode'),
212 213 category='success')
213 214 Session().commit()
214 215 return redirect(url('login_home'))
215 216
216 217 except formencode.Invalid as errors:
217 218 return htmlfill.render(
218 219 render('/register.html'),
219 220 defaults=errors.value,
220 221 errors=errors.error_dict or {},
221 222 prefix_error=False,
222 223 encoding="UTF-8",
223 224 force_defaults=False)
224 225 except UserCreationError as e:
225 226 # container auth or other auth functions that create users on
226 227 # the fly can throw this exception signaling that there's issue
227 228 # with user creation, explanation should be provided in
228 229 # Exception itself
229 230 h.flash(e, 'error')
230 231
231 232 return render('/register.html')
232 233
233 234 def password_reset(self):
234 235 settings = SettingsModel().get_all_settings()
235 236 captcha_private_key = settings.get('rhodecode_captcha_private_key')
236 237 c.captcha_active = bool(captcha_private_key)
237 238 c.captcha_public_key = settings.get('rhodecode_captcha_public_key')
238 239
239 240 if request.POST:
240 241 password_reset_form = PasswordResetForm()()
241 242 try:
242 243 form_result = password_reset_form.to_python(dict(request.POST))
243 244 if c.captcha_active:
244 245 response = submit(
245 246 request.POST.get('recaptcha_challenge_field'),
246 247 request.POST.get('recaptcha_response_field'),
247 248 private_key=captcha_private_key,
248 249 remoteip=self.ip_addr)
249 250 if c.captcha_active and not response.is_valid:
250 251 _value = form_result
251 252 _msg = _('bad captcha')
252 253 error_dict = {'recaptcha_field': _msg}
253 254 raise formencode.Invalid(_msg, _value, None,
254 255 error_dict=error_dict)
255 256 UserModel().reset_password_link(form_result)
256 257 h.flash(_('Your password reset link was sent'),
257 258 category='success')
258 259 return redirect(url('login_home'))
259 260
260 261 except formencode.Invalid as errors:
261 262 return htmlfill.render(
262 263 render('/password_reset.html'),
263 264 defaults=errors.value,
264 265 errors=errors.error_dict or {},
265 266 prefix_error=False,
266 267 encoding="UTF-8",
267 268 force_defaults=False)
268 269
269 270 return render('/password_reset.html')
270 271
271 272 def password_reset_confirmation(self):
272 273 if request.GET and request.GET.get('key'):
273 274 try:
274 275 user = User.get_by_auth_token(request.GET.get('key'))
275 276 data = {'email': user.email}
276 277 UserModel().reset_password(data)
277 278 h.flash(_(
278 279 'Your password reset was successful, '
279 280 'a new password has been sent to your email'),
280 281 category='success')
281 282 except Exception as e:
282 283 log.error(e)
283 284 return redirect(url('reset_password'))
284 285
285 286 return redirect(url('login_home'))
286 287
287 288 @CSRFRequired()
288 289 def logout(self):
289 290 LoginSession().destroy_user_session()
290 291 return redirect(url('home'))
General Comments 0
You need to be logged in to leave comments. Login now