##// END OF EJS Templates
security fix, inspired by django security...
marcink -
r2678:04d2bcfb beta
parent child Browse files
Show More
@@ -1,183 +1,197 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.controllers.login
4 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 6 Login controller for rhodeocode
7 7
8 8 :created_on: Apr 22, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25
26 26 import logging
27 27 import formencode
28 28 import datetime
29 import urlparse
29 30
30 31 from formencode import htmlfill
31 32 from webob.exc import HTTPFound
32 33 from pylons.i18n.translation import _
33 34 from pylons.controllers.util import abort, redirect
34 35 from pylons import request, response, session, tmpl_context as c, url
35 36
36 37 import rhodecode.lib.helpers as h
37 38 from rhodecode.lib.auth import AuthUser, HasPermissionAnyDecorator
38 39 from rhodecode.lib.base import BaseController, render
39 40 from rhodecode.model.db import User
40 41 from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm
41 42 from rhodecode.model.user import UserModel
42 43 from rhodecode.model.meta import Session
43 44
44 45
45 46
46 47 log = logging.getLogger(__name__)
47 48
48 49
49 50 class LoginController(BaseController):
50 51
51 52 def __before__(self):
52 53 super(LoginController, self).__before__()
53 54
54 55 def index(self):
55 56 # redirect if already logged in
56 57 c.came_from = request.GET.get('came_from', None)
57 58
58 59 if self.rhodecode_user.is_authenticated \
59 60 and self.rhodecode_user.username != 'default':
60 61
61 62 return redirect(url('home'))
62 63
63 64 if request.POST:
64 65 # import Login Form validator class
65 66 login_form = LoginForm()
66 67 try:
67 68 session.invalidate()
68 69 c.form_result = login_form.to_python(dict(request.POST))
69 70 # form checks for username/password, now we're authenticated
70 71 username = c.form_result['username']
71 72 user = User.get_by_username(username, case_insensitive=True)
72 73 auth_user = AuthUser(user.user_id)
73 74 auth_user.set_authenticated()
74 75 cs = auth_user.get_cookie_store()
75 76 session['rhodecode_user'] = cs
76 77 user.update_lastlogin()
77 78 Session().commit()
78 79
79 80 # If they want to be remembered, update the cookie
80 81 if c.form_result['remember'] is not False:
81 82 _year = (datetime.datetime.now() +
82 83 datetime.timedelta(seconds=60 * 60 * 24 * 365))
83 84 session._set_cookie_expires(_year)
84 85
85 86 session.save()
86 87
87 88 log.info('user %s is now authenticated and stored in '
88 89 'session, session attrs %s' % (username, cs))
89 90
90 91 # dumps session attrs back to cookie
91 92 session._update_cookie_out()
92 93
93 94 # we set new cookie
94 95 headers = None
95 96 if session.request['set_cookie']:
96 97 # send set-cookie headers back to response to update cookie
97 98 headers = [('Set-Cookie', session.request['cookie_out'])]
98 99
100 allowed_schemes = ['http', 'https', 'ftp']
101 parsed = urlparse.urlparse(c.came_from)
102 server_parsed = urlparse.urlparse(url.current())
103
104 if parsed.scheme and parsed.scheme not in allowed_schemes:
105 log.error('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')
99 113 if c.came_from:
100 114 raise HTTPFound(location=c.came_from, headers=headers)
101 115 else:
102 116 raise HTTPFound(location=url('home'), headers=headers)
103 117
104 118 except formencode.Invalid, errors:
105 119 return htmlfill.render(
106 120 render('/login.html'),
107 121 defaults=errors.value,
108 122 errors=errors.error_dict or {},
109 123 prefix_error=False,
110 124 encoding="UTF-8")
111 125
112 126 return render('/login.html')
113 127
114 128 @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate',
115 129 'hg.register.manual_activate')
116 130 def register(self):
117 131 c.auto_active = False
118 132 for perm in User.get_by_username('default').user_perms:
119 133 if perm.permission.permission_name == 'hg.register.auto_activate':
120 134 c.auto_active = True
121 135 break
122 136
123 137 if request.POST:
124 138
125 139 register_form = RegisterForm()()
126 140 try:
127 141 form_result = register_form.to_python(dict(request.POST))
128 142 form_result['active'] = c.auto_active
129 143 UserModel().create_registration(form_result)
130 144 h.flash(_('You have successfully registered into rhodecode'),
131 145 category='success')
132 146 Session().commit()
133 147 return redirect(url('login_home'))
134 148
135 149 except formencode.Invalid, errors:
136 150 return htmlfill.render(
137 151 render('/register.html'),
138 152 defaults=errors.value,
139 153 errors=errors.error_dict or {},
140 154 prefix_error=False,
141 155 encoding="UTF-8")
142 156
143 157 return render('/register.html')
144 158
145 159 def password_reset(self):
146 160 if request.POST:
147 161 password_reset_form = PasswordResetForm()()
148 162 try:
149 163 form_result = password_reset_form.to_python(dict(request.POST))
150 164 UserModel().reset_password_link(form_result)
151 165 h.flash(_('Your password reset link was sent'),
152 166 category='success')
153 167 return redirect(url('login_home'))
154 168
155 169 except formencode.Invalid, errors:
156 170 return htmlfill.render(
157 171 render('/password_reset.html'),
158 172 defaults=errors.value,
159 173 errors=errors.error_dict or {},
160 174 prefix_error=False,
161 175 encoding="UTF-8")
162 176
163 177 return render('/password_reset.html')
164 178
165 179 def password_reset_confirmation(self):
166 180 if request.GET and request.GET.get('key'):
167 181 try:
168 182 user = User.get_by_api_key(request.GET.get('key'))
169 183 data = dict(email=user.email)
170 184 UserModel().reset_password(data)
171 185 h.flash(_('Your password reset was successful, '
172 186 'new password has been sent to your email'),
173 187 category='success')
174 188 except Exception, e:
175 189 log.error(e)
176 190 return redirect(url('reset_password'))
177 191
178 192 return redirect(url('login_home'))
179 193
180 194 def logout(self):
181 195 session.delete()
182 196 log.info('Logging out and deleting session for user')
183 197 redirect(url('home'))
General Comments 0
You need to be logged in to leave comments. Login now