##// END OF EJS Templates
login: add support link to disabled password reset page
lisaq -
r1038:1703d7ca default
parent child Browse files
Show More
@@ -1,83 +1,88 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="base/root.html"/>
2 <%inherit file="base/root.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Sign In')}
5 ${_('Sign In')}
6 %if c.rhodecode_name:
6 %if c.rhodecode_name:
7 &middot; ${h.branding(c.rhodecode_name)}
7 &middot; ${h.branding(c.rhodecode_name)}
8 %endif
8 %endif
9 </%def>
9 </%def>
10
10
11 <style>body{background-color:#eeeeee;}</style>
11 <style>body{background-color:#eeeeee;}</style>
12 <div class="loginbox">
12 <div class="loginbox">
13 <div class="header">
13 <div class="header">
14 <div id="header-inner" class="title">
14 <div id="header-inner" class="title">
15 <div id="logo">
15 <div id="logo">
16 <div class="logo-wrapper">
16 <div class="logo-wrapper">
17 <a href="${h.url('home')}"><img src="${h.asset('images/rhodecode-logo-white-216x60.png')}" alt="RhodeCode"/></a>
17 <a href="${h.url('home')}"><img src="${h.asset('images/rhodecode-logo-white-216x60.png')}" alt="RhodeCode"/></a>
18 </div>
18 </div>
19 %if c.rhodecode_name:
19 %if c.rhodecode_name:
20 <div class="branding"> ${h.branding(c.rhodecode_name)}</div>
20 <div class="branding"> ${h.branding(c.rhodecode_name)}</div>
21 %endif
21 %endif
22 </div>
22 </div>
23 </div>
23 </div>
24 </div>
24 </div>
25
25
26 <div class="loginwrapper">
26 <div class="loginwrapper">
27 <div class="left-column">
27 <div class="left-column">
28 <img class="sign-in-image" src="${h.asset('images/sign-in.png')}" alt="RhodeCode"/>
28 <img class="sign-in-image" src="${h.asset('images/sign-in.png')}" alt="RhodeCode"/>
29 </div>
29 </div>
30 <%block name="above_login_button" />
30 <%block name="above_login_button" />
31 <div id="login" class="right-column">
31 <div id="login" class="right-column">
32 <!-- login -->
32 <!-- login -->
33 <div class="sign-in-title">
33 <div class="sign-in-title">
34 <h1>${_('Sign In')}</h1>
34 <h1>${_('Sign In')}</h1>
35 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
35 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
36 <h4>${h.link_to(_("Go to the registration page to create a new account."), request.route_path('register'))}</h4>
36 <h4>${h.link_to(_("Go to the registration page to create a new account."), request.route_path('register'))}</h4>
37 %endif
37 %endif
38 </div>
38 </div>
39 <div class="inner form">
39 <div class="inner form">
40 ${h.form(request.route_path('login', _query={'came_from': came_from}), needs_csrf_token=False)}
40 ${h.form(request.route_path('login', _query={'came_from': came_from}), needs_csrf_token=False)}
41
41
42 <label for="username">${_('Username')}:</label>
42 <label for="username">${_('Username')}:</label>
43 ${h.text('username', class_='focus', value=defaults.get('username'))}
43 ${h.text('username', class_='focus', value=defaults.get('username'))}
44 %if 'username' in errors:
44 %if 'username' in errors:
45 <span class="error-message">${errors.get('username')}</span>
45 <span class="error-message">${errors.get('username')}</span>
46 <br />
46 <br />
47 %endif
47 %endif
48
48
49 <label for="password">${_('Password')}:</label>
49 <label for="password">${_('Password')}:</label>
50 ${h.password('password', class_='focus')}
50 ${h.password('password', class_='focus')}
51 %if 'password' in errors:
51 %if 'password' in errors:
52 <span class="error-message">${errors.get('password')}</span>
52 <span class="error-message">${errors.get('password')}</span>
53 <br />
53 <br />
54 %endif
54 %endif
55
55
56 ${h.checkbox('remember', value=True, checked=defaults.get('remember'))}
56 ${h.checkbox('remember', value=True, checked=defaults.get('remember'))}
57 <label class="checkbox" for="remember">${_('Remember me')}</label>
57 <label class="checkbox" for="remember">${_('Remember me')}</label>
58
58
59 %if h.HasPermissionAny('hg.password_reset.enabled')():
59 %if h.HasPermissionAny('hg.password_reset.enabled')():
60 <p class="links">
60 <p class="links">
61 ${h.link_to(_('Forgot your password?'), h.route_path('reset_password'), class_='pwd_reset')}
61 ${h.link_to(_('Forgot your password?'), h.route_path('reset_password'), class_='pwd_reset')}
62 </p>
62 </p>
63 %elif h.HasPermissionAny('hg.password_reset.hidden')():
63 %elif h.HasPermissionAny('hg.password_reset.hidden')():
64 <p class="help-block">
64 <p class="help-block">
65 ${_('Contact an administrator if you have forgotten your password.')}
65 ${_('Password reset is disabled. Please contact ')}
66 % if c.visual.rhodecode_support_url:
67 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
68 ${_('or')}
69 % endif
70 ${_('an administrator if you need help.')}
66 </p>
71 </p>
67 %endif
72 %endif
68
73
69
74
70 ${h.submit('sign_in', _('Sign In'), class_="btn sign-in")}
75 ${h.submit('sign_in', _('Sign In'), class_="btn sign-in")}
71
76
72 ${h.end_form()}
77 ${h.end_form()}
73 <script type="text/javascript">
78 <script type="text/javascript">
74 $(document).ready(function(){
79 $(document).ready(function(){
75 $('#username').focus();
80 $('#username').focus();
76 })
81 })
77 </script>
82 </script>
78 </div>
83 </div>
79 <!-- end login -->
84 <!-- end login -->
80 <%block name="below_login_button" />
85 <%block name="below_login_button" />
81 </div>
86 </div>
82 </div>
87 </div>
83 </div>
88 </div>
@@ -1,83 +1,90 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="base/root.html"/>
2 <%inherit file="base/root.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Create an Account')}
5 ${_('Reset Password')}
6 %if c.rhodecode_name:
6 %if c.rhodecode_name:
7 &middot; ${h.branding(c.rhodecode_name)}
7 &middot; ${h.branding(c.rhodecode_name)}
8 %endif
8 %endif
9 </%def>
9 </%def>
10 <style>body{background-color:#eeeeee;}</style>
10 <style>body{background-color:#eeeeee;}</style>
11
11
12 <div class="loginbox">
12 <div class="loginbox">
13 <div class="header">
13 <div class="header">
14 <div id="header-inner" class="title">
14 <div id="header-inner" class="title">
15 <div id="logo">
15 <div id="logo">
16 <div class="logo-wrapper">
16 <div class="logo-wrapper">
17 <a href="${h.url('home')}"><img src="${h.asset('images/rhodecode-logo-white-216x60.png')}" alt="RhodeCode"/></a>
17 <a href="${h.url('home')}"><img src="${h.asset('images/rhodecode-logo-white-216x60.png')}" alt="RhodeCode"/></a>
18 </div>
18 </div>
19 %if c.rhodecode_name:
19 %if c.rhodecode_name:
20 <div class="branding"> ${h.branding(c.rhodecode_name)}</div>
20 <div class="branding"> ${h.branding(c.rhodecode_name)}</div>
21 %endif
21 %endif
22 </div>
22 </div>
23 </div>
23 </div>
24 </div>
24 </div>
25
25
26 <div class="loginwrapper">
26 <div class="loginwrapper">
27 <div class="left-column">
27 <div class="left-column">
28 <img class="sign-in-image" src="${h.asset('images/sign-in.png')}" alt="RhodeCode"/>
28 <img class="sign-in-image" src="${h.asset('images/sign-in.png')}" alt="RhodeCode"/>
29 </div>
29 </div>
30
30
31 %if h.HasPermissionAny('hg.password_reset.disabled')():
31 %if h.HasPermissionAny('hg.password_reset.disabled')():
32 <div class="right-column">
32 <div class="right-column">
33 <p>${_('Password reset has been disabled.')}</p>
33 <p>
34 ${_('Password reset is disabled. Please contact ')}
35 % if c.visual.rhodecode_support_url:
36 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
37 ${_('or')}
38 % endif
39 ${_('an administrator if you need help.')}
40 </p>
34 </div>
41 </div>
35 %else:
42 %else:
36 <div id="register" class="right-column">
43 <div id="register" class="right-column">
37 <!-- login -->
44 <!-- login -->
38 <div class="sign-in-title">
45 <div class="sign-in-title">
39 <h1>${_('Reset your Password')}</h1>
46 <h1>${_('Reset your Password')}</h1>
40 <h4>${h.link_to(_("Go to the login page to sign in."), request.route_path('login'))}</h4>
47 <h4>${h.link_to(_("Go to the login page to sign in."), request.route_path('login'))}</h4>
41 </div>
48 </div>
42 <div class="inner form">
49 <div class="inner form">
43 ${h.form(request.route_path('reset_password'), needs_csrf_token=False)}
50 ${h.form(request.route_path('reset_password'), needs_csrf_token=False)}
44 <label for="email">${_('Email Address')}:</label>
51 <label for="email">${_('Email Address')}:</label>
45 ${h.text('email', defaults.get('email'))}
52 ${h.text('email', defaults.get('email'))}
46 %if 'email' in errors:
53 %if 'email' in errors:
47 <span class="error-message">${errors.get('email')}</span>
54 <span class="error-message">${errors.get('email')}</span>
48 <br />
55 <br />
49 %endif
56 %endif
50
57
51 %if captcha_active:
58 %if captcha_active:
52 <div class="login-captcha"
59 <div class="login-captcha"
53 <label for="email">${_('Captcha')}:</label>
60 <label for="email">${_('Captcha')}:</label>
54 ${h.hidden('recaptcha_field')}
61 ${h.hidden('recaptcha_field')}
55 <div id="recaptcha"></div>
62 <div id="recaptcha"></div>
56 %if 'recaptcha_field' in errors:
63 %if 'recaptcha_field' in errors:
57 <span class="error-message">${errors.get('recaptcha_field')}</span>
64 <span class="error-message">${errors.get('recaptcha_field')}</span>
58 <br />
65 <br />
59 %endif
66 %endif
60 </div>
67 </div>
61 %endif
68 %endif
62
69
63 ${h.submit('send', _('Send password reset email'), class_="btn sign-in")}
70 ${h.submit('send', _('Send password reset email'), class_="btn sign-in")}
64 <div class="activation_msg">${_('Password reset link will be sent to matching email address')}</div>
71 <div class="activation_msg">${_('Password reset link will be sent to matching email address')}</div>
65
72
66 ${h.end_form()}
73 ${h.end_form()}
67 </div>
74 </div>
68 </div>
75 </div>
69 %endif
76 %endif
70 </div>
77 </div>
71 </div>
78 </div>
72
79
73 %if captcha_active:
80 %if captcha_active:
74 <script type="text/javascript" src="https://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script>
81 <script type="text/javascript" src="https://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script>
75 %endif
82 %endif
76 <script type="text/javascript">
83 <script type="text/javascript">
77 $(document).ready(function(){
84 $(document).ready(function(){
78 $('#email').focus();
85 $('#email').focus();
79 %if captcha_active:
86 %if captcha_active:
80 Recaptcha.create("${captcha_public_key}", "recaptcha", {theme: "white"});
87 Recaptcha.create("${captcha_public_key}", "recaptcha", {theme: "white"});
81 %endif
88 %endif
82 });
89 });
83 </script>
90 </script>
@@ -1,588 +1,588 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import urlparse
21 import urlparse
22
22
23 import mock
23 import mock
24 import pytest
24 import pytest
25
25
26 from rhodecode.config.routing import ADMIN_PREFIX
26 from rhodecode.config.routing import ADMIN_PREFIX
27 from rhodecode.tests import (
27 from rhodecode.tests import (
28 TestController, assert_session_flash, clear_all_caches, url,
28 TestController, assert_session_flash, clear_all_caches, url,
29 HG_REPO, TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS)
29 HG_REPO, TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS)
30 from rhodecode.tests.fixture import Fixture
30 from rhodecode.tests.fixture import Fixture
31 from rhodecode.tests.utils import AssertResponse, get_session_from_response
31 from rhodecode.tests.utils import AssertResponse, get_session_from_response
32 from rhodecode.lib.auth import check_password, generate_auth_token
32 from rhodecode.lib.auth import check_password, generate_auth_token
33 from rhodecode.lib import helpers as h
33 from rhodecode.lib import helpers as h
34 from rhodecode.model.auth_token import AuthTokenModel
34 from rhodecode.model.auth_token import AuthTokenModel
35 from rhodecode.model import validators
35 from rhodecode.model import validators
36 from rhodecode.model.db import User, Notification
36 from rhodecode.model.db import User, Notification
37 from rhodecode.model.meta import Session
37 from rhodecode.model.meta import Session
38
38
39 fixture = Fixture()
39 fixture = Fixture()
40
40
41 # Hardcode URLs because we don't have a request object to use
41 # Hardcode URLs because we don't have a request object to use
42 # pyramids URL generation methods.
42 # pyramids URL generation methods.
43 index_url = '/'
43 index_url = '/'
44 login_url = ADMIN_PREFIX + '/login'
44 login_url = ADMIN_PREFIX + '/login'
45 logut_url = ADMIN_PREFIX + '/logout'
45 logut_url = ADMIN_PREFIX + '/logout'
46 register_url = ADMIN_PREFIX + '/register'
46 register_url = ADMIN_PREFIX + '/register'
47 pwd_reset_url = ADMIN_PREFIX + '/password_reset'
47 pwd_reset_url = ADMIN_PREFIX + '/password_reset'
48 pwd_reset_confirm_url = ADMIN_PREFIX + '/password_reset_confirmation'
48 pwd_reset_confirm_url = ADMIN_PREFIX + '/password_reset_confirmation'
49
49
50
50
51 @pytest.mark.usefixtures('app')
51 @pytest.mark.usefixtures('app')
52 class TestLoginController:
52 class TestLoginController:
53 destroy_users = set()
53 destroy_users = set()
54
54
55 @classmethod
55 @classmethod
56 def teardown_class(cls):
56 def teardown_class(cls):
57 fixture.destroy_users(cls.destroy_users)
57 fixture.destroy_users(cls.destroy_users)
58
58
59 def teardown_method(self, method):
59 def teardown_method(self, method):
60 for n in Notification.query().all():
60 for n in Notification.query().all():
61 Session().delete(n)
61 Session().delete(n)
62
62
63 Session().commit()
63 Session().commit()
64 assert Notification.query().all() == []
64 assert Notification.query().all() == []
65
65
66 def test_index(self):
66 def test_index(self):
67 response = self.app.get(login_url)
67 response = self.app.get(login_url)
68 assert response.status == '200 OK'
68 assert response.status == '200 OK'
69 # Test response...
69 # Test response...
70
70
71 def test_login_admin_ok(self):
71 def test_login_admin_ok(self):
72 response = self.app.post(login_url,
72 response = self.app.post(login_url,
73 {'username': 'test_admin',
73 {'username': 'test_admin',
74 'password': 'test12'})
74 'password': 'test12'})
75 assert response.status == '302 Found'
75 assert response.status == '302 Found'
76 session = get_session_from_response(response)
76 session = get_session_from_response(response)
77 username = session['rhodecode_user'].get('username')
77 username = session['rhodecode_user'].get('username')
78 assert username == 'test_admin'
78 assert username == 'test_admin'
79 response = response.follow()
79 response = response.follow()
80 response.mustcontain('/%s' % HG_REPO)
80 response.mustcontain('/%s' % HG_REPO)
81
81
82 def test_login_regular_ok(self):
82 def test_login_regular_ok(self):
83 response = self.app.post(login_url,
83 response = self.app.post(login_url,
84 {'username': 'test_regular',
84 {'username': 'test_regular',
85 'password': 'test12'})
85 'password': 'test12'})
86
86
87 assert response.status == '302 Found'
87 assert response.status == '302 Found'
88 session = get_session_from_response(response)
88 session = get_session_from_response(response)
89 username = session['rhodecode_user'].get('username')
89 username = session['rhodecode_user'].get('username')
90 assert username == 'test_regular'
90 assert username == 'test_regular'
91 response = response.follow()
91 response = response.follow()
92 response.mustcontain('/%s' % HG_REPO)
92 response.mustcontain('/%s' % HG_REPO)
93
93
94 def test_login_ok_came_from(self):
94 def test_login_ok_came_from(self):
95 test_came_from = '/_admin/users?branch=stable'
95 test_came_from = '/_admin/users?branch=stable'
96 _url = '{}?came_from={}'.format(login_url, test_came_from)
96 _url = '{}?came_from={}'.format(login_url, test_came_from)
97 response = self.app.post(
97 response = self.app.post(
98 _url, {'username': 'test_admin', 'password': 'test12'})
98 _url, {'username': 'test_admin', 'password': 'test12'})
99 assert response.status == '302 Found'
99 assert response.status == '302 Found'
100 assert 'branch=stable' in response.location
100 assert 'branch=stable' in response.location
101 response = response.follow()
101 response = response.follow()
102
102
103 assert response.status == '200 OK'
103 assert response.status == '200 OK'
104 response.mustcontain('Users administration')
104 response.mustcontain('Users administration')
105
105
106 def test_redirect_to_login_with_get_args(self):
106 def test_redirect_to_login_with_get_args(self):
107 with fixture.anon_access(False):
107 with fixture.anon_access(False):
108 kwargs = {'branch': 'stable'}
108 kwargs = {'branch': 'stable'}
109 response = self.app.get(
109 response = self.app.get(
110 url('summary_home', repo_name=HG_REPO, **kwargs))
110 url('summary_home', repo_name=HG_REPO, **kwargs))
111 assert response.status == '302 Found'
111 assert response.status == '302 Found'
112 response_query = urlparse.parse_qsl(response.location)
112 response_query = urlparse.parse_qsl(response.location)
113 assert 'branch=stable' in response_query[0][1]
113 assert 'branch=stable' in response_query[0][1]
114
114
115 def test_login_form_with_get_args(self):
115 def test_login_form_with_get_args(self):
116 _url = '{}?came_from=/_admin/users,branch=stable'.format(login_url)
116 _url = '{}?came_from=/_admin/users,branch=stable'.format(login_url)
117 response = self.app.get(_url)
117 response = self.app.get(_url)
118 assert 'branch%3Dstable' in response.form.action
118 assert 'branch%3Dstable' in response.form.action
119
119
120 @pytest.mark.parametrize("url_came_from", [
120 @pytest.mark.parametrize("url_came_from", [
121 'data:text/html,<script>window.alert("xss")</script>',
121 'data:text/html,<script>window.alert("xss")</script>',
122 'mailto:test@rhodecode.org',
122 'mailto:test@rhodecode.org',
123 'file:///etc/passwd',
123 'file:///etc/passwd',
124 'ftp://some.ftp.server',
124 'ftp://some.ftp.server',
125 'http://other.domain',
125 'http://other.domain',
126 '/\r\nX-Forwarded-Host: http://example.org',
126 '/\r\nX-Forwarded-Host: http://example.org',
127 ])
127 ])
128 def test_login_bad_came_froms(self, url_came_from):
128 def test_login_bad_came_froms(self, url_came_from):
129 _url = '{}?came_from={}'.format(login_url, url_came_from)
129 _url = '{}?came_from={}'.format(login_url, url_came_from)
130 response = self.app.post(
130 response = self.app.post(
131 _url,
131 _url,
132 {'username': 'test_admin', 'password': 'test12'})
132 {'username': 'test_admin', 'password': 'test12'})
133 assert response.status == '302 Found'
133 assert response.status == '302 Found'
134 response = response.follow()
134 response = response.follow()
135 assert response.status == '200 OK'
135 assert response.status == '200 OK'
136 assert response.request.path == '/'
136 assert response.request.path == '/'
137
137
138 def test_login_short_password(self):
138 def test_login_short_password(self):
139 response = self.app.post(login_url,
139 response = self.app.post(login_url,
140 {'username': 'test_admin',
140 {'username': 'test_admin',
141 'password': 'as'})
141 'password': 'as'})
142 assert response.status == '200 OK'
142 assert response.status == '200 OK'
143
143
144 response.mustcontain('Enter 3 characters or more')
144 response.mustcontain('Enter 3 characters or more')
145
145
146 def test_login_wrong_non_ascii_password(self, user_regular):
146 def test_login_wrong_non_ascii_password(self, user_regular):
147 response = self.app.post(
147 response = self.app.post(
148 login_url,
148 login_url,
149 {'username': user_regular.username,
149 {'username': user_regular.username,
150 'password': u'invalid-non-asci\xe4'.encode('utf8')})
150 'password': u'invalid-non-asci\xe4'.encode('utf8')})
151
151
152 response.mustcontain('invalid user name')
152 response.mustcontain('invalid user name')
153 response.mustcontain('invalid password')
153 response.mustcontain('invalid password')
154
154
155 def test_login_with_non_ascii_password(self, user_util):
155 def test_login_with_non_ascii_password(self, user_util):
156 password = u'valid-non-ascii\xe4'
156 password = u'valid-non-ascii\xe4'
157 user = user_util.create_user(password=password)
157 user = user_util.create_user(password=password)
158 response = self.app.post(
158 response = self.app.post(
159 login_url,
159 login_url,
160 {'username': user.username,
160 {'username': user.username,
161 'password': password.encode('utf-8')})
161 'password': password.encode('utf-8')})
162 assert response.status_code == 302
162 assert response.status_code == 302
163
163
164 def test_login_wrong_username_password(self):
164 def test_login_wrong_username_password(self):
165 response = self.app.post(login_url,
165 response = self.app.post(login_url,
166 {'username': 'error',
166 {'username': 'error',
167 'password': 'test12'})
167 'password': 'test12'})
168
168
169 response.mustcontain('invalid user name')
169 response.mustcontain('invalid user name')
170 response.mustcontain('invalid password')
170 response.mustcontain('invalid password')
171
171
172 def test_login_admin_ok_password_migration(self, real_crypto_backend):
172 def test_login_admin_ok_password_migration(self, real_crypto_backend):
173 from rhodecode.lib import auth
173 from rhodecode.lib import auth
174
174
175 # create new user, with sha256 password
175 # create new user, with sha256 password
176 temp_user = 'test_admin_sha256'
176 temp_user = 'test_admin_sha256'
177 user = fixture.create_user(temp_user)
177 user = fixture.create_user(temp_user)
178 user.password = auth._RhodeCodeCryptoSha256().hash_create(
178 user.password = auth._RhodeCodeCryptoSha256().hash_create(
179 b'test123')
179 b'test123')
180 Session().add(user)
180 Session().add(user)
181 Session().commit()
181 Session().commit()
182 self.destroy_users.add(temp_user)
182 self.destroy_users.add(temp_user)
183 response = self.app.post(login_url,
183 response = self.app.post(login_url,
184 {'username': temp_user,
184 {'username': temp_user,
185 'password': 'test123'})
185 'password': 'test123'})
186
186
187 assert response.status == '302 Found'
187 assert response.status == '302 Found'
188 session = get_session_from_response(response)
188 session = get_session_from_response(response)
189 username = session['rhodecode_user'].get('username')
189 username = session['rhodecode_user'].get('username')
190 assert username == temp_user
190 assert username == temp_user
191 response = response.follow()
191 response = response.follow()
192 response.mustcontain('/%s' % HG_REPO)
192 response.mustcontain('/%s' % HG_REPO)
193
193
194 # new password should be bcrypted, after log-in and transfer
194 # new password should be bcrypted, after log-in and transfer
195 user = User.get_by_username(temp_user)
195 user = User.get_by_username(temp_user)
196 assert user.password.startswith('$')
196 assert user.password.startswith('$')
197
197
198 # REGISTRATIONS
198 # REGISTRATIONS
199 def test_register(self):
199 def test_register(self):
200 response = self.app.get(register_url)
200 response = self.app.get(register_url)
201 response.mustcontain('Create an Account')
201 response.mustcontain('Create an Account')
202
202
203 def test_register_err_same_username(self):
203 def test_register_err_same_username(self):
204 uname = 'test_admin'
204 uname = 'test_admin'
205 response = self.app.post(
205 response = self.app.post(
206 register_url,
206 register_url,
207 {
207 {
208 'username': uname,
208 'username': uname,
209 'password': 'test12',
209 'password': 'test12',
210 'password_confirmation': 'test12',
210 'password_confirmation': 'test12',
211 'email': 'goodmail@domain.com',
211 'email': 'goodmail@domain.com',
212 'firstname': 'test',
212 'firstname': 'test',
213 'lastname': 'test'
213 'lastname': 'test'
214 }
214 }
215 )
215 )
216
216
217 assertr = AssertResponse(response)
217 assertr = AssertResponse(response)
218 msg = validators.ValidUsername()._messages['username_exists']
218 msg = validators.ValidUsername()._messages['username_exists']
219 msg = msg % {'username': uname}
219 msg = msg % {'username': uname}
220 assertr.element_contains('#username+.error-message', msg)
220 assertr.element_contains('#username+.error-message', msg)
221
221
222 def test_register_err_same_email(self):
222 def test_register_err_same_email(self):
223 response = self.app.post(
223 response = self.app.post(
224 register_url,
224 register_url,
225 {
225 {
226 'username': 'test_admin_0',
226 'username': 'test_admin_0',
227 'password': 'test12',
227 'password': 'test12',
228 'password_confirmation': 'test12',
228 'password_confirmation': 'test12',
229 'email': 'test_admin@mail.com',
229 'email': 'test_admin@mail.com',
230 'firstname': 'test',
230 'firstname': 'test',
231 'lastname': 'test'
231 'lastname': 'test'
232 }
232 }
233 )
233 )
234
234
235 assertr = AssertResponse(response)
235 assertr = AssertResponse(response)
236 msg = validators.UniqSystemEmail()()._messages['email_taken']
236 msg = validators.UniqSystemEmail()()._messages['email_taken']
237 assertr.element_contains('#email+.error-message', msg)
237 assertr.element_contains('#email+.error-message', msg)
238
238
239 def test_register_err_same_email_case_sensitive(self):
239 def test_register_err_same_email_case_sensitive(self):
240 response = self.app.post(
240 response = self.app.post(
241 register_url,
241 register_url,
242 {
242 {
243 'username': 'test_admin_1',
243 'username': 'test_admin_1',
244 'password': 'test12',
244 'password': 'test12',
245 'password_confirmation': 'test12',
245 'password_confirmation': 'test12',
246 'email': 'TesT_Admin@mail.COM',
246 'email': 'TesT_Admin@mail.COM',
247 'firstname': 'test',
247 'firstname': 'test',
248 'lastname': 'test'
248 'lastname': 'test'
249 }
249 }
250 )
250 )
251 assertr = AssertResponse(response)
251 assertr = AssertResponse(response)
252 msg = validators.UniqSystemEmail()()._messages['email_taken']
252 msg = validators.UniqSystemEmail()()._messages['email_taken']
253 assertr.element_contains('#email+.error-message', msg)
253 assertr.element_contains('#email+.error-message', msg)
254
254
255 def test_register_err_wrong_data(self):
255 def test_register_err_wrong_data(self):
256 response = self.app.post(
256 response = self.app.post(
257 register_url,
257 register_url,
258 {
258 {
259 'username': 'xs',
259 'username': 'xs',
260 'password': 'test',
260 'password': 'test',
261 'password_confirmation': 'test',
261 'password_confirmation': 'test',
262 'email': 'goodmailm',
262 'email': 'goodmailm',
263 'firstname': 'test',
263 'firstname': 'test',
264 'lastname': 'test'
264 'lastname': 'test'
265 }
265 }
266 )
266 )
267 assert response.status == '200 OK'
267 assert response.status == '200 OK'
268 response.mustcontain('An email address must contain a single @')
268 response.mustcontain('An email address must contain a single @')
269 response.mustcontain('Enter a value 6 characters long or more')
269 response.mustcontain('Enter a value 6 characters long or more')
270
270
271 def test_register_err_username(self):
271 def test_register_err_username(self):
272 response = self.app.post(
272 response = self.app.post(
273 register_url,
273 register_url,
274 {
274 {
275 'username': 'error user',
275 'username': 'error user',
276 'password': 'test12',
276 'password': 'test12',
277 'password_confirmation': 'test12',
277 'password_confirmation': 'test12',
278 'email': 'goodmailm',
278 'email': 'goodmailm',
279 'firstname': 'test',
279 'firstname': 'test',
280 'lastname': 'test'
280 'lastname': 'test'
281 }
281 }
282 )
282 )
283
283
284 response.mustcontain('An email address must contain a single @')
284 response.mustcontain('An email address must contain a single @')
285 response.mustcontain(
285 response.mustcontain(
286 'Username may only contain '
286 'Username may only contain '
287 'alphanumeric characters underscores, '
287 'alphanumeric characters underscores, '
288 'periods or dashes and must begin with '
288 'periods or dashes and must begin with '
289 'alphanumeric character')
289 'alphanumeric character')
290
290
291 def test_register_err_case_sensitive(self):
291 def test_register_err_case_sensitive(self):
292 usr = 'Test_Admin'
292 usr = 'Test_Admin'
293 response = self.app.post(
293 response = self.app.post(
294 register_url,
294 register_url,
295 {
295 {
296 'username': usr,
296 'username': usr,
297 'password': 'test12',
297 'password': 'test12',
298 'password_confirmation': 'test12',
298 'password_confirmation': 'test12',
299 'email': 'goodmailm',
299 'email': 'goodmailm',
300 'firstname': 'test',
300 'firstname': 'test',
301 'lastname': 'test'
301 'lastname': 'test'
302 }
302 }
303 )
303 )
304
304
305 assertr = AssertResponse(response)
305 assertr = AssertResponse(response)
306 msg = validators.ValidUsername()._messages['username_exists']
306 msg = validators.ValidUsername()._messages['username_exists']
307 msg = msg % {'username': usr}
307 msg = msg % {'username': usr}
308 assertr.element_contains('#username+.error-message', msg)
308 assertr.element_contains('#username+.error-message', msg)
309
309
310 def test_register_special_chars(self):
310 def test_register_special_chars(self):
311 response = self.app.post(
311 response = self.app.post(
312 register_url,
312 register_url,
313 {
313 {
314 'username': 'xxxaxn',
314 'username': 'xxxaxn',
315 'password': 'Δ…Δ‡ΕΊΕΌΔ…Ε›Ε›Ε›Ε›',
315 'password': 'Δ…Δ‡ΕΊΕΌΔ…Ε›Ε›Ε›Ε›',
316 'password_confirmation': 'Δ…Δ‡ΕΊΕΌΔ…Ε›Ε›Ε›Ε›',
316 'password_confirmation': 'Δ…Δ‡ΕΊΕΌΔ…Ε›Ε›Ε›Ε›',
317 'email': 'goodmailm@test.plx',
317 'email': 'goodmailm@test.plx',
318 'firstname': 'test',
318 'firstname': 'test',
319 'lastname': 'test'
319 'lastname': 'test'
320 }
320 }
321 )
321 )
322
322
323 msg = validators.ValidPassword()._messages['invalid_password']
323 msg = validators.ValidPassword()._messages['invalid_password']
324 response.mustcontain(msg)
324 response.mustcontain(msg)
325
325
326 def test_register_password_mismatch(self):
326 def test_register_password_mismatch(self):
327 response = self.app.post(
327 response = self.app.post(
328 register_url,
328 register_url,
329 {
329 {
330 'username': 'xs',
330 'username': 'xs',
331 'password': '123qwe',
331 'password': '123qwe',
332 'password_confirmation': 'qwe123',
332 'password_confirmation': 'qwe123',
333 'email': 'goodmailm@test.plxa',
333 'email': 'goodmailm@test.plxa',
334 'firstname': 'test',
334 'firstname': 'test',
335 'lastname': 'test'
335 'lastname': 'test'
336 }
336 }
337 )
337 )
338 msg = validators.ValidPasswordsMatch()._messages['password_mismatch']
338 msg = validators.ValidPasswordsMatch()._messages['password_mismatch']
339 response.mustcontain(msg)
339 response.mustcontain(msg)
340
340
341 def test_register_ok(self):
341 def test_register_ok(self):
342 username = 'test_regular4'
342 username = 'test_regular4'
343 password = 'qweqwe'
343 password = 'qweqwe'
344 email = 'marcin@test.com'
344 email = 'marcin@test.com'
345 name = 'testname'
345 name = 'testname'
346 lastname = 'testlastname'
346 lastname = 'testlastname'
347
347
348 response = self.app.post(
348 response = self.app.post(
349 register_url,
349 register_url,
350 {
350 {
351 'username': username,
351 'username': username,
352 'password': password,
352 'password': password,
353 'password_confirmation': password,
353 'password_confirmation': password,
354 'email': email,
354 'email': email,
355 'firstname': name,
355 'firstname': name,
356 'lastname': lastname,
356 'lastname': lastname,
357 'admin': True
357 'admin': True
358 }
358 }
359 ) # This should be overriden
359 ) # This should be overriden
360 assert response.status == '302 Found'
360 assert response.status == '302 Found'
361 assert_session_flash(
361 assert_session_flash(
362 response, 'You have successfully registered with RhodeCode')
362 response, 'You have successfully registered with RhodeCode')
363
363
364 ret = Session().query(User).filter(
364 ret = Session().query(User).filter(
365 User.username == 'test_regular4').one()
365 User.username == 'test_regular4').one()
366 assert ret.username == username
366 assert ret.username == username
367 assert check_password(password, ret.password)
367 assert check_password(password, ret.password)
368 assert ret.email == email
368 assert ret.email == email
369 assert ret.name == name
369 assert ret.name == name
370 assert ret.lastname == lastname
370 assert ret.lastname == lastname
371 assert ret.api_key is not None
371 assert ret.api_key is not None
372 assert not ret.admin
372 assert not ret.admin
373
373
374 def test_forgot_password_wrong_mail(self):
374 def test_forgot_password_wrong_mail(self):
375 bad_email = 'marcin@wrongmail.org'
375 bad_email = 'marcin@wrongmail.org'
376 response = self.app.post(
376 response = self.app.post(
377 pwd_reset_url,
377 pwd_reset_url,
378 {'email': bad_email, }
378 {'email': bad_email, }
379 )
379 )
380
380
381 msg = validators.ValidSystemEmail()._messages['non_existing_email']
381 msg = validators.ValidSystemEmail()._messages['non_existing_email']
382 msg = h.html_escape(msg % {'email': bad_email})
382 msg = h.html_escape(msg % {'email': bad_email})
383 response.mustcontain()
383 response.mustcontain()
384
384
385 def test_forgot_password(self):
385 def test_forgot_password(self):
386 response = self.app.get(pwd_reset_url)
386 response = self.app.get(pwd_reset_url)
387 assert response.status == '200 OK'
387 assert response.status == '200 OK'
388
388
389 username = 'test_password_reset_1'
389 username = 'test_password_reset_1'
390 password = 'qweqwe'
390 password = 'qweqwe'
391 email = 'marcin@python-works.com'
391 email = 'marcin@python-works.com'
392 name = 'passwd'
392 name = 'passwd'
393 lastname = 'reset'
393 lastname = 'reset'
394
394
395 new = User()
395 new = User()
396 new.username = username
396 new.username = username
397 new.password = password
397 new.password = password
398 new.email = email
398 new.email = email
399 new.name = name
399 new.name = name
400 new.lastname = lastname
400 new.lastname = lastname
401 new.api_key = generate_auth_token(username)
401 new.api_key = generate_auth_token(username)
402 Session().add(new)
402 Session().add(new)
403 Session().commit()
403 Session().commit()
404
404
405 response = self.app.post(pwd_reset_url,
405 response = self.app.post(pwd_reset_url,
406 {'email': email, })
406 {'email': email, })
407
407
408 assert_session_flash(
408 assert_session_flash(
409 response, 'Your password reset link was sent')
409 response, 'Your password reset link was sent')
410
410
411 response = response.follow()
411 response = response.follow()
412
412
413 # BAD KEY
413 # BAD KEY
414
414
415 key = "bad"
415 key = "bad"
416 confirm_url = '{}?key={}'.format(pwd_reset_confirm_url, key)
416 confirm_url = '{}?key={}'.format(pwd_reset_confirm_url, key)
417 response = self.app.get(confirm_url)
417 response = self.app.get(confirm_url)
418 assert response.status == '302 Found'
418 assert response.status == '302 Found'
419 assert response.location.endswith(pwd_reset_url)
419 assert response.location.endswith(pwd_reset_url)
420
420
421 # GOOD KEY
421 # GOOD KEY
422
422
423 key = User.get_by_username(username).api_key
423 key = User.get_by_username(username).api_key
424 confirm_url = '{}?key={}'.format(pwd_reset_confirm_url, key)
424 confirm_url = '{}?key={}'.format(pwd_reset_confirm_url, key)
425 response = self.app.get(confirm_url)
425 response = self.app.get(confirm_url)
426 assert response.status == '302 Found'
426 assert response.status == '302 Found'
427 assert response.location.endswith(login_url)
427 assert response.location.endswith(login_url)
428
428
429 assert_session_flash(
429 assert_session_flash(
430 response,
430 response,
431 'Your password reset was successful, '
431 'Your password reset was successful, '
432 'a new password has been sent to your email')
432 'a new password has been sent to your email')
433
433
434 response = response.follow()
434 response = response.follow()
435
435
436 def _get_api_whitelist(self, values=None):
436 def _get_api_whitelist(self, values=None):
437 config = {'api_access_controllers_whitelist': values or []}
437 config = {'api_access_controllers_whitelist': values or []}
438 return config
438 return config
439
439
440 @pytest.mark.parametrize("test_name, auth_token", [
440 @pytest.mark.parametrize("test_name, auth_token", [
441 ('none', None),
441 ('none', None),
442 ('empty_string', ''),
442 ('empty_string', ''),
443 ('fake_number', '123456'),
443 ('fake_number', '123456'),
444 ('proper_auth_token', None)
444 ('proper_auth_token', None)
445 ])
445 ])
446 def test_access_not_whitelisted_page_via_auth_token(self, test_name,
446 def test_access_not_whitelisted_page_via_auth_token(self, test_name,
447 auth_token):
447 auth_token):
448 whitelist = self._get_api_whitelist([])
448 whitelist = self._get_api_whitelist([])
449 with mock.patch.dict('rhodecode.CONFIG', whitelist):
449 with mock.patch.dict('rhodecode.CONFIG', whitelist):
450 assert [] == whitelist['api_access_controllers_whitelist']
450 assert [] == whitelist['api_access_controllers_whitelist']
451 if test_name == 'proper_auth_token':
451 if test_name == 'proper_auth_token':
452 # use builtin if api_key is None
452 # use builtin if api_key is None
453 auth_token = User.get_first_super_admin().api_key
453 auth_token = User.get_first_super_admin().api_key
454
454
455 with fixture.anon_access(False):
455 with fixture.anon_access(False):
456 self.app.get(url(controller='changeset',
456 self.app.get(url(controller='changeset',
457 action='changeset_raw',
457 action='changeset_raw',
458 repo_name=HG_REPO, revision='tip',
458 repo_name=HG_REPO, revision='tip',
459 api_key=auth_token),
459 api_key=auth_token),
460 status=302)
460 status=302)
461
461
462 @pytest.mark.parametrize("test_name, auth_token, code", [
462 @pytest.mark.parametrize("test_name, auth_token, code", [
463 ('none', None, 302),
463 ('none', None, 302),
464 ('empty_string', '', 302),
464 ('empty_string', '', 302),
465 ('fake_number', '123456', 302),
465 ('fake_number', '123456', 302),
466 ('proper_auth_token', None, 200)
466 ('proper_auth_token', None, 200)
467 ])
467 ])
468 def test_access_whitelisted_page_via_auth_token(self, test_name,
468 def test_access_whitelisted_page_via_auth_token(self, test_name,
469 auth_token, code):
469 auth_token, code):
470 whitelist = self._get_api_whitelist(
470 whitelist = self._get_api_whitelist(
471 ['ChangesetController:changeset_raw'])
471 ['ChangesetController:changeset_raw'])
472 with mock.patch.dict('rhodecode.CONFIG', whitelist):
472 with mock.patch.dict('rhodecode.CONFIG', whitelist):
473 assert ['ChangesetController:changeset_raw'] == \
473 assert ['ChangesetController:changeset_raw'] == \
474 whitelist['api_access_controllers_whitelist']
474 whitelist['api_access_controllers_whitelist']
475 if test_name == 'proper_auth_token':
475 if test_name == 'proper_auth_token':
476 auth_token = User.get_first_super_admin().api_key
476 auth_token = User.get_first_super_admin().api_key
477
477
478 with fixture.anon_access(False):
478 with fixture.anon_access(False):
479 self.app.get(url(controller='changeset',
479 self.app.get(url(controller='changeset',
480 action='changeset_raw',
480 action='changeset_raw',
481 repo_name=HG_REPO, revision='tip',
481 repo_name=HG_REPO, revision='tip',
482 api_key=auth_token),
482 api_key=auth_token),
483 status=code)
483 status=code)
484
484
485 def test_access_page_via_extra_auth_token(self):
485 def test_access_page_via_extra_auth_token(self):
486 whitelist = self._get_api_whitelist(
486 whitelist = self._get_api_whitelist(
487 ['ChangesetController:changeset_raw'])
487 ['ChangesetController:changeset_raw'])
488 with mock.patch.dict('rhodecode.CONFIG', whitelist):
488 with mock.patch.dict('rhodecode.CONFIG', whitelist):
489 assert ['ChangesetController:changeset_raw'] == \
489 assert ['ChangesetController:changeset_raw'] == \
490 whitelist['api_access_controllers_whitelist']
490 whitelist['api_access_controllers_whitelist']
491
491
492 new_auth_token = AuthTokenModel().create(
492 new_auth_token = AuthTokenModel().create(
493 TEST_USER_ADMIN_LOGIN, 'test')
493 TEST_USER_ADMIN_LOGIN, 'test')
494 Session().commit()
494 Session().commit()
495 with fixture.anon_access(False):
495 with fixture.anon_access(False):
496 self.app.get(url(controller='changeset',
496 self.app.get(url(controller='changeset',
497 action='changeset_raw',
497 action='changeset_raw',
498 repo_name=HG_REPO, revision='tip',
498 repo_name=HG_REPO, revision='tip',
499 api_key=new_auth_token.api_key),
499 api_key=new_auth_token.api_key),
500 status=200)
500 status=200)
501
501
502 def test_access_page_via_expired_auth_token(self):
502 def test_access_page_via_expired_auth_token(self):
503 whitelist = self._get_api_whitelist(
503 whitelist = self._get_api_whitelist(
504 ['ChangesetController:changeset_raw'])
504 ['ChangesetController:changeset_raw'])
505 with mock.patch.dict('rhodecode.CONFIG', whitelist):
505 with mock.patch.dict('rhodecode.CONFIG', whitelist):
506 assert ['ChangesetController:changeset_raw'] == \
506 assert ['ChangesetController:changeset_raw'] == \
507 whitelist['api_access_controllers_whitelist']
507 whitelist['api_access_controllers_whitelist']
508
508
509 new_auth_token = AuthTokenModel().create(
509 new_auth_token = AuthTokenModel().create(
510 TEST_USER_ADMIN_LOGIN, 'test')
510 TEST_USER_ADMIN_LOGIN, 'test')
511 Session().commit()
511 Session().commit()
512 # patch the api key and make it expired
512 # patch the api key and make it expired
513 new_auth_token.expires = 0
513 new_auth_token.expires = 0
514 Session().add(new_auth_token)
514 Session().add(new_auth_token)
515 Session().commit()
515 Session().commit()
516 with fixture.anon_access(False):
516 with fixture.anon_access(False):
517 self.app.get(url(controller='changeset',
517 self.app.get(url(controller='changeset',
518 action='changeset_raw',
518 action='changeset_raw',
519 repo_name=HG_REPO, revision='tip',
519 repo_name=HG_REPO, revision='tip',
520 api_key=new_auth_token.api_key),
520 api_key=new_auth_token.api_key),
521 status=302)
521 status=302)
522
522
523
523
524 class TestPasswordReset(TestController):
524 class TestPasswordReset(TestController):
525
525
526 @pytest.mark.parametrize(
526 @pytest.mark.parametrize(
527 'pwd_reset_setting, show_link, show_reset', [
527 'pwd_reset_setting, show_link, show_reset', [
528 ('hg.password_reset.enabled', True, True),
528 ('hg.password_reset.enabled', True, True),
529 ('hg.password_reset.hidden', False, True),
529 ('hg.password_reset.hidden', False, True),
530 ('hg.password_reset.disabled', False, False),
530 ('hg.password_reset.disabled', False, False),
531 ])
531 ])
532 def test_password_reset_settings(
532 def test_password_reset_settings(
533 self, pwd_reset_setting, show_link, show_reset):
533 self, pwd_reset_setting, show_link, show_reset):
534 clear_all_caches()
534 clear_all_caches()
535 self.log_user(TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS)
535 self.log_user(TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS)
536 params = {
536 params = {
537 'csrf_token': self.csrf_token,
537 'csrf_token': self.csrf_token,
538 'anonymous': 'True',
538 'anonymous': 'True',
539 'default_register': 'hg.register.auto_activate',
539 'default_register': 'hg.register.auto_activate',
540 'default_register_message': '',
540 'default_register_message': '',
541 'default_password_reset': pwd_reset_setting,
541 'default_password_reset': pwd_reset_setting,
542 'default_extern_activate': 'hg.extern_activate.auto',
542 'default_extern_activate': 'hg.extern_activate.auto',
543 }
543 }
544 resp = self.app.post(url('admin_permissions_application'), params=params)
544 resp = self.app.post(url('admin_permissions_application'), params=params)
545 self.logout_user()
545 self.logout_user()
546
546
547 login_page = self.app.get(login_url)
547 login_page = self.app.get(login_url)
548 asr_login = AssertResponse(login_page)
548 asr_login = AssertResponse(login_page)
549 index_page = self.app.get(index_url)
549 index_page = self.app.get(index_url)
550 asr_index = AssertResponse(index_page)
550 asr_index = AssertResponse(index_page)
551
551
552 if show_link:
552 if show_link:
553 asr_login.one_element_exists('a.pwd_reset')
553 asr_login.one_element_exists('a.pwd_reset')
554 asr_index.one_element_exists('a.pwd_reset')
554 asr_index.one_element_exists('a.pwd_reset')
555 else:
555 else:
556 asr_login.no_element_exists('a.pwd_reset')
556 asr_login.no_element_exists('a.pwd_reset')
557 asr_index.no_element_exists('a.pwd_reset')
557 asr_index.no_element_exists('a.pwd_reset')
558
558
559 pwdreset_page = self.app.get(pwd_reset_url)
559 pwdreset_page = self.app.get(pwd_reset_url)
560
560
561 asr_reset = AssertResponse(pwdreset_page)
561 asr_reset = AssertResponse(pwdreset_page)
562 if show_reset:
562 if show_reset:
563 assert 'Send password reset email' in pwdreset_page
563 assert 'Send password reset email' in pwdreset_page
564 asr_reset.one_element_exists('#email')
564 asr_reset.one_element_exists('#email')
565 asr_reset.one_element_exists('#send')
565 asr_reset.one_element_exists('#send')
566 else:
566 else:
567 assert 'Password reset has been disabled.' in pwdreset_page
567 assert 'Password reset is disabled.' in pwdreset_page
568 asr_reset.no_element_exists('#email')
568 asr_reset.no_element_exists('#email')
569 asr_reset.no_element_exists('#send')
569 asr_reset.no_element_exists('#send')
570
570
571 def test_password_form_disabled(self):
571 def test_password_form_disabled(self):
572 self.log_user(TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS)
572 self.log_user(TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS)
573 params = {
573 params = {
574 'csrf_token': self.csrf_token,
574 'csrf_token': self.csrf_token,
575 'anonymous': 'True',
575 'anonymous': 'True',
576 'default_register': 'hg.register.auto_activate',
576 'default_register': 'hg.register.auto_activate',
577 'default_register_message': '',
577 'default_register_message': '',
578 'default_password_reset': 'hg.password_reset.disabled',
578 'default_password_reset': 'hg.password_reset.disabled',
579 'default_extern_activate': 'hg.extern_activate.auto',
579 'default_extern_activate': 'hg.extern_activate.auto',
580 }
580 }
581 self.app.post(url('admin_permissions_application'), params=params)
581 self.app.post(url('admin_permissions_application'), params=params)
582 self.logout_user()
582 self.logout_user()
583
583
584 pwdreset_page = self.app.post(
584 pwdreset_page = self.app.post(
585 pwd_reset_url,
585 pwd_reset_url,
586 {'email': 'lisa@rhodecode.com',}
586 {'email': 'lisa@rhodecode.com',}
587 )
587 )
588 assert 'Password reset has been disabled.' in pwdreset_page
588 assert 'Password reset is disabled.' in pwdreset_page
General Comments 0
You need to be logged in to leave comments. Login now