comparison rhodecode/controllers/login.py @ 4116:ffd45b185016 rhodecode-2.2.5-gpl

Imported some of the GPLv3'd changes from RhodeCode v2.2.5. This imports changes between changesets 21af6c4eab3d and 6177597791c2 in RhodeCode's original repository, including only changes to Python files and HTML. RhodeCode clearly licensed its changes to these files under GPLv3 in their /LICENSE file, which states the following: The Python code and integrated HTML are licensed under the GPLv3 license. (See: https://code.rhodecode.com/rhodecode/files/v2.2.5/LICENSE or http://web.archive.org/web/20140512193334/https://code.rhodecode.com/rhodecode/files/f3b123159901f15426d18e3dc395e8369f70ebe0/LICENSE for an online copy of that LICENSE file) Conservancy reviewed these changes and confirmed that they can be licensed as a whole to the Kallithea project under GPLv3-only. While some of the contents committed herein are clearly licensed GPLv3-or-later, on the whole we must assume the are GPLv3-only, since the statement above from RhodeCode indicates that they intend GPLv3-only as their license, per GPLv3ยง14 and other relevant sections of GPLv3.
author Bradley M. Kuhn <bkuhn@sfconservancy.org>
date Wed, 02 Jul 2014 19:03:13 -0400
parents b59568e929ef
children 7e5f8c12a3fc
comparison
equal deleted inserted replaced
4115:8b7294a804a0 4116:ffd45b185016
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 """
3 rhodecode.controllers.login
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
6 Login controller for rhodeocode
7
8 :created_on: Apr 22, 2010
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
12 """
13 # This program is free software: you can redistribute it and/or modify 2 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by 3 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or 4 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version. 5 # (at your option) any later version.
17 # 6 #
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details. 10 # GNU General Public License for more details.
22 # 11 #
23 # You should have received a copy of the GNU General Public License 12 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>. 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
15 rhodecode.controllers.login
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
17
18 Login controller for rhodeocode
19
20 :created_on: Apr 22, 2010
21 :author: marcink
22 :copyright: (c) 2013 RhodeCode GmbH.
23 :license: GPLv3, see LICENSE for more details.
24 """
25
25 26
26 import logging 27 import logging
27 import formencode 28 import formencode
28 import datetime 29 import datetime
29 import urlparse 30 import urlparse
30 31
31 from formencode import htmlfill 32 from formencode import htmlfill
32 from webob.exc import HTTPFound 33 from webob.exc import HTTPFound
33 from pylons.i18n.translation import _ 34 from pylons.i18n.translation import _
34 from pylons.controllers.util import abort, redirect 35 from pylons.controllers.util import redirect
35 from pylons import request, response, session, tmpl_context as c, url 36 from pylons import request, session, tmpl_context as c, url
36 37
37 import rhodecode.lib.helpers as h 38 import rhodecode.lib.helpers as h
38 from rhodecode.lib.auth import AuthUser, HasPermissionAnyDecorator 39 from rhodecode.lib.auth import AuthUser, HasPermissionAnyDecorator
40 from rhodecode.lib.auth_modules import importplugin
39 from rhodecode.lib.base import BaseController, render 41 from rhodecode.lib.base import BaseController, render
40 from rhodecode.lib.exceptions import UserCreationError 42 from rhodecode.lib.exceptions import UserCreationError
41 from rhodecode.model.db import User 43 from rhodecode.model.db import User, RhodeCodeSetting
42 from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm 44 from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm
43 from rhodecode.model.user import UserModel 45 from rhodecode.model.user import UserModel
44 from rhodecode.model.meta import Session 46 from rhodecode.model.meta import Session
45 47
46 48
50 class LoginController(BaseController): 52 class LoginController(BaseController):
51 53
52 def __before__(self): 54 def __before__(self):
53 super(LoginController, self).__before__() 55 super(LoginController, self).__before__()
54 56
57 def _store_user_in_session(self, username, remember=False):
58 user = User.get_by_username(username, case_insensitive=True)
59 auth_user = AuthUser(user.user_id)
60 auth_user.set_authenticated()
61 cs = auth_user.get_cookie_store()
62 session['rhodecode_user'] = cs
63 user.update_lastlogin()
64 Session().commit()
65
66 # If they want to be remembered, update the cookie
67 if remember:
68 _year = (datetime.datetime.now() +
69 datetime.timedelta(seconds=60 * 60 * 24 * 365))
70 session._set_cookie_expires(_year)
71
72 session.save()
73
74 log.info('user %s is now authenticated and stored in '
75 'session, session attrs %s' % (username, cs))
76
77 # dumps session attrs back to cookie
78 session._update_cookie_out()
79 # we set new cookie
80 headers = None
81 if session.request['set_cookie']:
82 # send set-cookie headers back to response to update cookie
83 headers = [('Set-Cookie', session.request['cookie_out'])]
84 return headers
85
86 def _validate_came_from(self, came_from):
87 if not came_from:
88 return came_from
89
90 parsed = urlparse.urlparse(came_from)
91 server_parsed = urlparse.urlparse(url.current())
92 allowed_schemes = ['http', 'https']
93 if parsed.scheme and parsed.scheme not in allowed_schemes:
94 log.error('Suspicious URL scheme detected %s for url %s' %
95 (parsed.scheme, parsed))
96 came_from = url('home')
97 elif server_parsed.netloc != parsed.netloc:
98 log.error('Suspicious NETLOC detected %s for url %s server url '
99 'is: %s' % (parsed.netloc, parsed, server_parsed))
100 came_from = url('home')
101 return came_from
102
55 def index(self): 103 def index(self):
104 _default_came_from = url('home')
105 came_from = self._validate_came_from(request.GET.get('came_from'))
106 c.came_from = came_from or _default_came_from
107
108 not_default = self.rhodecode_user.username != User.DEFAULT_USER
109 ip_allowed = self.rhodecode_user.ip_allowed
110
56 # redirect if already logged in 111 # redirect if already logged in
57 c.came_from = request.GET.get('came_from')
58 not_default = self.rhodecode_user.username != 'default'
59 ip_allowed = self.rhodecode_user.ip_allowed
60 if self.rhodecode_user.is_authenticated and not_default and ip_allowed: 112 if self.rhodecode_user.is_authenticated and not_default and ip_allowed:
61 return redirect(url('home')) 113 raise HTTPFound(location=c.came_from)
62 114
63 if request.POST: 115 if request.POST:
64 # import Login Form validator class 116 # import Login Form validator class
65 login_form = LoginForm() 117 login_form = LoginForm()
66 try: 118 try:
67 session.invalidate() 119 session.invalidate()
68 c.form_result = login_form.to_python(dict(request.POST)) 120 c.form_result = login_form.to_python(dict(request.POST))
69 # form checks for username/password, now we're authenticated 121 # form checks for username/password, now we're authenticated
70 username = c.form_result['username'] 122 headers = self._store_user_in_session(
71 user = User.get_by_username(username, case_insensitive=True) 123 username=c.form_result['username'],
72 auth_user = AuthUser(user.user_id) 124 remember=c.form_result['remember'])
73 auth_user.set_authenticated() 125 raise HTTPFound(location=c.came_from, headers=headers)
74 cs = auth_user.get_cookie_store()
75 session['rhodecode_user'] = cs
76 user.update_lastlogin()
77 Session().commit()
78
79 # If they want to be remembered, update the cookie
80 if c.form_result['remember']:
81 _year = (datetime.datetime.now() +
82 datetime.timedelta(seconds=60 * 60 * 24 * 365))
83 session._set_cookie_expires(_year)
84
85 session.save()
86
87 log.info('user %s is now authenticated and stored in '
88 'session, session attrs %s' % (username, cs))
89
90 # dumps session attrs back to cookie
91 session._update_cookie_out()
92
93 # we set new cookie
94 headers = None
95 if session.request['set_cookie']:
96 # send set-cookie headers back to response to update cookie
97 headers = [('Set-Cookie', session.request['cookie_out'])]
98
99 allowed_schemes = ['http', 'https']
100 if c.came_from:
101 parsed = urlparse.urlparse(c.came_from)
102 server_parsed = urlparse.urlparse(url.current())
103 if parsed.scheme and parsed.scheme not in allowed_schemes:
104 log.error(
105 'Suspicious URL scheme detected %s for url %s' %
106 (parsed.scheme, parsed))
107 c.came_from = url('home')
108 elif server_parsed.netloc != parsed.netloc:
109 log.error('Suspicious NETLOC detected %s for url %s'
110 'server url is: %s' %
111 (parsed.netloc, parsed, server_parsed))
112 c.came_from = url('home')
113 raise HTTPFound(location=c.came_from, headers=headers)
114 else:
115 raise HTTPFound(location=url('home'), headers=headers)
116
117 except formencode.Invalid, errors: 126 except formencode.Invalid, errors:
118 defaults = errors.value 127 defaults = errors.value
119 # remove password from filling in form again 128 # remove password from filling in form again
120 del defaults['password'] 129 del defaults['password']
121 return htmlfill.render( 130 return htmlfill.render(
129 # the fly can throw this exception signaling that there's issue 138 # the fly can throw this exception signaling that there's issue
130 # with user creation, explanation should be provided in 139 # with user creation, explanation should be provided in
131 # Exception itself 140 # Exception itself
132 h.flash(e, 'error') 141 h.flash(e, 'error')
133 142
143 # check if we use container plugin, and try to login using it.
144 auth_plugins = RhodeCodeSetting.get_auth_plugins()
145 if any((importplugin(name).is_container_auth for name in auth_plugins)):
146 from rhodecode.lib import auth_modules
147 try:
148 auth_info = auth_modules.authenticate('', '', request.environ)
149 except UserCreationError, e:
150 log.error(e)
151 h.flash(e, 'error')
152 # render login, with flash message about limit
153 return render('/login.html')
154
155 if auth_info:
156 headers = self._store_user_in_session(auth_info.get('username'))
157 raise HTTPFound(location=c.came_from, headers=headers)
134 return render('/login.html') 158 return render('/login.html')
135 159
136 @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate', 160 @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate',
137 'hg.register.manual_activate') 161 'hg.register.manual_activate')
138 def register(self): 162 def register(self):
139 c.auto_active = 'hg.register.auto_activate' in User.get_default_user()\ 163 c.auto_active = 'hg.register.auto_activate' in User.get_default_user()\
140 .AuthUser.permissions['global'] 164 .AuthUser.permissions['global']
141 165
166 settings = RhodeCodeSetting.get_app_settings()
167 captcha_private_key = settings.get('rhodecode_captcha_private_key')
168 c.captcha_active = bool(captcha_private_key)
169 c.captcha_public_key = settings.get('rhodecode_captcha_public_key')
170
142 if request.POST: 171 if request.POST:
143 register_form = RegisterForm()() 172 register_form = RegisterForm()()
144 try: 173 try:
145 form_result = register_form.to_python(dict(request.POST)) 174 form_result = register_form.to_python(dict(request.POST))
146 form_result['active'] = c.auto_active 175 form_result['active'] = c.auto_active
176
177 if c.captcha_active:
178 from rhodecode.lib.recaptcha import submit
179 response = submit(request.POST.get('recaptcha_challenge_field'),
180 request.POST.get('recaptcha_response_field'),
181 private_key=captcha_private_key,
182 remoteip=self.ip_addr)
183 if c.captcha_active and not response.is_valid:
184 _value = form_result
185 _msg = _('bad captcha')
186 error_dict = {'recaptcha_field': _msg}
187 raise formencode.Invalid(_msg, _value, None,
188 error_dict=error_dict)
189
147 UserModel().create_registration(form_result) 190 UserModel().create_registration(form_result)
148 h.flash(_('You have successfully registered into RhodeCode'), 191 h.flash(_('You have successfully registered into RhodeCode'),
149 category='success') 192 category='success')
150 Session().commit() 193 Session().commit()
151 return redirect(url('login_home')) 194 return redirect(url('login_home'))
152 195
153 except formencode.Invalid, errors: 196 except formencode.Invalid, errors:
154 return htmlfill.render( 197 return htmlfill.render(
165 h.flash(e, 'error') 208 h.flash(e, 'error')
166 209
167 return render('/register.html') 210 return render('/register.html')
168 211
169 def password_reset(self): 212 def password_reset(self):
213 settings = RhodeCodeSetting.get_app_settings()
214 captcha_private_key = settings.get('rhodecode_captcha_private_key')
215 c.captcha_active = bool(captcha_private_key)
216 c.captcha_public_key = settings.get('rhodecode_captcha_public_key')
217
170 if request.POST: 218 if request.POST:
171 password_reset_form = PasswordResetForm()() 219 password_reset_form = PasswordResetForm()()
172 try: 220 try:
173 form_result = password_reset_form.to_python(dict(request.POST)) 221 form_result = password_reset_form.to_python(dict(request.POST))
222 if c.captcha_active:
223 from rhodecode.lib.recaptcha import submit
224 response = submit(request.POST.get('recaptcha_challenge_field'),
225 request.POST.get('recaptcha_response_field'),
226 private_key=captcha_private_key,
227 remoteip=self.ip_addr)
228 if c.captcha_active and not response.is_valid:
229 _value = form_result
230 _msg = _('bad captcha')
231 error_dict = {'recaptcha_field': _msg}
232 raise formencode.Invalid(_msg, _value, None,
233 error_dict=error_dict)
174 UserModel().reset_password_link(form_result) 234 UserModel().reset_password_link(form_result)
175 h.flash(_('Your password reset link was sent'), 235 h.flash(_('Your password reset link was sent'),
176 category='success') 236 category='success')
177 return redirect(url('login_home')) 237 return redirect(url('login_home'))
178 238