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