##// END OF EJS Templates
permissions: Fix permissions for authentication plugin settings view.
Martin Bornhold -
r173:b542bf08 stable
parent child Browse files
Show More
@@ -1,182 +1,188 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2012-2016 RhodeCode GmbH
3 # Copyright (C) 2012-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 colander
21 import colander
22 import formencode.htmlfill
22 import formencode.htmlfill
23 import logging
23 import logging
24
24
25 from pyramid.httpexceptions import HTTPFound
25 from pyramid.httpexceptions import HTTPFound
26 from pyramid.renderers import render
26 from pyramid.renderers import render
27 from pyramid.response import Response
27 from pyramid.response import Response
28
28
29 from rhodecode.authentication.base import get_auth_cache_manager
29 from rhodecode.authentication.base import get_auth_cache_manager
30 from rhodecode.authentication.interface import IAuthnPluginRegistry
30 from rhodecode.authentication.interface import IAuthnPluginRegistry
31 from rhodecode.lib import auth
31 from rhodecode.lib import auth
32 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
32 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
33 from rhodecode.model.forms import AuthSettingsForm
33 from rhodecode.model.forms import AuthSettingsForm
34 from rhodecode.model.meta import Session
34 from rhodecode.model.meta import Session
35 from rhodecode.model.settings import SettingsModel
35 from rhodecode.model.settings import SettingsModel
36 from rhodecode.translation import _
36 from rhodecode.translation import _
37
37
38 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
39
39
40
40
41 class AuthnPluginViewBase(object):
41 class AuthnPluginViewBase(object):
42
42
43 def __init__(self, context, request):
43 def __init__(self, context, request):
44 self.request = request
44 self.request = request
45 self.context = context
45 self.context = context
46 self.plugin = context.plugin
46 self.plugin = context.plugin
47 self._rhodecode_user = request.user
47
48
49 @LoginRequired()
50 @HasPermissionAllDecorator('hg.admin')
48 def settings_get(self, defaults=None, errors=None):
51 def settings_get(self, defaults=None, errors=None):
49 """
52 """
50 View that displays the plugin settings as a form.
53 View that displays the plugin settings as a form.
51 """
54 """
52 defaults = defaults or {}
55 defaults = defaults or {}
53 errors = errors or {}
56 errors = errors or {}
54 schema = self.plugin.get_settings_schema()
57 schema = self.plugin.get_settings_schema()
55
58
56 # Get default values for the form.
59 # Get default values for the form.
57 for node in schema:
60 for node in schema:
58 db_value = self.plugin.get_setting_by_name(node.name)
61 db_value = self.plugin.get_setting_by_name(node.name)
59 defaults.setdefault(node.name, db_value)
62 defaults.setdefault(node.name, db_value)
60
63
61 template_context = {
64 template_context = {
62 'defaults': defaults,
65 'defaults': defaults,
63 'errors': errors,
66 'errors': errors,
64 'plugin': self.context.plugin,
67 'plugin': self.context.plugin,
65 'resource': self.context,
68 'resource': self.context,
66 }
69 }
67
70
68 return template_context
71 return template_context
69
72
73 @LoginRequired()
74 @HasPermissionAllDecorator('hg.admin')
75 @auth.CSRFRequired()
70 def settings_post(self):
76 def settings_post(self):
71 """
77 """
72 View that validates and stores the plugin settings.
78 View that validates and stores the plugin settings.
73 """
79 """
74 schema = self.plugin.get_settings_schema()
80 schema = self.plugin.get_settings_schema()
75 try:
81 try:
76 valid_data = schema.deserialize(self.request.params)
82 valid_data = schema.deserialize(self.request.params)
77 except colander.Invalid, e:
83 except colander.Invalid, e:
78 # Display error message and display form again.
84 # Display error message and display form again.
79 self.request.session.flash(
85 self.request.session.flash(
80 _('Errors exist when saving plugin settings. '
86 _('Errors exist when saving plugin settings. '
81 'Please check the form inputs.'),
87 'Please check the form inputs.'),
82 queue='error')
88 queue='error')
83 defaults = schema.flatten(self.request.params)
89 defaults = schema.flatten(self.request.params)
84 return self.settings_get(errors=e.asdict(), defaults=defaults)
90 return self.settings_get(errors=e.asdict(), defaults=defaults)
85
91
86 # Store validated data.
92 # Store validated data.
87 for name, value in valid_data.items():
93 for name, value in valid_data.items():
88 self.plugin.create_or_update_setting(name, value)
94 self.plugin.create_or_update_setting(name, value)
89 Session.commit()
95 Session.commit()
90
96
91 # Display success message and redirect.
97 # Display success message and redirect.
92 self.request.session.flash(
98 self.request.session.flash(
93 _('Auth settings updated successfully.'),
99 _('Auth settings updated successfully.'),
94 queue='success')
100 queue='success')
95 redirect_to = self.request.resource_path(
101 redirect_to = self.request.resource_path(
96 self.context, route_name='auth_home')
102 self.context, route_name='auth_home')
97 return HTTPFound(redirect_to)
103 return HTTPFound(redirect_to)
98
104
99
105
100 # TODO: Ongoing migration in these views.
106 # TODO: Ongoing migration in these views.
101 # - Maybe we should also use a colander schema for these views.
107 # - Maybe we should also use a colander schema for these views.
102 class AuthSettingsView(object):
108 class AuthSettingsView(object):
103 def __init__(self, context, request):
109 def __init__(self, context, request):
104 self.context = context
110 self.context = context
105 self.request = request
111 self.request = request
106
112
107 # TODO: Move this into a utility function. It is needed in all view
113 # TODO: Move this into a utility function. It is needed in all view
108 # classes during migration. Maybe a mixin?
114 # classes during migration. Maybe a mixin?
109
115
110 # Some of the decorators rely on this attribute to be present on the
116 # Some of the decorators rely on this attribute to be present on the
111 # class of the decorated method.
117 # class of the decorated method.
112 self._rhodecode_user = request.user
118 self._rhodecode_user = request.user
113
119
114 @LoginRequired()
120 @LoginRequired()
115 @HasPermissionAllDecorator('hg.admin')
121 @HasPermissionAllDecorator('hg.admin')
116 def index(self, defaults=None, errors=None, prefix_error=False):
122 def index(self, defaults=None, errors=None, prefix_error=False):
117 defaults = defaults or {}
123 defaults = defaults or {}
118 authn_registry = self.request.registry.getUtility(IAuthnPluginRegistry)
124 authn_registry = self.request.registry.getUtility(IAuthnPluginRegistry)
119 enabled_plugins = SettingsModel().get_auth_plugins()
125 enabled_plugins = SettingsModel().get_auth_plugins()
120
126
121 # Create template context and render it.
127 # Create template context and render it.
122 template_context = {
128 template_context = {
123 'resource': self.context,
129 'resource': self.context,
124 'available_plugins': authn_registry.get_plugins(),
130 'available_plugins': authn_registry.get_plugins(),
125 'enabled_plugins': enabled_plugins,
131 'enabled_plugins': enabled_plugins,
126 }
132 }
127 html = render('rhodecode:templates/admin/auth/auth_settings.html',
133 html = render('rhodecode:templates/admin/auth/auth_settings.html',
128 template_context,
134 template_context,
129 request=self.request)
135 request=self.request)
130
136
131 # Create form default values and fill the form.
137 # Create form default values and fill the form.
132 form_defaults = {
138 form_defaults = {
133 'auth_plugins': ','.join(enabled_plugins)
139 'auth_plugins': ','.join(enabled_plugins)
134 }
140 }
135 form_defaults.update(defaults)
141 form_defaults.update(defaults)
136 html = formencode.htmlfill.render(
142 html = formencode.htmlfill.render(
137 html,
143 html,
138 defaults=form_defaults,
144 defaults=form_defaults,
139 errors=errors,
145 errors=errors,
140 prefix_error=prefix_error,
146 prefix_error=prefix_error,
141 encoding="UTF-8",
147 encoding="UTF-8",
142 force_defaults=False)
148 force_defaults=False)
143
149
144 return Response(html)
150 return Response(html)
145
151
146 @LoginRequired()
152 @LoginRequired()
147 @HasPermissionAllDecorator('hg.admin')
153 @HasPermissionAllDecorator('hg.admin')
148 @auth.CSRFRequired()
154 @auth.CSRFRequired()
149 def auth_settings(self):
155 def auth_settings(self):
150 try:
156 try:
151 form = AuthSettingsForm()()
157 form = AuthSettingsForm()()
152 form_result = form.to_python(self.request.params)
158 form_result = form.to_python(self.request.params)
153 plugins = ','.join(form_result['auth_plugins'])
159 plugins = ','.join(form_result['auth_plugins'])
154 setting = SettingsModel().create_or_update_setting(
160 setting = SettingsModel().create_or_update_setting(
155 'auth_plugins', plugins)
161 'auth_plugins', plugins)
156 Session().add(setting)
162 Session().add(setting)
157 Session().commit()
163 Session().commit()
158
164
159 cache_manager = get_auth_cache_manager()
165 cache_manager = get_auth_cache_manager()
160 cache_manager.clear()
166 cache_manager.clear()
161 self.request.session.flash(
167 self.request.session.flash(
162 _('Auth settings updated successfully.'),
168 _('Auth settings updated successfully.'),
163 queue='success')
169 queue='success')
164 except formencode.Invalid as errors:
170 except formencode.Invalid as errors:
165 e = errors.error_dict or {}
171 e = errors.error_dict or {}
166 self.request.session.flash(
172 self.request.session.flash(
167 _('Errors exist when saving plugin setting. '
173 _('Errors exist when saving plugin setting. '
168 'Please check the form inputs.'),
174 'Please check the form inputs.'),
169 queue='error')
175 queue='error')
170 return self.index(
176 return self.index(
171 defaults=errors.value,
177 defaults=errors.value,
172 errors=e,
178 errors=e,
173 prefix_error=False)
179 prefix_error=False)
174 except Exception:
180 except Exception:
175 log.exception('Exception in auth_settings')
181 log.exception('Exception in auth_settings')
176 self.request.session.flash(
182 self.request.session.flash(
177 _('Error occurred during update of auth settings.'),
183 _('Error occurred during update of auth settings.'),
178 queue='error')
184 queue='error')
179
185
180 redirect_to = self.request.resource_path(
186 redirect_to = self.request.resource_path(
181 self.context, route_name='auth_home')
187 self.context, route_name='auth_home')
182 return HTTPFound(redirect_to)
188 return HTTPFound(redirect_to)
@@ -1,337 +1,339 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2016 RhodeCode GmbH
3 # Copyright (C) 2016-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 datetime
21 import datetime
22 import formencode
22 import formencode
23 import logging
23 import logging
24 import urlparse
24 import urlparse
25
25
26 from pylons import url
26 from pylons import url
27 from pyramid.httpexceptions import HTTPFound
27 from pyramid.httpexceptions import HTTPFound
28 from pyramid.view import view_config
28 from pyramid.view import view_config
29 from recaptcha.client.captcha import submit
29 from recaptcha.client.captcha import submit
30
30
31 from rhodecode.authentication.base import authenticate, HTTP_TYPE
31 from rhodecode.authentication.base import authenticate, HTTP_TYPE
32 from rhodecode.events import UserRegistered
32 from rhodecode.events import UserRegistered
33 from rhodecode.lib.auth import (
33 from rhodecode.lib.auth import (
34 AuthUser, HasPermissionAnyDecorator, CSRFRequired)
34 AuthUser, HasPermissionAnyDecorator, CSRFRequired)
35 from rhodecode.lib.base import get_ip_addr
35 from rhodecode.lib.base import get_ip_addr
36 from rhodecode.lib.exceptions import UserCreationError
36 from rhodecode.lib.exceptions import UserCreationError
37 from rhodecode.lib.utils2 import safe_str
37 from rhodecode.lib.utils2 import safe_str
38 from rhodecode.model.db import User
38 from rhodecode.model.db import User
39 from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm
39 from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm
40 from rhodecode.model.login_session import LoginSession
40 from rhodecode.model.login_session import LoginSession
41 from rhodecode.model.meta import Session
41 from rhodecode.model.meta import Session
42 from rhodecode.model.settings import SettingsModel
42 from rhodecode.model.settings import SettingsModel
43 from rhodecode.model.user import UserModel
43 from rhodecode.model.user import UserModel
44 from rhodecode.translation import _
44 from rhodecode.translation import _
45
45
46
46
47 log = logging.getLogger(__name__)
47 log = logging.getLogger(__name__)
48
48
49
49
50 def _store_user_in_session(session, username, remember=False):
50 def _store_user_in_session(session, username, remember=False):
51 user = User.get_by_username(username, case_insensitive=True)
51 user = User.get_by_username(username, case_insensitive=True)
52 auth_user = AuthUser(user.user_id)
52 auth_user = AuthUser(user.user_id)
53 auth_user.set_authenticated()
53 auth_user.set_authenticated()
54 cs = auth_user.get_cookie_store()
54 cs = auth_user.get_cookie_store()
55 session['rhodecode_user'] = cs
55 session['rhodecode_user'] = cs
56 user.update_lastlogin()
56 user.update_lastlogin()
57 Session().commit()
57 Session().commit()
58
58
59 # If they want to be remembered, update the cookie
59 # If they want to be remembered, update the cookie
60 if remember:
60 if remember:
61 _year = (datetime.datetime.now() +
61 _year = (datetime.datetime.now() +
62 datetime.timedelta(seconds=60 * 60 * 24 * 365))
62 datetime.timedelta(seconds=60 * 60 * 24 * 365))
63 session._set_cookie_expires(_year)
63 session._set_cookie_expires(_year)
64
64
65 session.save()
65 session.save()
66
66
67 log.info('user %s is now authenticated and stored in '
67 log.info('user %s is now authenticated and stored in '
68 'session, session attrs %s', username, cs)
68 'session, session attrs %s', username, cs)
69
69
70 # dumps session attrs back to cookie
70 # dumps session attrs back to cookie
71 session._update_cookie_out()
71 session._update_cookie_out()
72 # we set new cookie
72 # we set new cookie
73 headers = None
73 headers = None
74 if session.request['set_cookie']:
74 if session.request['set_cookie']:
75 # send set-cookie headers back to response to update cookie
75 # send set-cookie headers back to response to update cookie
76 headers = [('Set-Cookie', session.request['cookie_out'])]
76 headers = [('Set-Cookie', session.request['cookie_out'])]
77 return headers
77 return headers
78
78
79
79
80 def get_came_from(request):
80 def get_came_from(request):
81 came_from = safe_str(request.GET.get('came_from', ''))
81 came_from = safe_str(request.GET.get('came_from', ''))
82 parsed = urlparse.urlparse(came_from)
82 parsed = urlparse.urlparse(came_from)
83 allowed_schemes = ['http', 'https']
83 allowed_schemes = ['http', 'https']
84 if parsed.scheme and parsed.scheme not in allowed_schemes:
84 if parsed.scheme and parsed.scheme not in allowed_schemes:
85 log.error('Suspicious URL scheme detected %s for url %s' %
85 log.error('Suspicious URL scheme detected %s for url %s' %
86 (parsed.scheme, parsed))
86 (parsed.scheme, parsed))
87 came_from = url('home')
87 came_from = url('home')
88 elif parsed.netloc and request.host != parsed.netloc:
88 elif parsed.netloc and request.host != parsed.netloc:
89 log.error('Suspicious NETLOC detected %s for url %s server url '
89 log.error('Suspicious NETLOC detected %s for url %s server url '
90 'is: %s' % (parsed.netloc, parsed, request.host))
90 'is: %s' % (parsed.netloc, parsed, request.host))
91 came_from = url('home')
91 came_from = url('home')
92 elif any(bad_str in parsed.path for bad_str in ('\r', '\n')):
92 elif any(bad_str in parsed.path for bad_str in ('\r', '\n')):
93 log.error('Header injection detected `%s` for url %s server url ' %
93 log.error('Header injection detected `%s` for url %s server url ' %
94 (parsed.path, parsed))
94 (parsed.path, parsed))
95 came_from = url('home')
95 came_from = url('home')
96
96
97 return came_from or url('home')
97 return came_from or url('home')
98
98
99
99
100 class LoginView(object):
100 class LoginView(object):
101
101
102 def __init__(self, context, request):
102 def __init__(self, context, request):
103 self.request = request
103 self.request = request
104 self.context = context
104 self.context = context
105 self.session = request.session
105 self.session = request.session
106 self._rhodecode_user = request.user
106 self._rhodecode_user = request.user
107
107
108 def _get_template_context(self):
108 def _get_template_context(self):
109 return {
109 return {
110 'came_from': get_came_from(self.request),
110 'came_from': get_came_from(self.request),
111 'defaults': {},
111 'defaults': {},
112 'errors': {},
112 'errors': {},
113 }
113 }
114
114
115 @view_config(
115 @view_config(
116 route_name='login', request_method='GET',
116 route_name='login', request_method='GET',
117 renderer='rhodecode:templates/login.html')
117 renderer='rhodecode:templates/login.html')
118 def login(self):
118 def login(self):
119 came_from = get_came_from(self.request)
119 came_from = get_came_from(self.request)
120 user = self.request.user
120 user = self.request.user
121
121
122 # redirect if already logged in
122 # redirect if already logged in
123 if user.is_authenticated and not user.is_default and user.ip_allowed:
123 if user.is_authenticated and not user.is_default and user.ip_allowed:
124 raise HTTPFound(came_from)
124 raise HTTPFound(came_from)
125
125
126 # check if we use headers plugin, and try to login using it.
126 # check if we use headers plugin, and try to login using it.
127 try:
127 try:
128 log.debug('Running PRE-AUTH for headers based authentication')
128 log.debug('Running PRE-AUTH for headers based authentication')
129 auth_info = authenticate(
129 auth_info = authenticate(
130 '', '', self.request.environ, HTTP_TYPE, skip_missing=True)
130 '', '', self.request.environ, HTTP_TYPE, skip_missing=True)
131 if auth_info:
131 if auth_info:
132 headers = _store_user_in_session(
132 headers = _store_user_in_session(
133 self.session, auth_info.get('username'))
133 self.session, auth_info.get('username'))
134 raise HTTPFound(came_from, headers=headers)
134 raise HTTPFound(came_from, headers=headers)
135 except UserCreationError as e:
135 except UserCreationError as e:
136 log.error(e)
136 log.error(e)
137 self.session.flash(e, queue='error')
137 self.session.flash(e, queue='error')
138
138
139 return self._get_template_context()
139 return self._get_template_context()
140
140
141 @view_config(
141 @view_config(
142 route_name='login', request_method='POST',
142 route_name='login', request_method='POST',
143 renderer='rhodecode:templates/login.html')
143 renderer='rhodecode:templates/login.html')
144 def login_post(self):
144 def login_post(self):
145 came_from = get_came_from(self.request)
145 came_from = get_came_from(self.request)
146 session = self.request.session
146 session = self.request.session
147 login_form = LoginForm()()
147 login_form = LoginForm()()
148
148
149 try:
149 try:
150 session.invalidate()
150 session.invalidate()
151 form_result = login_form.to_python(self.request.params)
151 form_result = login_form.to_python(self.request.params)
152 # form checks for username/password, now we're authenticated
152 # form checks for username/password, now we're authenticated
153 headers = _store_user_in_session(
153 headers = _store_user_in_session(
154 self.session,
154 self.session,
155 username=form_result['username'],
155 username=form_result['username'],
156 remember=form_result['remember'])
156 remember=form_result['remember'])
157 raise HTTPFound(came_from, headers=headers)
157 raise HTTPFound(came_from, headers=headers)
158 except formencode.Invalid as errors:
158 except formencode.Invalid as errors:
159 defaults = errors.value
159 defaults = errors.value
160 # remove password from filling in form again
160 # remove password from filling in form again
161 del defaults['password']
161 del defaults['password']
162 render_ctx = self._get_template_context()
162 render_ctx = self._get_template_context()
163 render_ctx.update({
163 render_ctx.update({
164 'errors': errors.error_dict,
164 'errors': errors.error_dict,
165 'defaults': defaults,
165 'defaults': defaults,
166 })
166 })
167 return render_ctx
167 return render_ctx
168
168
169 except UserCreationError as e:
169 except UserCreationError as e:
170 # headers auth or other auth functions that create users on
170 # headers auth or other auth functions that create users on
171 # the fly can throw this exception signaling that there's issue
171 # the fly can throw this exception signaling that there's issue
172 # with user creation, explanation should be provided in
172 # with user creation, explanation should be provided in
173 # Exception itself
173 # Exception itself
174 session.flash(e, queue='error')
174 session.flash(e, queue='error')
175 return self._get_template_context()
175 return self._get_template_context()
176
176
177 @CSRFRequired()
177 @CSRFRequired()
178 @view_config(route_name='logout', request_method='POST')
178 @view_config(route_name='logout', request_method='POST')
179 def logout(self):
179 def logout(self):
180 LoginSession().destroy_user_session()
180 LoginSession().destroy_user_session()
181 return HTTPFound(url('home'))
181 return HTTPFound(url('home'))
182
182
183 @HasPermissionAnyDecorator(
183 @HasPermissionAnyDecorator(
184 'hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')
184 'hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')
185 @view_config(
185 @view_config(
186 route_name='register', request_method='GET',
186 route_name='register', request_method='GET',
187 renderer='rhodecode:templates/register.html',)
187 renderer='rhodecode:templates/register.html',)
188 def register(self, defaults=None, errors=None):
188 def register(self, defaults=None, errors=None):
189 defaults = defaults or {}
189 defaults = defaults or {}
190 errors = errors or {}
190 errors = errors or {}
191
191
192 settings = SettingsModel().get_all_settings()
192 settings = SettingsModel().get_all_settings()
193 captcha_public_key = settings.get('rhodecode_captcha_public_key')
193 captcha_public_key = settings.get('rhodecode_captcha_public_key')
194 captcha_private_key = settings.get('rhodecode_captcha_private_key')
194 captcha_private_key = settings.get('rhodecode_captcha_private_key')
195 captcha_active = bool(captcha_private_key)
195 captcha_active = bool(captcha_private_key)
196 register_message = settings.get('rhodecode_register_message') or ''
196 register_message = settings.get('rhodecode_register_message') or ''
197 auto_active = 'hg.register.auto_activate' in User.get_default_user()\
197 auto_active = 'hg.register.auto_activate' in User.get_default_user()\
198 .AuthUser.permissions['global']
198 .AuthUser.permissions['global']
199
199
200 render_ctx = self._get_template_context()
200 render_ctx = self._get_template_context()
201 render_ctx.update({
201 render_ctx.update({
202 'defaults': defaults,
202 'defaults': defaults,
203 'errors': errors,
203 'errors': errors,
204 'auto_active': auto_active,
204 'auto_active': auto_active,
205 'captcha_active': captcha_active,
205 'captcha_active': captcha_active,
206 'captcha_public_key': captcha_public_key,
206 'captcha_public_key': captcha_public_key,
207 'register_message': register_message,
207 'register_message': register_message,
208 })
208 })
209 return render_ctx
209 return render_ctx
210
210
211 @HasPermissionAnyDecorator(
212 'hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')
211 @view_config(
213 @view_config(
212 route_name='register', request_method='POST',
214 route_name='register', request_method='POST',
213 renderer='rhodecode:templates/register.html')
215 renderer='rhodecode:templates/register.html')
214 def register_post(self):
216 def register_post(self):
215 captcha_private_key = SettingsModel().get_setting_by_name(
217 captcha_private_key = SettingsModel().get_setting_by_name(
216 'rhodecode_captcha_private_key')
218 'rhodecode_captcha_private_key')
217 captcha_active = bool(captcha_private_key)
219 captcha_active = bool(captcha_private_key)
218 auto_active = 'hg.register.auto_activate' in User.get_default_user()\
220 auto_active = 'hg.register.auto_activate' in User.get_default_user()\
219 .AuthUser.permissions['global']
221 .AuthUser.permissions['global']
220
222
221 register_form = RegisterForm()()
223 register_form = RegisterForm()()
222 try:
224 try:
223 form_result = register_form.to_python(self.request.params)
225 form_result = register_form.to_python(self.request.params)
224 form_result['active'] = auto_active
226 form_result['active'] = auto_active
225
227
226 if captcha_active:
228 if captcha_active:
227 response = submit(
229 response = submit(
228 self.request.params.get('recaptcha_challenge_field'),
230 self.request.params.get('recaptcha_challenge_field'),
229 self.request.params.get('recaptcha_response_field'),
231 self.request.params.get('recaptcha_response_field'),
230 private_key=captcha_private_key,
232 private_key=captcha_private_key,
231 remoteip=get_ip_addr(self.request.environ))
233 remoteip=get_ip_addr(self.request.environ))
232 if captcha_active and not response.is_valid:
234 if captcha_active and not response.is_valid:
233 _value = form_result
235 _value = form_result
234 _msg = _('bad captcha')
236 _msg = _('bad captcha')
235 error_dict = {'recaptcha_field': _msg}
237 error_dict = {'recaptcha_field': _msg}
236 raise formencode.Invalid(_msg, _value, None,
238 raise formencode.Invalid(_msg, _value, None,
237 error_dict=error_dict)
239 error_dict=error_dict)
238
240
239 new_user = UserModel().create_registration(form_result)
241 new_user = UserModel().create_registration(form_result)
240 event = UserRegistered(user=new_user, session=self.session)
242 event = UserRegistered(user=new_user, session=self.session)
241 self.request.registry.notify(event)
243 self.request.registry.notify(event)
242 self.session.flash(
244 self.session.flash(
243 _('You have successfully registered with RhodeCode'),
245 _('You have successfully registered with RhodeCode'),
244 queue='success')
246 queue='success')
245 Session().commit()
247 Session().commit()
246
248
247 redirect_ro = self.request.route_path('login')
249 redirect_ro = self.request.route_path('login')
248 raise HTTPFound(redirect_ro)
250 raise HTTPFound(redirect_ro)
249
251
250 except formencode.Invalid as errors:
252 except formencode.Invalid as errors:
251 del errors.value['password']
253 del errors.value['password']
252 del errors.value['password_confirmation']
254 del errors.value['password_confirmation']
253 return self.register(
255 return self.register(
254 defaults=errors.value, errors=errors.error_dict)
256 defaults=errors.value, errors=errors.error_dict)
255
257
256 except UserCreationError as e:
258 except UserCreationError as e:
257 # container auth or other auth functions that create users on
259 # container auth or other auth functions that create users on
258 # the fly can throw this exception signaling that there's issue
260 # the fly can throw this exception signaling that there's issue
259 # with user creation, explanation should be provided in
261 # with user creation, explanation should be provided in
260 # Exception itself
262 # Exception itself
261 self.session.flash(e, queue='error')
263 self.session.flash(e, queue='error')
262 return self.register()
264 return self.register()
263
265
264 @view_config(
266 @view_config(
265 route_name='reset_password', request_method=('GET', 'POST'),
267 route_name='reset_password', request_method=('GET', 'POST'),
266 renderer='rhodecode:templates/password_reset.html')
268 renderer='rhodecode:templates/password_reset.html')
267 def password_reset(self):
269 def password_reset(self):
268 settings = SettingsModel().get_all_settings()
270 settings = SettingsModel().get_all_settings()
269 captcha_private_key = settings.get('rhodecode_captcha_private_key')
271 captcha_private_key = settings.get('rhodecode_captcha_private_key')
270 captcha_active = bool(captcha_private_key)
272 captcha_active = bool(captcha_private_key)
271 captcha_public_key = settings.get('rhodecode_captcha_public_key')
273 captcha_public_key = settings.get('rhodecode_captcha_public_key')
272
274
273 render_ctx = {
275 render_ctx = {
274 'captcha_active': captcha_active,
276 'captcha_active': captcha_active,
275 'captcha_public_key': captcha_public_key,
277 'captcha_public_key': captcha_public_key,
276 'defaults': {},
278 'defaults': {},
277 'errors': {},
279 'errors': {},
278 }
280 }
279
281
280 if self.request.POST:
282 if self.request.POST:
281 password_reset_form = PasswordResetForm()()
283 password_reset_form = PasswordResetForm()()
282 try:
284 try:
283 form_result = password_reset_form.to_python(
285 form_result = password_reset_form.to_python(
284 self.request.params)
286 self.request.params)
285 if captcha_active:
287 if captcha_active:
286 response = submit(
288 response = submit(
287 self.request.params.get('recaptcha_challenge_field'),
289 self.request.params.get('recaptcha_challenge_field'),
288 self.request.params.get('recaptcha_response_field'),
290 self.request.params.get('recaptcha_response_field'),
289 private_key=captcha_private_key,
291 private_key=captcha_private_key,
290 remoteip=get_ip_addr(self.request.environ))
292 remoteip=get_ip_addr(self.request.environ))
291 if captcha_active and not response.is_valid:
293 if captcha_active and not response.is_valid:
292 _value = form_result
294 _value = form_result
293 _msg = _('bad captcha')
295 _msg = _('bad captcha')
294 error_dict = {'recaptcha_field': _msg}
296 error_dict = {'recaptcha_field': _msg}
295 raise formencode.Invalid(_msg, _value, None,
297 raise formencode.Invalid(_msg, _value, None,
296 error_dict=error_dict)
298 error_dict=error_dict)
297
299
298 # Generate reset URL and send mail.
300 # Generate reset URL and send mail.
299 user_email = form_result['email']
301 user_email = form_result['email']
300 user = User.get_by_email(user_email)
302 user = User.get_by_email(user_email)
301 password_reset_url = self.request.route_url(
303 password_reset_url = self.request.route_url(
302 'reset_password_confirmation',
304 'reset_password_confirmation',
303 _query={'key': user.api_key})
305 _query={'key': user.api_key})
304 UserModel().reset_password_link(
306 UserModel().reset_password_link(
305 form_result, password_reset_url)
307 form_result, password_reset_url)
306
308
307 # Display success message and redirect.
309 # Display success message and redirect.
308 self.session.flash(
310 self.session.flash(
309 _('Your password reset link was sent'),
311 _('Your password reset link was sent'),
310 queue='success')
312 queue='success')
311 return HTTPFound(self.request.route_path('login'))
313 return HTTPFound(self.request.route_path('login'))
312
314
313 except formencode.Invalid as errors:
315 except formencode.Invalid as errors:
314 render_ctx.update({
316 render_ctx.update({
315 'defaults': errors.value,
317 'defaults': errors.value,
316 'errors': errors.error_dict,
318 'errors': errors.error_dict,
317 })
319 })
318
320
319 return render_ctx
321 return render_ctx
320
322
321 @view_config(route_name='reset_password_confirmation',
323 @view_config(route_name='reset_password_confirmation',
322 request_method='GET')
324 request_method='GET')
323 def password_reset_confirmation(self):
325 def password_reset_confirmation(self):
324 if self.request.GET and self.request.GET.get('key'):
326 if self.request.GET and self.request.GET.get('key'):
325 try:
327 try:
326 user = User.get_by_auth_token(self.request.GET.get('key'))
328 user = User.get_by_auth_token(self.request.GET.get('key'))
327 data = {'email': user.email}
329 data = {'email': user.email}
328 UserModel().reset_password(data)
330 UserModel().reset_password(data)
329 self.session.flash(
331 self.session.flash(
330 _('Your password reset was successful, '
332 _('Your password reset was successful, '
331 'a new password has been sent to your email'),
333 'a new password has been sent to your email'),
332 queue='success')
334 queue='success')
333 except Exception as e:
335 except Exception as e:
334 log.error(e)
336 log.error(e)
335 return HTTPFound(self.request.route_path('reset_password'))
337 return HTTPFound(self.request.route_path('reset_password'))
336
338
337 return HTTPFound(self.request.route_path('login'))
339 return HTTPFound(self.request.route_path('login'))
General Comments 0
You need to be logged in to leave comments. Login now