##// END OF EJS Templates
login: removed log_session model, and replaced it with two lines of code....
marcink -
r1321:cb7ffeab default
parent child Browse files
Show More
@@ -1,357 +1,358 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2017 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 import collections
22 22 import datetime
23 23 import formencode
24 24 import logging
25 25 import urlparse
26 26
27 27 from pylons import url
28 28 from pyramid.httpexceptions import HTTPFound
29 29 from pyramid.view import view_config
30 30 from recaptcha.client.captcha import submit
31 31
32 32 from rhodecode.authentication.base import authenticate, HTTP_TYPE
33 33 from rhodecode.events import UserRegistered
34 34 from rhodecode.lib import helpers as h
35 35 from rhodecode.lib.auth import (
36 36 AuthUser, HasPermissionAnyDecorator, CSRFRequired)
37 37 from rhodecode.lib.base import get_ip_addr
38 38 from rhodecode.lib.exceptions import UserCreationError
39 39 from rhodecode.lib.utils2 import safe_str
40 40 from rhodecode.model.db import User
41 41 from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm
42 from rhodecode.model.login_session import LoginSession
43 42 from rhodecode.model.meta import Session
44 43 from rhodecode.model.settings import SettingsModel
45 44 from rhodecode.model.user import UserModel
46 45 from rhodecode.translation import _
47 46
48 47
49 48 log = logging.getLogger(__name__)
50 49
51 50 CaptchaData = collections.namedtuple(
52 51 'CaptchaData', 'active, private_key, public_key')
53 52
54 53
55 54 def _store_user_in_session(session, username, remember=False):
56 55 user = User.get_by_username(username, case_insensitive=True)
57 56 auth_user = AuthUser(user.user_id)
58 57 auth_user.set_authenticated()
59 58 cs = auth_user.get_cookie_store()
60 59 session['rhodecode_user'] = cs
61 60 user.update_lastlogin()
62 61 Session().commit()
63 62
64 63 # If they want to be remembered, update the cookie
65 64 if remember:
66 65 _year = (datetime.datetime.now() +
67 66 datetime.timedelta(seconds=60 * 60 * 24 * 365))
68 67 session._set_cookie_expires(_year)
69 68
70 69 session.save()
71 70
72 71 safe_cs = cs.copy()
73 72 safe_cs['password'] = '****'
74 73 log.info('user %s is now authenticated and stored in '
75 74 'session, session attrs %s', username, safe_cs)
76 75
77 76 # dumps session attrs back to cookie
78 77 session._update_cookie_out()
79 78 # we set new cookie
80 79 headers = None
81 80 if session.request['set_cookie']:
82 81 # send set-cookie headers back to response to update cookie
83 82 headers = [('Set-Cookie', session.request['cookie_out'])]
84 83 return headers
85 84
86 85
87 86 def get_came_from(request):
88 87 came_from = safe_str(request.GET.get('came_from', ''))
89 88 parsed = urlparse.urlparse(came_from)
90 89 allowed_schemes = ['http', 'https']
91 90 if parsed.scheme and parsed.scheme not in allowed_schemes:
92 91 log.error('Suspicious URL scheme detected %s for url %s' %
93 92 (parsed.scheme, parsed))
94 93 came_from = url('home')
95 94 elif parsed.netloc and request.host != parsed.netloc:
96 95 log.error('Suspicious NETLOC detected %s for url %s server url '
97 96 'is: %s' % (parsed.netloc, parsed, request.host))
98 97 came_from = url('home')
99 98 elif any(bad_str in parsed.path for bad_str in ('\r', '\n')):
100 99 log.error('Header injection detected `%s` for url %s server url ' %
101 100 (parsed.path, parsed))
102 101 came_from = url('home')
103 102
104 103 return came_from or url('home')
105 104
106 105
107 106 class LoginView(object):
108 107
109 108 def __init__(self, context, request):
110 109 self.request = request
111 110 self.context = context
112 111 self.session = request.session
113 112 self._rhodecode_user = request.user
114 113
115 114 def _get_template_context(self):
116 115 return {
117 116 'came_from': get_came_from(self.request),
118 117 'defaults': {},
119 118 'errors': {},
120 119 }
121 120
122 121 def _get_captcha_data(self):
123 122 settings = SettingsModel().get_all_settings()
124 123 private_key = settings.get('rhodecode_captcha_private_key')
125 124 public_key = settings.get('rhodecode_captcha_public_key')
126 125 active = bool(private_key)
127 126 return CaptchaData(
128 127 active=active, private_key=private_key, public_key=public_key)
129 128
130 129 @view_config(
131 130 route_name='login', request_method='GET',
132 131 renderer='rhodecode:templates/login.mako')
133 132 def login(self):
134 133 came_from = get_came_from(self.request)
135 134 user = self.request.user
136 135
137 136 # redirect if already logged in
138 137 if user.is_authenticated and not user.is_default and user.ip_allowed:
139 138 raise HTTPFound(came_from)
140 139
141 140 # check if we use headers plugin, and try to login using it.
142 141 try:
143 142 log.debug('Running PRE-AUTH for headers based authentication')
144 143 auth_info = authenticate(
145 144 '', '', self.request.environ, HTTP_TYPE, skip_missing=True)
146 145 if auth_info:
147 146 headers = _store_user_in_session(
148 147 self.session, auth_info.get('username'))
149 148 raise HTTPFound(came_from, headers=headers)
150 149 except UserCreationError as e:
151 150 log.error(e)
152 151 self.session.flash(e, queue='error')
153 152
154 153 return self._get_template_context()
155 154
156 155 @view_config(
157 156 route_name='login', request_method='POST',
158 157 renderer='rhodecode:templates/login.mako')
159 158 def login_post(self):
160 159 came_from = get_came_from(self.request)
161 session = self.request.session
160
162 161 login_form = LoginForm()()
163 162
164 163 try:
165 session.invalidate()
164 self.session.invalidate()
166 165 form_result = login_form.to_python(self.request.params)
167 166 # form checks for username/password, now we're authenticated
168 167 headers = _store_user_in_session(
169 168 self.session,
170 169 username=form_result['username'],
171 170 remember=form_result['remember'])
172 171 log.debug('Redirecting to "%s" after login.', came_from)
173 172 raise HTTPFound(came_from, headers=headers)
174 173 except formencode.Invalid as errors:
175 174 defaults = errors.value
176 175 # remove password from filling in form again
177 176 defaults.pop('password', None)
178 177 render_ctx = self._get_template_context()
179 178 render_ctx.update({
180 179 'errors': errors.error_dict,
181 180 'defaults': defaults,
182 181 })
183 182 return render_ctx
184 183
185 184 except UserCreationError as e:
186 185 # headers auth or other auth functions that create users on
187 186 # the fly can throw this exception signaling that there's issue
188 187 # with user creation, explanation should be provided in
189 188 # Exception itself
190 session.flash(e, queue='error')
189 self.session.flash(e, queue='error')
191 190 return self._get_template_context()
192 191
193 192 @CSRFRequired()
194 193 @view_config(route_name='logout', request_method='POST')
195 194 def logout(self):
196 LoginSession().destroy_user_session()
195 user = self.request.user
196 log.info('Deleting session for user: `%s`', user)
197 self.session.delete()
197 198 return HTTPFound(url('home'))
198 199
199 200 @HasPermissionAnyDecorator(
200 201 'hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')
201 202 @view_config(
202 203 route_name='register', request_method='GET',
203 204 renderer='rhodecode:templates/register.mako',)
204 205 def register(self, defaults=None, errors=None):
205 206 defaults = defaults or {}
206 207 errors = errors or {}
207 208
208 209 settings = SettingsModel().get_all_settings()
209 210 register_message = settings.get('rhodecode_register_message') or ''
210 211 captcha = self._get_captcha_data()
211 212 auto_active = 'hg.register.auto_activate' in User.get_default_user()\
212 213 .AuthUser.permissions['global']
213 214
214 215 render_ctx = self._get_template_context()
215 216 render_ctx.update({
216 217 'defaults': defaults,
217 218 'errors': errors,
218 219 'auto_active': auto_active,
219 220 'captcha_active': captcha.active,
220 221 'captcha_public_key': captcha.public_key,
221 222 'register_message': register_message,
222 223 })
223 224 return render_ctx
224 225
225 226 @HasPermissionAnyDecorator(
226 227 'hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')
227 228 @view_config(
228 229 route_name='register', request_method='POST',
229 230 renderer='rhodecode:templates/register.mako')
230 231 def register_post(self):
231 232 captcha = self._get_captcha_data()
232 233 auto_active = 'hg.register.auto_activate' in User.get_default_user()\
233 234 .AuthUser.permissions['global']
234 235
235 236 register_form = RegisterForm()()
236 237 try:
237 238 form_result = register_form.to_python(self.request.params)
238 239 form_result['active'] = auto_active
239 240
240 241 if captcha.active:
241 242 response = submit(
242 243 self.request.params.get('recaptcha_challenge_field'),
243 244 self.request.params.get('recaptcha_response_field'),
244 245 private_key=captcha.private_key,
245 246 remoteip=get_ip_addr(self.request.environ))
246 247 if not response.is_valid:
247 248 _value = form_result
248 249 _msg = _('Bad captcha')
249 250 error_dict = {'recaptcha_field': _msg}
250 251 raise formencode.Invalid(_msg, _value, None,
251 252 error_dict=error_dict)
252 253
253 254 new_user = UserModel().create_registration(form_result)
254 255 event = UserRegistered(user=new_user, session=self.session)
255 256 self.request.registry.notify(event)
256 257 self.session.flash(
257 258 _('You have successfully registered with RhodeCode'),
258 259 queue='success')
259 260 Session().commit()
260 261
261 262 redirect_ro = self.request.route_path('login')
262 263 raise HTTPFound(redirect_ro)
263 264
264 265 except formencode.Invalid as errors:
265 266 errors.value.pop('password', None)
266 267 errors.value.pop('password_confirmation', None)
267 268 return self.register(
268 269 defaults=errors.value, errors=errors.error_dict)
269 270
270 271 except UserCreationError as e:
271 272 # container auth or other auth functions that create users on
272 273 # the fly can throw this exception signaling that there's issue
273 274 # with user creation, explanation should be provided in
274 275 # Exception itself
275 276 self.session.flash(e, queue='error')
276 277 return self.register()
277 278
278 279 @view_config(
279 280 route_name='reset_password', request_method=('GET', 'POST'),
280 281 renderer='rhodecode:templates/password_reset.mako')
281 282 def password_reset(self):
282 283 captcha = self._get_captcha_data()
283 284
284 285 render_ctx = {
285 286 'captcha_active': captcha.active,
286 287 'captcha_public_key': captcha.public_key,
287 288 'defaults': {},
288 289 'errors': {},
289 290 }
290 291
291 292 if self.request.POST:
292 293 password_reset_form = PasswordResetForm()()
293 294 try:
294 295 form_result = password_reset_form.to_python(
295 296 self.request.params)
296 297 if h.HasPermissionAny('hg.password_reset.disabled')():
297 298 log.error('Failed attempt to reset password for %s.', form_result['email'] )
298 299 self.session.flash(
299 300 _('Password reset has been disabled.'),
300 301 queue='error')
301 302 return HTTPFound(self.request.route_path('reset_password'))
302 303 if captcha.active:
303 304 response = submit(
304 305 self.request.params.get('recaptcha_challenge_field'),
305 306 self.request.params.get('recaptcha_response_field'),
306 307 private_key=captcha.private_key,
307 308 remoteip=get_ip_addr(self.request.environ))
308 309 if not response.is_valid:
309 310 _value = form_result
310 311 _msg = _('Bad captcha')
311 312 error_dict = {'recaptcha_field': _msg}
312 313 raise formencode.Invalid(_msg, _value, None,
313 314 error_dict=error_dict)
314 315
315 316 # Generate reset URL and send mail.
316 317 user_email = form_result['email']
317 318 user = User.get_by_email(user_email)
318 319 password_reset_url = self.request.route_url(
319 320 'reset_password_confirmation',
320 321 _query={'key': user.api_key})
321 322 UserModel().reset_password_link(
322 323 form_result, password_reset_url)
323 324
324 325 # Display success message and redirect.
325 326 self.session.flash(
326 327 _('Your password reset link was sent'),
327 328 queue='success')
328 329 return HTTPFound(self.request.route_path('login'))
329 330
330 331 except formencode.Invalid as errors:
331 332 render_ctx.update({
332 333 'defaults': errors.value,
333 334 'errors': errors.error_dict,
334 335 })
335 336
336 337 return render_ctx
337 338
338 339 @view_config(route_name='reset_password_confirmation',
339 340 request_method='GET')
340 341 def password_reset_confirmation(self):
341 342 if self.request.GET and self.request.GET.get('key'):
342 343 try:
343 344 user = User.get_by_auth_token(self.request.GET.get('key'))
344 345 password_reset_url = self.request.route_url(
345 346 'reset_password_confirmation',
346 347 _query={'key': user.api_key})
347 348 data = {'email': user.email}
348 349 UserModel().reset_password(data, password_reset_url)
349 350 self.session.flash(
350 351 _('Your password reset was successful, '
351 352 'a new password has been sent to your email'),
352 353 queue='success')
353 354 except Exception as e:
354 355 log.error(e)
355 356 return HTTPFound(self.request.route_path('reset_password'))
356 357
357 358 return HTTPFound(self.request.route_path('login'))
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now