Show More
@@ -1,197 +1,196 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | # -*- coding: utf-8 -*- | |
2 | """ |
|
2 | """ | |
3 | rhodecode.controllers.login |
|
3 | rhodecode.controllers.login | |
4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
5 |
|
5 | |||
6 | Login controller for rhodeocode |
|
6 | Login controller for rhodeocode | |
7 |
|
7 | |||
8 | :created_on: Apr 22, 2010 |
|
8 | :created_on: Apr 22, 2010 | |
9 | :author: marcink |
|
9 | :author: marcink | |
10 | :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com> |
|
10 | :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com> | |
11 | :license: GPLv3, see COPYING for more details. |
|
11 | :license: GPLv3, see COPYING for more details. | |
12 | """ |
|
12 | """ | |
13 | # This program is free software: you can redistribute it and/or modify |
|
13 | # 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 |
|
14 | # 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 |
|
15 | # the Free Software Foundation, either version 3 of the License, or | |
16 | # (at your option) any later version. |
|
16 | # (at your option) any later version. | |
17 | # |
|
17 | # | |
18 | # This program is distributed in the hope that it will be useful, |
|
18 | # This program is distributed in the hope that it will be useful, | |
19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 | # GNU General Public License for more details. |
|
21 | # GNU General Public License for more details. | |
22 | # |
|
22 | # | |
23 | # You should have received a copy of the GNU General Public License |
|
23 | # 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/>. |
|
24 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
25 |
|
25 | |||
26 | import logging |
|
26 | import logging | |
27 | import formencode |
|
27 | import formencode | |
28 | import datetime |
|
28 | import datetime | |
29 | import urlparse |
|
29 | import urlparse | |
30 |
|
30 | |||
31 | from formencode import htmlfill |
|
31 | from formencode import htmlfill | |
32 | from webob.exc import HTTPFound |
|
32 | from webob.exc import HTTPFound | |
33 | from pylons.i18n.translation import _ |
|
33 | from pylons.i18n.translation import _ | |
34 | from pylons.controllers.util import abort, redirect |
|
34 | from pylons.controllers.util import abort, redirect | |
35 | from pylons import request, response, session, tmpl_context as c, url |
|
35 | from pylons import request, response, session, tmpl_context as c, url | |
36 |
|
36 | |||
37 | import rhodecode.lib.helpers as h |
|
37 | import rhodecode.lib.helpers as h | |
38 | from rhodecode.lib.auth import AuthUser, HasPermissionAnyDecorator |
|
38 | from rhodecode.lib.auth import AuthUser, HasPermissionAnyDecorator | |
39 | from rhodecode.lib.base import BaseController, render |
|
39 | from rhodecode.lib.base import BaseController, render | |
40 | from rhodecode.model.db import User |
|
40 | from rhodecode.model.db import User | |
41 | from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm |
|
41 | from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm | |
42 | from rhodecode.model.user import UserModel |
|
42 | from rhodecode.model.user import UserModel | |
43 | from rhodecode.model.meta import Session |
|
43 | from rhodecode.model.meta import Session | |
44 |
|
44 | |||
45 |
|
45 | |||
46 |
|
||||
47 | log = logging.getLogger(__name__) |
|
46 | log = logging.getLogger(__name__) | |
48 |
|
47 | |||
49 |
|
48 | |||
50 | class LoginController(BaseController): |
|
49 | class LoginController(BaseController): | |
51 |
|
50 | |||
52 | def __before__(self): |
|
51 | def __before__(self): | |
53 | super(LoginController, self).__before__() |
|
52 | super(LoginController, self).__before__() | |
54 |
|
53 | |||
55 | def index(self): |
|
54 | def index(self): | |
56 | # redirect if already logged in |
|
55 | # redirect if already logged in | |
57 |
c.came_from = request.GET.get('came_from' |
|
56 | c.came_from = request.GET.get('came_from') | |
58 |
|
57 | |||
59 | if self.rhodecode_user.is_authenticated \ |
|
58 | if self.rhodecode_user.is_authenticated \ | |
60 | and self.rhodecode_user.username != 'default': |
|
59 | and self.rhodecode_user.username != 'default': | |
61 |
|
60 | |||
62 | return redirect(url('home')) |
|
61 | return redirect(url('home')) | |
63 |
|
62 | |||
64 | if request.POST: |
|
63 | if request.POST: | |
65 | # import Login Form validator class |
|
64 | # import Login Form validator class | |
66 | login_form = LoginForm() |
|
65 | login_form = LoginForm() | |
67 | try: |
|
66 | try: | |
68 | session.invalidate() |
|
67 | session.invalidate() | |
69 | c.form_result = login_form.to_python(dict(request.POST)) |
|
68 | c.form_result = login_form.to_python(dict(request.POST)) | |
70 | # form checks for username/password, now we're authenticated |
|
69 | # form checks for username/password, now we're authenticated | |
71 | username = c.form_result['username'] |
|
70 | username = c.form_result['username'] | |
72 | user = User.get_by_username(username, case_insensitive=True) |
|
71 | user = User.get_by_username(username, case_insensitive=True) | |
73 | auth_user = AuthUser(user.user_id) |
|
72 | auth_user = AuthUser(user.user_id) | |
74 | auth_user.set_authenticated() |
|
73 | auth_user.set_authenticated() | |
75 | cs = auth_user.get_cookie_store() |
|
74 | cs = auth_user.get_cookie_store() | |
76 | session['rhodecode_user'] = cs |
|
75 | session['rhodecode_user'] = cs | |
77 | user.update_lastlogin() |
|
76 | user.update_lastlogin() | |
78 | Session().commit() |
|
77 | Session().commit() | |
79 |
|
78 | |||
80 | # If they want to be remembered, update the cookie |
|
79 | # If they want to be remembered, update the cookie | |
81 | if c.form_result['remember'] is not False: |
|
80 | if c.form_result['remember'] is not False: | |
82 | _year = (datetime.datetime.now() + |
|
81 | _year = (datetime.datetime.now() + | |
83 | datetime.timedelta(seconds=60 * 60 * 24 * 365)) |
|
82 | datetime.timedelta(seconds=60 * 60 * 24 * 365)) | |
84 | session._set_cookie_expires(_year) |
|
83 | session._set_cookie_expires(_year) | |
85 |
|
84 | |||
86 | session.save() |
|
85 | session.save() | |
87 |
|
86 | |||
88 | log.info('user %s is now authenticated and stored in ' |
|
87 | log.info('user %s is now authenticated and stored in ' | |
89 | 'session, session attrs %s' % (username, cs)) |
|
88 | 'session, session attrs %s' % (username, cs)) | |
90 |
|
89 | |||
91 | # dumps session attrs back to cookie |
|
90 | # dumps session attrs back to cookie | |
92 | session._update_cookie_out() |
|
91 | session._update_cookie_out() | |
93 |
|
92 | |||
94 | # we set new cookie |
|
93 | # we set new cookie | |
95 | headers = None |
|
94 | headers = None | |
96 | if session.request['set_cookie']: |
|
95 | if session.request['set_cookie']: | |
97 | # send set-cookie headers back to response to update cookie |
|
96 | # send set-cookie headers back to response to update cookie | |
98 | headers = [('Set-Cookie', session.request['cookie_out'])] |
|
97 | headers = [('Set-Cookie', session.request['cookie_out'])] | |
99 |
|
98 | |||
100 |
allowed_schemes = ['http', 'https' |
|
99 | allowed_schemes = ['http', 'https'] | |
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') |
|
|||
113 | if c.came_from: |
|
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') | |||
114 | raise HTTPFound(location=c.came_from, headers=headers) |
|
113 | raise HTTPFound(location=c.came_from, headers=headers) | |
115 | else: |
|
114 | else: | |
116 | raise HTTPFound(location=url('home'), headers=headers) |
|
115 | raise HTTPFound(location=url('home'), headers=headers) | |
117 |
|
116 | |||
118 | except formencode.Invalid, errors: |
|
117 | except formencode.Invalid, errors: | |
119 | return htmlfill.render( |
|
118 | return htmlfill.render( | |
120 | render('/login.html'), |
|
119 | render('/login.html'), | |
121 | defaults=errors.value, |
|
120 | defaults=errors.value, | |
122 | errors=errors.error_dict or {}, |
|
121 | errors=errors.error_dict or {}, | |
123 | prefix_error=False, |
|
122 | prefix_error=False, | |
124 | encoding="UTF-8") |
|
123 | encoding="UTF-8") | |
125 |
|
124 | |||
126 | return render('/login.html') |
|
125 | return render('/login.html') | |
127 |
|
126 | |||
128 | @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate', |
|
127 | @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate', | |
129 | 'hg.register.manual_activate') |
|
128 | 'hg.register.manual_activate') | |
130 | def register(self): |
|
129 | def register(self): | |
131 | c.auto_active = False |
|
130 | c.auto_active = False | |
132 | for perm in User.get_by_username('default').user_perms: |
|
131 | for perm in User.get_by_username('default').user_perms: | |
133 | if perm.permission.permission_name == 'hg.register.auto_activate': |
|
132 | if perm.permission.permission_name == 'hg.register.auto_activate': | |
134 | c.auto_active = True |
|
133 | c.auto_active = True | |
135 | break |
|
134 | break | |
136 |
|
135 | |||
137 | if request.POST: |
|
136 | if request.POST: | |
138 |
|
137 | |||
139 | register_form = RegisterForm()() |
|
138 | register_form = RegisterForm()() | |
140 | try: |
|
139 | try: | |
141 | form_result = register_form.to_python(dict(request.POST)) |
|
140 | form_result = register_form.to_python(dict(request.POST)) | |
142 | form_result['active'] = c.auto_active |
|
141 | form_result['active'] = c.auto_active | |
143 | UserModel().create_registration(form_result) |
|
142 | UserModel().create_registration(form_result) | |
144 | h.flash(_('You have successfully registered into rhodecode'), |
|
143 | h.flash(_('You have successfully registered into rhodecode'), | |
145 | category='success') |
|
144 | category='success') | |
146 | Session().commit() |
|
145 | Session().commit() | |
147 | return redirect(url('login_home')) |
|
146 | return redirect(url('login_home')) | |
148 |
|
147 | |||
149 | except formencode.Invalid, errors: |
|
148 | except formencode.Invalid, errors: | |
150 | return htmlfill.render( |
|
149 | return htmlfill.render( | |
151 | render('/register.html'), |
|
150 | render('/register.html'), | |
152 | defaults=errors.value, |
|
151 | defaults=errors.value, | |
153 | errors=errors.error_dict or {}, |
|
152 | errors=errors.error_dict or {}, | |
154 | prefix_error=False, |
|
153 | prefix_error=False, | |
155 | encoding="UTF-8") |
|
154 | encoding="UTF-8") | |
156 |
|
155 | |||
157 | return render('/register.html') |
|
156 | return render('/register.html') | |
158 |
|
157 | |||
159 | def password_reset(self): |
|
158 | def password_reset(self): | |
160 | if request.POST: |
|
159 | if request.POST: | |
161 | password_reset_form = PasswordResetForm()() |
|
160 | password_reset_form = PasswordResetForm()() | |
162 | try: |
|
161 | try: | |
163 | form_result = password_reset_form.to_python(dict(request.POST)) |
|
162 | form_result = password_reset_form.to_python(dict(request.POST)) | |
164 | UserModel().reset_password_link(form_result) |
|
163 | UserModel().reset_password_link(form_result) | |
165 | h.flash(_('Your password reset link was sent'), |
|
164 | h.flash(_('Your password reset link was sent'), | |
166 | category='success') |
|
165 | category='success') | |
167 | return redirect(url('login_home')) |
|
166 | return redirect(url('login_home')) | |
168 |
|
167 | |||
169 | except formencode.Invalid, errors: |
|
168 | except formencode.Invalid, errors: | |
170 | return htmlfill.render( |
|
169 | return htmlfill.render( | |
171 | render('/password_reset.html'), |
|
170 | render('/password_reset.html'), | |
172 | defaults=errors.value, |
|
171 | defaults=errors.value, | |
173 | errors=errors.error_dict or {}, |
|
172 | errors=errors.error_dict or {}, | |
174 | prefix_error=False, |
|
173 | prefix_error=False, | |
175 | encoding="UTF-8") |
|
174 | encoding="UTF-8") | |
176 |
|
175 | |||
177 | return render('/password_reset.html') |
|
176 | return render('/password_reset.html') | |
178 |
|
177 | |||
179 | def password_reset_confirmation(self): |
|
178 | def password_reset_confirmation(self): | |
180 | if request.GET and request.GET.get('key'): |
|
179 | if request.GET and request.GET.get('key'): | |
181 | try: |
|
180 | try: | |
182 | user = User.get_by_api_key(request.GET.get('key')) |
|
181 | user = User.get_by_api_key(request.GET.get('key')) | |
183 | data = dict(email=user.email) |
|
182 | data = dict(email=user.email) | |
184 | UserModel().reset_password(data) |
|
183 | UserModel().reset_password(data) | |
185 | h.flash(_('Your password reset was successful, ' |
|
184 | h.flash(_('Your password reset was successful, ' | |
186 | 'new password has been sent to your email'), |
|
185 | 'new password has been sent to your email'), | |
187 | category='success') |
|
186 | category='success') | |
188 | except Exception, e: |
|
187 | except Exception, e: | |
189 | log.error(e) |
|
188 | log.error(e) | |
190 | return redirect(url('reset_password')) |
|
189 | return redirect(url('reset_password')) | |
191 |
|
190 | |||
192 | return redirect(url('login_home')) |
|
191 | return redirect(url('login_home')) | |
193 |
|
192 | |||
194 | def logout(self): |
|
193 | def logout(self): | |
195 | session.delete() |
|
194 | session.delete() | |
196 | log.info('Logging out and deleting session for user') |
|
195 | log.info('Logging out and deleting session for user') | |
197 | redirect(url('home')) |
|
196 | redirect(url('home')) |
@@ -1,272 +1,291 b'' | |||||
1 | # -*- coding: utf-8 -*- |
|
1 | # -*- coding: utf-8 -*- | |
2 | from rhodecode.tests import * |
|
2 | from rhodecode.tests import * | |
3 | from rhodecode.model.db import User, Notification |
|
3 | from rhodecode.model.db import User, Notification | |
4 | from rhodecode.lib.utils2 import generate_api_key |
|
4 | from rhodecode.lib.utils2 import generate_api_key | |
5 | from rhodecode.lib.auth import check_password |
|
5 | from rhodecode.lib.auth import check_password | |
6 | from rhodecode.lib import helpers as h |
|
6 | from rhodecode.lib import helpers as h | |
7 | from rhodecode.model import validators |
|
7 | from rhodecode.model import validators | |
8 |
|
8 | |||
9 |
|
9 | |||
10 | class TestLoginController(TestController): |
|
10 | class TestLoginController(TestController): | |
11 |
|
11 | |||
12 | def tearDown(self): |
|
12 | def tearDown(self): | |
13 | for n in Notification.query().all(): |
|
13 | for n in Notification.query().all(): | |
14 | self.Session().delete(n) |
|
14 | self.Session().delete(n) | |
15 |
|
15 | |||
16 | self.Session().commit() |
|
16 | self.Session().commit() | |
17 | self.assertEqual(Notification.query().all(), []) |
|
17 | self.assertEqual(Notification.query().all(), []) | |
18 |
|
18 | |||
19 | def test_index(self): |
|
19 | def test_index(self): | |
20 | response = self.app.get(url(controller='login', action='index')) |
|
20 | response = self.app.get(url(controller='login', action='index')) | |
21 | self.assertEqual(response.status, '200 OK') |
|
21 | self.assertEqual(response.status, '200 OK') | |
22 | # Test response... |
|
22 | # Test response... | |
23 |
|
23 | |||
24 | def test_login_admin_ok(self): |
|
24 | def test_login_admin_ok(self): | |
25 | response = self.app.post(url(controller='login', action='index'), |
|
25 | response = self.app.post(url(controller='login', action='index'), | |
26 | {'username': 'test_admin', |
|
26 | {'username': 'test_admin', | |
27 | 'password': 'test12'}) |
|
27 | 'password': 'test12'}) | |
28 | self.assertEqual(response.status, '302 Found') |
|
28 | self.assertEqual(response.status, '302 Found') | |
29 | self.assertEqual(response.session['rhodecode_user'].get('username'), |
|
29 | self.assertEqual(response.session['rhodecode_user'].get('username'), | |
30 | 'test_admin') |
|
30 | 'test_admin') | |
31 | response = response.follow() |
|
31 | response = response.follow() | |
32 | self.assertTrue('%s repository' % HG_REPO in response.body) |
|
32 | self.assertTrue('%s repository' % HG_REPO in response.body) | |
33 |
|
33 | |||
34 | def test_login_regular_ok(self): |
|
34 | def test_login_regular_ok(self): | |
35 | response = self.app.post(url(controller='login', action='index'), |
|
35 | response = self.app.post(url(controller='login', action='index'), | |
36 | {'username': 'test_regular', |
|
36 | {'username': 'test_regular', | |
37 | 'password': 'test12'}) |
|
37 | 'password': 'test12'}) | |
38 |
|
38 | |||
39 | self.assertEqual(response.status, '302 Found') |
|
39 | self.assertEqual(response.status, '302 Found') | |
40 | self.assertEqual(response.session['rhodecode_user'].get('username'), |
|
40 | self.assertEqual(response.session['rhodecode_user'].get('username'), | |
41 | 'test_regular') |
|
41 | 'test_regular') | |
42 | response = response.follow() |
|
42 | response = response.follow() | |
43 | self.assertTrue('%s repository' % HG_REPO in response.body) |
|
43 | self.assertTrue('%s repository' % HG_REPO in response.body) | |
44 | self.assertTrue('<a title="Admin" href="/_admin">' not in response.body) |
|
44 | self.assertTrue('<a title="Admin" href="/_admin">' not in response.body) | |
45 |
|
45 | |||
46 | def test_login_ok_came_from(self): |
|
46 | def test_login_ok_came_from(self): | |
47 | test_came_from = '/_admin/users' |
|
47 | test_came_from = '/_admin/users' | |
48 | response = self.app.post(url(controller='login', action='index', |
|
48 | response = self.app.post(url(controller='login', action='index', | |
49 | came_from=test_came_from), |
|
49 | came_from=test_came_from), | |
50 | {'username': 'test_admin', |
|
50 | {'username': 'test_admin', | |
51 | 'password': 'test12'}) |
|
51 | 'password': 'test12'}) | |
52 | self.assertEqual(response.status, '302 Found') |
|
52 | self.assertEqual(response.status, '302 Found') | |
53 | response = response.follow() |
|
53 | response = response.follow() | |
54 |
|
54 | |||
55 | self.assertEqual(response.status, '200 OK') |
|
55 | self.assertEqual(response.status, '200 OK') | |
56 | self.assertTrue('Users administration' in response.body) |
|
56 | self.assertTrue('Users administration' in response.body) | |
57 |
|
57 | |||
|
58 | @parameterized.expand([ | |||
|
59 | ('data:text/html,<script>window.alert("xss")</script>',), | |||
|
60 | ('mailto:test@rhodecode.org',), | |||
|
61 | ('file:///etc/passwd',), | |||
|
62 | ('ftp://some.ftp.server',), | |||
|
63 | ('http://other.domain',), | |||
|
64 | ]) | |||
|
65 | def test_login_bad_came_froms(self, url_came_from): | |||
|
66 | response = self.app.post(url(controller='login', action='index', | |||
|
67 | came_from=url_came_from), | |||
|
68 | {'username': 'test_admin', | |||
|
69 | 'password': 'test12'}) | |||
|
70 | self.assertEqual(response.status, '302 Found') | |||
|
71 | self.assertEqual(response._environ['paste.testing_variables'] | |||
|
72 | ['tmpl_context'].came_from, '/') | |||
|
73 | response = response.follow() | |||
|
74 | ||||
|
75 | self.assertEqual(response.status, '200 OK') | |||
|
76 | ||||
58 | def test_login_short_password(self): |
|
77 | def test_login_short_password(self): | |
59 | response = self.app.post(url(controller='login', action='index'), |
|
78 | response = self.app.post(url(controller='login', action='index'), | |
60 | {'username': 'test_admin', |
|
79 | {'username': 'test_admin', | |
61 | 'password': 'as'}) |
|
80 | 'password': 'as'}) | |
62 | self.assertEqual(response.status, '200 OK') |
|
81 | self.assertEqual(response.status, '200 OK') | |
63 |
|
82 | |||
64 | self.assertTrue('Enter 3 characters or more' in response.body) |
|
83 | self.assertTrue('Enter 3 characters or more' in response.body) | |
65 |
|
84 | |||
66 | def test_login_wrong_username_password(self): |
|
85 | def test_login_wrong_username_password(self): | |
67 | response = self.app.post(url(controller='login', action='index'), |
|
86 | response = self.app.post(url(controller='login', action='index'), | |
68 | {'username': 'error', |
|
87 | {'username': 'error', | |
69 | 'password': 'test12'}) |
|
88 | 'password': 'test12'}) | |
70 |
|
89 | |||
71 | self.assertTrue('invalid user name' in response.body) |
|
90 | self.assertTrue('invalid user name' in response.body) | |
72 | self.assertTrue('invalid password' in response.body) |
|
91 | self.assertTrue('invalid password' in response.body) | |
73 |
|
92 | |||
74 | #========================================================================== |
|
93 | #========================================================================== | |
75 | # REGISTRATIONS |
|
94 | # REGISTRATIONS | |
76 | #========================================================================== |
|
95 | #========================================================================== | |
77 | def test_register(self): |
|
96 | def test_register(self): | |
78 | response = self.app.get(url(controller='login', action='register')) |
|
97 | response = self.app.get(url(controller='login', action='register')) | |
79 | self.assertTrue('Sign Up to RhodeCode' in response.body) |
|
98 | self.assertTrue('Sign Up to RhodeCode' in response.body) | |
80 |
|
99 | |||
81 | def test_register_err_same_username(self): |
|
100 | def test_register_err_same_username(self): | |
82 | uname = 'test_admin' |
|
101 | uname = 'test_admin' | |
83 | response = self.app.post(url(controller='login', action='register'), |
|
102 | response = self.app.post(url(controller='login', action='register'), | |
84 | {'username': uname, |
|
103 | {'username': uname, | |
85 | 'password': 'test12', |
|
104 | 'password': 'test12', | |
86 | 'password_confirmation': 'test12', |
|
105 | 'password_confirmation': 'test12', | |
87 | 'email': 'goodmail@domain.com', |
|
106 | 'email': 'goodmail@domain.com', | |
88 | 'firstname': 'test', |
|
107 | 'firstname': 'test', | |
89 | 'lastname': 'test'}) |
|
108 | 'lastname': 'test'}) | |
90 |
|
109 | |||
91 | msg = validators.ValidUsername()._messages['username_exists'] |
|
110 | msg = validators.ValidUsername()._messages['username_exists'] | |
92 | msg = h.html_escape(msg % {'username': uname}) |
|
111 | msg = h.html_escape(msg % {'username': uname}) | |
93 | response.mustcontain(msg) |
|
112 | response.mustcontain(msg) | |
94 |
|
113 | |||
95 | def test_register_err_same_email(self): |
|
114 | def test_register_err_same_email(self): | |
96 | response = self.app.post(url(controller='login', action='register'), |
|
115 | response = self.app.post(url(controller='login', action='register'), | |
97 | {'username': 'test_admin_0', |
|
116 | {'username': 'test_admin_0', | |
98 | 'password': 'test12', |
|
117 | 'password': 'test12', | |
99 | 'password_confirmation': 'test12', |
|
118 | 'password_confirmation': 'test12', | |
100 | 'email': 'test_admin@mail.com', |
|
119 | 'email': 'test_admin@mail.com', | |
101 | 'firstname': 'test', |
|
120 | 'firstname': 'test', | |
102 | 'lastname': 'test'}) |
|
121 | 'lastname': 'test'}) | |
103 |
|
122 | |||
104 | msg = validators.UniqSystemEmail()()._messages['email_taken'] |
|
123 | msg = validators.UniqSystemEmail()()._messages['email_taken'] | |
105 | response.mustcontain(msg) |
|
124 | response.mustcontain(msg) | |
106 |
|
125 | |||
107 | def test_register_err_same_email_case_sensitive(self): |
|
126 | def test_register_err_same_email_case_sensitive(self): | |
108 | response = self.app.post(url(controller='login', action='register'), |
|
127 | response = self.app.post(url(controller='login', action='register'), | |
109 | {'username': 'test_admin_1', |
|
128 | {'username': 'test_admin_1', | |
110 | 'password': 'test12', |
|
129 | 'password': 'test12', | |
111 | 'password_confirmation': 'test12', |
|
130 | 'password_confirmation': 'test12', | |
112 | 'email': 'TesT_Admin@mail.COM', |
|
131 | 'email': 'TesT_Admin@mail.COM', | |
113 | 'firstname': 'test', |
|
132 | 'firstname': 'test', | |
114 | 'lastname': 'test'}) |
|
133 | 'lastname': 'test'}) | |
115 | msg = validators.UniqSystemEmail()()._messages['email_taken'] |
|
134 | msg = validators.UniqSystemEmail()()._messages['email_taken'] | |
116 | response.mustcontain(msg) |
|
135 | response.mustcontain(msg) | |
117 |
|
136 | |||
118 | def test_register_err_wrong_data(self): |
|
137 | def test_register_err_wrong_data(self): | |
119 | response = self.app.post(url(controller='login', action='register'), |
|
138 | response = self.app.post(url(controller='login', action='register'), | |
120 | {'username': 'xs', |
|
139 | {'username': 'xs', | |
121 | 'password': 'test', |
|
140 | 'password': 'test', | |
122 | 'password_confirmation': 'test', |
|
141 | 'password_confirmation': 'test', | |
123 | 'email': 'goodmailm', |
|
142 | 'email': 'goodmailm', | |
124 | 'firstname': 'test', |
|
143 | 'firstname': 'test', | |
125 | 'lastname': 'test'}) |
|
144 | 'lastname': 'test'}) | |
126 | self.assertEqual(response.status, '200 OK') |
|
145 | self.assertEqual(response.status, '200 OK') | |
127 | response.mustcontain('An email address must contain a single @') |
|
146 | response.mustcontain('An email address must contain a single @') | |
128 | response.mustcontain('Enter a value 6 characters long or more') |
|
147 | response.mustcontain('Enter a value 6 characters long or more') | |
129 |
|
148 | |||
130 | def test_register_err_username(self): |
|
149 | def test_register_err_username(self): | |
131 | response = self.app.post(url(controller='login', action='register'), |
|
150 | response = self.app.post(url(controller='login', action='register'), | |
132 | {'username': 'error user', |
|
151 | {'username': 'error user', | |
133 | 'password': 'test12', |
|
152 | 'password': 'test12', | |
134 | 'password_confirmation': 'test12', |
|
153 | 'password_confirmation': 'test12', | |
135 | 'email': 'goodmailm', |
|
154 | 'email': 'goodmailm', | |
136 | 'firstname': 'test', |
|
155 | 'firstname': 'test', | |
137 | 'lastname': 'test'}) |
|
156 | 'lastname': 'test'}) | |
138 |
|
157 | |||
139 | response.mustcontain('An email address must contain a single @') |
|
158 | response.mustcontain('An email address must contain a single @') | |
140 | response.mustcontain('Username may only contain ' |
|
159 | response.mustcontain('Username may only contain ' | |
141 | 'alphanumeric characters underscores, ' |
|
160 | 'alphanumeric characters underscores, ' | |
142 | 'periods or dashes and must begin with ' |
|
161 | 'periods or dashes and must begin with ' | |
143 | 'alphanumeric character') |
|
162 | 'alphanumeric character') | |
144 |
|
163 | |||
145 | def test_register_err_case_sensitive(self): |
|
164 | def test_register_err_case_sensitive(self): | |
146 | usr = 'Test_Admin' |
|
165 | usr = 'Test_Admin' | |
147 | response = self.app.post(url(controller='login', action='register'), |
|
166 | response = self.app.post(url(controller='login', action='register'), | |
148 | {'username': usr, |
|
167 | {'username': usr, | |
149 | 'password': 'test12', |
|
168 | 'password': 'test12', | |
150 | 'password_confirmation': 'test12', |
|
169 | 'password_confirmation': 'test12', | |
151 | 'email': 'goodmailm', |
|
170 | 'email': 'goodmailm', | |
152 | 'firstname': 'test', |
|
171 | 'firstname': 'test', | |
153 | 'lastname': 'test'}) |
|
172 | 'lastname': 'test'}) | |
154 |
|
173 | |||
155 | response.mustcontain('An email address must contain a single @') |
|
174 | response.mustcontain('An email address must contain a single @') | |
156 | msg = validators.ValidUsername()._messages['username_exists'] |
|
175 | msg = validators.ValidUsername()._messages['username_exists'] | |
157 | msg = h.html_escape(msg % {'username': usr}) |
|
176 | msg = h.html_escape(msg % {'username': usr}) | |
158 | response.mustcontain(msg) |
|
177 | response.mustcontain(msg) | |
159 |
|
178 | |||
160 | def test_register_special_chars(self): |
|
179 | def test_register_special_chars(self): | |
161 | response = self.app.post(url(controller='login', action='register'), |
|
180 | response = self.app.post(url(controller='login', action='register'), | |
162 | {'username': 'xxxaxn', |
|
181 | {'username': 'xxxaxn', | |
163 | 'password': 'Δ ΔΕΊΕΌΔ ΕΕΕΕ', |
|
182 | 'password': 'Δ ΔΕΊΕΌΔ ΕΕΕΕ', | |
164 | 'password_confirmation': 'Δ ΔΕΊΕΌΔ ΕΕΕΕ', |
|
183 | 'password_confirmation': 'Δ ΔΕΊΕΌΔ ΕΕΕΕ', | |
165 | 'email': 'goodmailm@test.plx', |
|
184 | 'email': 'goodmailm@test.plx', | |
166 | 'firstname': 'test', |
|
185 | 'firstname': 'test', | |
167 | 'lastname': 'test'}) |
|
186 | 'lastname': 'test'}) | |
168 |
|
187 | |||
169 | msg = validators.ValidPassword()._messages['invalid_password'] |
|
188 | msg = validators.ValidPassword()._messages['invalid_password'] | |
170 | response.mustcontain(msg) |
|
189 | response.mustcontain(msg) | |
171 |
|
190 | |||
172 | def test_register_password_mismatch(self): |
|
191 | def test_register_password_mismatch(self): | |
173 | response = self.app.post(url(controller='login', action='register'), |
|
192 | response = self.app.post(url(controller='login', action='register'), | |
174 | {'username': 'xs', |
|
193 | {'username': 'xs', | |
175 | 'password': '123qwe', |
|
194 | 'password': '123qwe', | |
176 | 'password_confirmation': 'qwe123', |
|
195 | 'password_confirmation': 'qwe123', | |
177 | 'email': 'goodmailm@test.plxa', |
|
196 | 'email': 'goodmailm@test.plxa', | |
178 | 'firstname': 'test', |
|
197 | 'firstname': 'test', | |
179 | 'lastname': 'test'}) |
|
198 | 'lastname': 'test'}) | |
180 | msg = validators.ValidPasswordsMatch()._messages['password_mismatch'] |
|
199 | msg = validators.ValidPasswordsMatch()._messages['password_mismatch'] | |
181 | response.mustcontain(msg) |
|
200 | response.mustcontain(msg) | |
182 |
|
201 | |||
183 | def test_register_ok(self): |
|
202 | def test_register_ok(self): | |
184 | username = 'test_regular4' |
|
203 | username = 'test_regular4' | |
185 | password = 'qweqwe' |
|
204 | password = 'qweqwe' | |
186 | email = 'marcin@test.com' |
|
205 | email = 'marcin@test.com' | |
187 | name = 'testname' |
|
206 | name = 'testname' | |
188 | lastname = 'testlastname' |
|
207 | lastname = 'testlastname' | |
189 |
|
208 | |||
190 | response = self.app.post(url(controller='login', action='register'), |
|
209 | response = self.app.post(url(controller='login', action='register'), | |
191 | {'username': username, |
|
210 | {'username': username, | |
192 | 'password': password, |
|
211 | 'password': password, | |
193 | 'password_confirmation': password, |
|
212 | 'password_confirmation': password, | |
194 | 'email': email, |
|
213 | 'email': email, | |
195 | 'firstname': name, |
|
214 | 'firstname': name, | |
196 | 'lastname': lastname, |
|
215 | 'lastname': lastname, | |
197 | 'admin': True}) # This should be overriden |
|
216 | 'admin': True}) # This should be overriden | |
198 | self.assertEqual(response.status, '302 Found') |
|
217 | self.assertEqual(response.status, '302 Found') | |
199 | self.checkSessionFlash(response, 'You have successfully registered into rhodecode') |
|
218 | self.checkSessionFlash(response, 'You have successfully registered into rhodecode') | |
200 |
|
219 | |||
201 | ret = self.Session().query(User).filter(User.username == 'test_regular4').one() |
|
220 | ret = self.Session().query(User).filter(User.username == 'test_regular4').one() | |
202 | self.assertEqual(ret.username, username) |
|
221 | self.assertEqual(ret.username, username) | |
203 | self.assertEqual(check_password(password, ret.password), True) |
|
222 | self.assertEqual(check_password(password, ret.password), True) | |
204 | self.assertEqual(ret.email, email) |
|
223 | self.assertEqual(ret.email, email) | |
205 | self.assertEqual(ret.name, name) |
|
224 | self.assertEqual(ret.name, name) | |
206 | self.assertEqual(ret.lastname, lastname) |
|
225 | self.assertEqual(ret.lastname, lastname) | |
207 | self.assertNotEqual(ret.api_key, None) |
|
226 | self.assertNotEqual(ret.api_key, None) | |
208 | self.assertEqual(ret.admin, False) |
|
227 | self.assertEqual(ret.admin, False) | |
209 |
|
228 | |||
210 | def test_forgot_password_wrong_mail(self): |
|
229 | def test_forgot_password_wrong_mail(self): | |
211 | bad_email = 'marcin@wrongmail.org' |
|
230 | bad_email = 'marcin@wrongmail.org' | |
212 | response = self.app.post( |
|
231 | response = self.app.post( | |
213 | url(controller='login', action='password_reset'), |
|
232 | url(controller='login', action='password_reset'), | |
214 | {'email': bad_email, } |
|
233 | {'email': bad_email, } | |
215 | ) |
|
234 | ) | |
216 |
|
235 | |||
217 | msg = validators.ValidSystemEmail()._messages['non_existing_email'] |
|
236 | msg = validators.ValidSystemEmail()._messages['non_existing_email'] | |
218 | msg = h.html_escape(msg % {'email': bad_email}) |
|
237 | msg = h.html_escape(msg % {'email': bad_email}) | |
219 | response.mustcontain() |
|
238 | response.mustcontain() | |
220 |
|
239 | |||
221 | def test_forgot_password(self): |
|
240 | def test_forgot_password(self): | |
222 | response = self.app.get(url(controller='login', |
|
241 | response = self.app.get(url(controller='login', | |
223 | action='password_reset')) |
|
242 | action='password_reset')) | |
224 | self.assertEqual(response.status, '200 OK') |
|
243 | self.assertEqual(response.status, '200 OK') | |
225 |
|
244 | |||
226 | username = 'test_password_reset_1' |
|
245 | username = 'test_password_reset_1' | |
227 | password = 'qweqwe' |
|
246 | password = 'qweqwe' | |
228 | email = 'marcin@python-works.com' |
|
247 | email = 'marcin@python-works.com' | |
229 | name = 'passwd' |
|
248 | name = 'passwd' | |
230 | lastname = 'reset' |
|
249 | lastname = 'reset' | |
231 |
|
250 | |||
232 | new = User() |
|
251 | new = User() | |
233 | new.username = username |
|
252 | new.username = username | |
234 | new.password = password |
|
253 | new.password = password | |
235 | new.email = email |
|
254 | new.email = email | |
236 | new.name = name |
|
255 | new.name = name | |
237 | new.lastname = lastname |
|
256 | new.lastname = lastname | |
238 | new.api_key = generate_api_key(username) |
|
257 | new.api_key = generate_api_key(username) | |
239 | self.Session().add(new) |
|
258 | self.Session().add(new) | |
240 | self.Session().commit() |
|
259 | self.Session().commit() | |
241 |
|
260 | |||
242 | response = self.app.post(url(controller='login', |
|
261 | response = self.app.post(url(controller='login', | |
243 | action='password_reset'), |
|
262 | action='password_reset'), | |
244 | {'email': email, }) |
|
263 | {'email': email, }) | |
245 |
|
264 | |||
246 | self.checkSessionFlash(response, 'Your password reset link was sent') |
|
265 | self.checkSessionFlash(response, 'Your password reset link was sent') | |
247 |
|
266 | |||
248 | response = response.follow() |
|
267 | response = response.follow() | |
249 |
|
268 | |||
250 | # BAD KEY |
|
269 | # BAD KEY | |
251 |
|
270 | |||
252 | key = "bad" |
|
271 | key = "bad" | |
253 | response = self.app.get(url(controller='login', |
|
272 | response = self.app.get(url(controller='login', | |
254 | action='password_reset_confirmation', |
|
273 | action='password_reset_confirmation', | |
255 | key=key)) |
|
274 | key=key)) | |
256 | self.assertEqual(response.status, '302 Found') |
|
275 | self.assertEqual(response.status, '302 Found') | |
257 | self.assertTrue(response.location.endswith(url('reset_password'))) |
|
276 | self.assertTrue(response.location.endswith(url('reset_password'))) | |
258 |
|
277 | |||
259 | # GOOD KEY |
|
278 | # GOOD KEY | |
260 |
|
279 | |||
261 | key = User.get_by_username(username).api_key |
|
280 | key = User.get_by_username(username).api_key | |
262 | response = self.app.get(url(controller='login', |
|
281 | response = self.app.get(url(controller='login', | |
263 | action='password_reset_confirmation', |
|
282 | action='password_reset_confirmation', | |
264 | key=key)) |
|
283 | key=key)) | |
265 | self.assertEqual(response.status, '302 Found') |
|
284 | self.assertEqual(response.status, '302 Found') | |
266 | self.assertTrue(response.location.endswith(url('login_home'))) |
|
285 | self.assertTrue(response.location.endswith(url('login_home'))) | |
267 |
|
286 | |||
268 | self.checkSessionFlash(response, |
|
287 | self.checkSessionFlash(response, | |
269 | ('Your password reset was successful, ' |
|
288 | ('Your password reset was successful, ' | |
270 | 'new password has been sent to your email')) |
|
289 | 'new password has been sent to your email')) | |
271 |
|
290 | |||
272 | response = response.follow() |
|
291 | response = response.follow() |
General Comments 0
You need to be logged in to leave comments.
Login now