##// END OF EJS Templates
i18n: Use new translation string factory....
johbo -
r51:2ebf8ced default
parent child Browse files
Show More
@@ -1,151 +1,150 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2012-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import logging
22 22
23 23 from pyramid.exceptions import ConfigurationError
24 from pyramid.i18n import TranslationStringFactory
25 24
26 25 from rhodecode.lib.utils2 import safe_str
27 26 from rhodecode.model.settings import SettingsModel
27 from rhodecode.translation import _
28 28
29 _ = TranslationStringFactory('rhodecode-enterprise')
30 29
31 30 log = logging.getLogger(__name__)
32 31
33 32
34 33 class AuthnResourceBase(object):
35 34 __name__ = None
36 35 __parent__ = None
37 36
38 37 def get_root(self):
39 38 current = self
40 39 while current.__parent__ is not None:
41 40 current = current.__parent__
42 41 return current
43 42
44 43
45 44 class AuthnPluginResourceBase(AuthnResourceBase):
46 45
47 46 def __init__(self, plugin):
48 47 self.plugin = plugin
49 48 self.__name__ = plugin.name
50 49 self.display_name = plugin.get_display_name()
51 50
52 51
53 52 class AuthnRootResource(AuthnResourceBase):
54 53 """
55 54 This is the root traversal resource object for the authentication settings.
56 55 """
57 56
58 57 def __init__(self):
59 58 self._store = {}
60 59 self._resource_name_map = {}
61 60 self.display_name = _('Global')
62 61
63 62 def __getitem__(self, key):
64 63 """
65 64 Customized get item function to return only items (plugins) that are
66 65 activated.
67 66 """
68 67 if self._is_item_active(key):
69 68 return self._store[key]
70 69 else:
71 70 raise KeyError('Authentication plugin "{}" is not active.'.format(
72 71 key))
73 72
74 73 def __iter__(self):
75 74 for key in self._store.keys():
76 75 if self._is_item_active(key):
77 76 yield self._store[key]
78 77
79 78 def _is_item_active(self, key):
80 79 activated_plugins = SettingsModel().get_auth_plugins()
81 80 plugin_id = self.get_plugin_id(key)
82 81 return plugin_id in activated_plugins
83 82
84 83 def get_plugin_id(self, resource_name):
85 84 """
86 85 Return the plugin id for the given traversal resource name.
87 86 """
88 87 # TODO: Store this info in the resource element.
89 88 return self._resource_name_map[resource_name]
90 89
91 90 def get_sorted_list(self):
92 91 """
93 92 Returns a sorted list of sub resources for displaying purposes.
94 93 """
95 94 def sort_key(resource):
96 95 return str.lower(safe_str(resource.display_name))
97 96
98 97 active = [item for item in self]
99 98 return sorted(active, key=sort_key)
100 99
101 100 def get_nav_list(self):
102 101 """
103 102 Returns a sorted list of resources for displaying the navigation.
104 103 """
105 104 list = self.get_sorted_list()
106 105 list.insert(0, self)
107 106 return list
108 107
109 108 def add_authn_resource(self, config, plugin_id, resource):
110 109 """
111 110 Register a traversal resource as a sub element to the authentication
112 111 settings. This method is registered as a directive on the pyramid
113 112 configurator object and called by plugins.
114 113 """
115 114
116 115 def _ensure_unique_name(name, limit=100):
117 116 counter = 1
118 117 current = name
119 118 while current in self._store.keys():
120 119 current = '{}{}'.format(name, counter)
121 120 counter += 1
122 121 if counter > limit:
123 122 raise ConfigurationError(
124 123 'Cannot build unique name for traversal resource "%s" '
125 124 'registered by plugin "%s"', name, plugin_id)
126 125 return current
127 126
128 127 # Allow plugin resources with identical names by rename duplicates.
129 128 unique_name = _ensure_unique_name(resource.__name__)
130 129 if unique_name != resource.__name__:
131 130 log.warn('Name collision for traversal resource "%s" registered '
132 131 'by authentication plugin "%s"', resource.__name__,
133 132 plugin_id)
134 133 resource.__name__ = unique_name
135 134
136 135 log.debug('Register traversal resource "%s" for plugin "%s"',
137 136 unique_name, plugin_id)
138 137 self._resource_name_map[unique_name] = plugin_id
139 138 resource.__parent__ = self
140 139 self._store[unique_name] = resource
141 140
142 141
143 142 root = AuthnRootResource()
144 143
145 144
146 145 def root_factory(request=None):
147 146 """
148 147 Returns the root traversal resource instance used for the authentication
149 148 settings route.
150 149 """
151 150 return root
@@ -1,53 +1,51 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2012-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import colander
22 22
23 from pyramid.i18n import TranslationStringFactory
24
25 _ = TranslationStringFactory('rhodecode-enterprise')
23 from rhodecode.translation import _
26 24
27 25
28 26 class AuthnPluginSettingsSchemaBase(colander.MappingSchema):
29 27 """
30 28 This base schema is intended for use in authentication plugins.
31 29 It adds a few default settings (e.g., "enabled"), so that plugin
32 30 authors don't have to maintain a bunch of boilerplate.
33 31 """
34 32 enabled = colander.SchemaNode(
35 33 colander.Bool(),
36 34 default=False,
37 35 description=_('Enable or disable this authentication plugin.'),
38 36 missing=False,
39 37 title=_('Enabled'),
40 38 widget='bool',
41 39 )
42 40 cache_ttl = colander.SchemaNode(
43 41 colander.Int(),
44 42 default=0,
45 43 description=_('Amount of seconds to cache the authentication '
46 44 'call for this plugin. Useful for long calls like '
47 45 'LDAP to improve the responsiveness of the '
48 46 'authentication system (0 means disabled).'),
49 47 missing=0,
50 48 title=_('Auth Cache TTL'),
51 49 validator=colander.Range(min=0, max=None),
52 50 widget='int',
53 51 )
@@ -1,220 +1,218 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2012-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import colander
22 22 import formencode.htmlfill
23 23 import logging
24 24
25 25 from pyramid.httpexceptions import HTTPFound
26 from pyramid.i18n import TranslationStringFactory
27 26 from pyramid.renderers import render
28 27 from pyramid.response import Response
29 28
30 29 from rhodecode.authentication.base import get_auth_cache_manager
31 30 from rhodecode.authentication.interface import IAuthnPluginRegistry
32 31 from rhodecode.lib import auth
33 32 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
34 33 from rhodecode.model.forms import AuthSettingsForm
35 34 from rhodecode.model.meta import Session
36 35 from rhodecode.model.settings import SettingsModel
36 from rhodecode.translation import _
37 37
38 38 log = logging.getLogger(__name__)
39 39
40 _ = TranslationStringFactory('rhodecode-enterprise')
41
42 40
43 41 class AuthnPluginViewBase(object):
44 42
45 43 def __init__(self, context, request):
46 44 self.request = request
47 45 self.context = context
48 46 self.plugin = context.plugin
49 47
50 48 # TODO: Think about replacing the htmlfill stuff.
51 49 def _render_and_fill(self, template, template_context, request,
52 50 form_defaults, validation_errors):
53 51 """
54 52 Helper to render a template and fill the HTML form fields with
55 53 defaults. Also displays the form errors.
56 54 """
57 55 # Render template to string.
58 56 html = render(template, template_context, request=request)
59 57
60 58 # Fill the HTML form fields with default values and add error messages.
61 59 html = formencode.htmlfill.render(
62 60 html,
63 61 defaults=form_defaults,
64 62 errors=validation_errors,
65 63 prefix_error=False,
66 64 encoding="UTF-8",
67 65 force_defaults=False)
68 66
69 67 return html
70 68
71 69 def settings_get(self):
72 70 """
73 71 View that displays the plugin settings as a form.
74 72 """
75 73 form_defaults = {}
76 74 validation_errors = None
77 75 schema = self.plugin.get_settings_schema()
78 76
79 77 # Get default values for the form.
80 78 for node in schema.children:
81 79 value = self.plugin.get_setting_by_name(node.name) or node.default
82 80 form_defaults[node.name] = value
83 81
84 82 template_context = {
85 83 'resource': self.context,
86 84 'plugin': self.context.plugin
87 85 }
88 86
89 87 return Response(self._render_and_fill(
90 88 'rhodecode:templates/admin/auth/plugin_settings.html',
91 89 template_context,
92 90 self.request,
93 91 form_defaults,
94 92 validation_errors))
95 93
96 94 def settings_post(self):
97 95 """
98 96 View that validates and stores the plugin settings.
99 97 """
100 98 schema = self.plugin.get_settings_schema()
101 99 try:
102 100 valid_data = schema.deserialize(self.request.params)
103 101 except colander.Invalid, e:
104 102 # Display error message and display form again.
105 103 form_defaults = self.request.params
106 104 validation_errors = e.asdict()
107 105 self.request.session.flash(
108 106 _('Errors exist when saving plugin settings. '
109 107 'Please check the form inputs.'),
110 108 queue='error')
111 109
112 110 template_context = {
113 111 'resource': self.context,
114 112 'plugin': self.context.plugin
115 113 }
116 114
117 115 return Response(self._render_and_fill(
118 116 'rhodecode:templates/admin/auth/plugin_settings.html',
119 117 template_context,
120 118 self.request,
121 119 form_defaults,
122 120 validation_errors))
123 121
124 122 # Store validated data.
125 123 for name, value in valid_data.items():
126 124 self.plugin.create_or_update_setting(name, value)
127 125 Session.commit()
128 126
129 127 # Display success message and redirect.
130 128 self.request.session.flash(
131 129 _('Auth settings updated successfully.'),
132 130 queue='success')
133 131 redirect_to = self.request.resource_path(
134 132 self.context, route_name='auth_home')
135 133 return HTTPFound(redirect_to)
136 134
137 135
138 136 # TODO: Ongoing migration in these views.
139 137 # - Maybe we should also use a colander schema for these views.
140 138 class AuthSettingsView(object):
141 139 def __init__(self, context, request):
142 140 self.context = context
143 141 self.request = request
144 142
145 143 # TODO: Move this into a utility function. It is needed in all view
146 144 # classes during migration. Maybe a mixin?
147 145
148 146 # Some of the decorators rely on this attribute to be present on the
149 147 # class of the decorated method.
150 148 self._rhodecode_user = request.user
151 149
152 150 @LoginRequired()
153 151 @HasPermissionAllDecorator('hg.admin')
154 152 def index(self, defaults={}, errors=None, prefix_error=False):
155 153 authn_registry = self.request.registry.getUtility(IAuthnPluginRegistry)
156 154 default_plugins = ['egg:rhodecode-enterprise-ce#rhodecode']
157 155 enabled_plugins = SettingsModel().get_auth_plugins() or default_plugins
158 156
159 157 # Create template context and render it.
160 158 template_context = {
161 159 'resource': self.context,
162 160 'available_plugins': authn_registry.get_plugins(),
163 161 'enabled_plugins': enabled_plugins,
164 162 }
165 163 html = render('rhodecode:templates/admin/auth/auth_settings.html',
166 164 template_context,
167 165 request=self.request)
168 166
169 167 # Create form default values and fill the form.
170 168 form_defaults = {
171 169 'auth_plugins': ','.join(enabled_plugins)
172 170 }
173 171 form_defaults.update(defaults)
174 172 html = formencode.htmlfill.render(
175 173 html,
176 174 defaults=form_defaults,
177 175 errors=errors,
178 176 prefix_error=prefix_error,
179 177 encoding="UTF-8",
180 178 force_defaults=False)
181 179
182 180 return Response(html)
183 181
184 182 @LoginRequired()
185 183 @HasPermissionAllDecorator('hg.admin')
186 184 @auth.CSRFRequired()
187 185 def auth_settings(self):
188 186 try:
189 187 form = AuthSettingsForm()()
190 188 form_result = form.to_python(self.request.params)
191 189 plugins = ','.join(form_result['auth_plugins'])
192 190 setting = SettingsModel().create_or_update_setting(
193 191 'auth_plugins', plugins)
194 192 Session().add(setting)
195 193 Session().commit()
196 194
197 195 cache_manager = get_auth_cache_manager()
198 196 cache_manager.clear()
199 197 self.request.session.flash(
200 198 _('Auth settings updated successfully.'),
201 199 queue='success')
202 200 except formencode.Invalid as errors:
203 201 e = errors.error_dict or {}
204 202 self.request.session.flash(
205 203 _('Errors exist when saving plugin setting. '
206 204 'Please check the form inputs.'),
207 205 queue='error')
208 206 return self.index(
209 207 defaults=errors.value,
210 208 errors=e,
211 209 prefix_error=False)
212 210 except Exception:
213 211 log.exception('Exception in auth_settings')
214 212 self.request.session.flash(
215 213 _('Error occurred during update of auth settings.'),
216 214 queue='error')
217 215
218 216 redirect_to = self.request.resource_path(
219 217 self.context, route_name='auth_home')
220 218 return HTTPFound(redirect_to)
@@ -1,346 +1,342 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import datetime
22 22 import formencode
23 23 import logging
24 24 import urlparse
25 import uuid
26 25
27 26 from pylons import url
28 27 from pyramid.httpexceptions import HTTPFound
29 from pyramid.i18n import TranslationStringFactory
30 28 from pyramid.view import view_config
31 29 from recaptcha.client.captcha import submit
32 30
33 from rhodecode.authentication.base import loadplugin
34 31 from rhodecode.events import UserRegistered
35 32 from rhodecode.lib.auth import (
36 33 AuthUser, HasPermissionAnyDecorator, CSRFRequired)
37 34 from rhodecode.lib.base import get_ip_addr
38 35 from rhodecode.lib.exceptions import UserCreationError
39 36 from rhodecode.lib.utils2 import safe_str
40 37 from rhodecode.model.db import User
41 38 from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm
42 39 from rhodecode.model.login_session import LoginSession
43 40 from rhodecode.model.meta import Session
44 41 from rhodecode.model.settings import SettingsModel
45 42 from rhodecode.model.user import UserModel
46
43 from rhodecode.translation import _
47 44
48 _ = TranslationStringFactory('rhodecode-enterprise')
49 45
50 46 log = logging.getLogger(__name__)
51 47
52 48
53 49 def _store_user_in_session(session, username, remember=False):
54 50 user = User.get_by_username(username, case_insensitive=True)
55 51 auth_user = AuthUser(user.user_id)
56 52 auth_user.set_authenticated()
57 53 cs = auth_user.get_cookie_store()
58 54 session['rhodecode_user'] = cs
59 55 user.update_lastlogin()
60 56 Session().commit()
61 57
62 58 # If they want to be remembered, update the cookie
63 59 if remember:
64 60 _year = (datetime.datetime.now() +
65 61 datetime.timedelta(seconds=60 * 60 * 24 * 365))
66 62 session._set_cookie_expires(_year)
67 63
68 64 session.save()
69 65
70 66 log.info('user %s is now authenticated and stored in '
71 67 'session, session attrs %s', username, cs)
72 68
73 69 # dumps session attrs back to cookie
74 70 session._update_cookie_out()
75 71 # we set new cookie
76 72 headers = None
77 73 if session.request['set_cookie']:
78 74 # send set-cookie headers back to response to update cookie
79 75 headers = [('Set-Cookie', session.request['cookie_out'])]
80 76 return headers
81 77
82 78
83 79 class LoginView(object):
84 80
85 81 def __init__(self, context, request):
86 82 self.request = request
87 83 self.context = context
88 84 self.session = request.session
89 85 self._rhodecode_user = request.user
90 86
91 87 def _validate_came_from(self, came_from):
92 88 if not came_from:
93 89 return came_from
94 90
95 91 parsed = urlparse.urlparse(came_from)
96 92 allowed_schemes = ['http', 'https']
97 93 if parsed.scheme and parsed.scheme not in allowed_schemes:
98 94 log.error('Suspicious URL scheme detected %s for url %s' %
99 95 (parsed.scheme, parsed))
100 96 came_from = url('home')
101 97 elif parsed.netloc and self.request.host != parsed.netloc:
102 98 log.error('Suspicious NETLOC detected %s for url %s server url '
103 99 'is: %s' % (parsed.netloc, parsed, self.request.host))
104 100 came_from = url('home')
105 101 if any(bad_str in parsed.path for bad_str in ('\r', '\n')):
106 102 log.error('Header injection detected `%s` for url %s server url ' %
107 103 (parsed.path, parsed))
108 104 came_from = url('home')
109 105 return came_from
110 106
111 107 def _get_came_from(self):
112 108 _default_came_from = url('home')
113 109 came_from = self._validate_came_from(
114 110 safe_str(self.request.GET.get('came_from', '')))
115 111 return came_from or _default_came_from
116 112
117 113 def _get_template_context(self):
118 114 return {
119 115 'came_from': self._get_came_from(),
120 116 'defaults': {},
121 117 'errors': {},
122 118 }
123 119
124 120 @view_config(
125 121 route_name='login', request_method='GET',
126 122 renderer='rhodecode:templates/login.html')
127 123 def login(self):
128 124 user = self.request.user
129 125
130 126 # redirect if already logged in
131 127 if user.is_authenticated and not user.is_default and user.ip_allowed:
132 128 raise HTTPFound(self._get_came_from())
133 129
134 130 return self._get_template_context()
135 131
136 132 @view_config(
137 133 route_name='login', request_method='POST',
138 134 renderer='rhodecode:templates/login.html')
139 135 def login_post(self):
140 136 came_from = self._get_came_from()
141 137 session = self.request.session
142 138 login_form = LoginForm()()
143 139
144 140 try:
145 141 session.invalidate()
146 142 form_result = login_form.to_python(self.request.params)
147 143 # form checks for username/password, now we're authenticated
148 144 headers = _store_user_in_session(
149 145 self.session,
150 146 username=form_result['username'],
151 147 remember=form_result['remember'])
152 148 raise HTTPFound(came_from, headers=headers)
153 149 except formencode.Invalid as errors:
154 150 defaults = errors.value
155 151 # remove password from filling in form again
156 152 del defaults['password']
157 153 render_ctx = self._get_template_context()
158 154 render_ctx.update({
159 155 'errors': errors.error_dict,
160 156 'defaults': defaults,
161 157 })
162 158 return render_ctx
163 159
164 160 except UserCreationError as e:
165 161 # container auth or other auth functions that create users on
166 162 # the fly can throw this exception signaling that there's issue
167 163 # with user creation, explanation should be provided in
168 164 # Exception itself
169 165 session.flash(e, queue='error')
170 166
171 167 # check if we use container plugin, and try to login using it.
172 168 from rhodecode.authentication.base import authenticate, HTTP_TYPE
173 169 try:
174 170 log.debug('Running PRE-AUTH for container based authentication')
175 171 auth_info = authenticate(
176 172 '', '', self.request.environ, HTTP_TYPE, skip_missing=True)
177 173 except UserCreationError as e:
178 174 log.error(e)
179 175 session.flash(e, queue='error')
180 176 # render login, with flash message about limit
181 177 return self._get_template_context()
182 178
183 179 if auth_info:
184 180 headers = _store_user_in_session(auth_info.get('username'))
185 181 raise HTTPFound(came_from, headers=headers)
186 182
187 183 return self._get_template_context()
188 184
189 185 @CSRFRequired()
190 186 @view_config(route_name='logout', request_method='POST')
191 187 def logout(self):
192 188 LoginSession().destroy_user_session()
193 189 return HTTPFound(url('home'))
194 190
195 191 @HasPermissionAnyDecorator(
196 192 'hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')
197 193 @view_config(
198 194 route_name='register', request_method='GET',
199 195 renderer='rhodecode:templates/register.html',)
200 196 def register(self, defaults={}, errors={}):
201 197 settings = SettingsModel().get_all_settings()
202 198 captcha_public_key = settings.get('rhodecode_captcha_public_key')
203 199 captcha_private_key = settings.get('rhodecode_captcha_private_key')
204 200 captcha_active = bool(captcha_private_key)
205 201 register_message = settings.get('rhodecode_register_message') or ''
206 202 auto_active = 'hg.register.auto_activate' in User.get_default_user()\
207 203 .AuthUser.permissions['global']
208 204
209 205 render_ctx = self._get_template_context()
210 206 render_ctx.update({
211 207 'defaults': defaults,
212 208 'errors': errors,
213 209 'auto_active': auto_active,
214 210 'captcha_active': captcha_active,
215 211 'captcha_public_key': captcha_public_key,
216 212 'register_message': register_message,
217 213 })
218 214 return render_ctx
219 215
220 216 @view_config(
221 217 route_name='register', request_method='POST',
222 218 renderer='rhodecode:templates/register.html')
223 219 def register_post(self):
224 220 captcha_private_key = SettingsModel().get_setting_by_name(
225 221 'rhodecode_captcha_private_key')
226 222 captcha_active = bool(captcha_private_key)
227 223 auto_active = 'hg.register.auto_activate' in User.get_default_user()\
228 224 .AuthUser.permissions['global']
229 225
230 226 register_form = RegisterForm()()
231 227 try:
232 228 form_result = register_form.to_python(self.request.params)
233 229 form_result['active'] = auto_active
234 230
235 231 if captcha_active:
236 232 response = submit(
237 233 self.request.params.get('recaptcha_challenge_field'),
238 234 self.request.params.get('recaptcha_response_field'),
239 235 private_key=captcha_private_key,
240 236 remoteip=get_ip_addr(self.request.environ))
241 237 if captcha_active and not response.is_valid:
242 238 _value = form_result
243 239 _msg = _('bad captcha')
244 240 error_dict = {'recaptcha_field': _msg}
245 241 raise formencode.Invalid(_msg, _value, None,
246 242 error_dict=error_dict)
247 243
248 244 new_user = UserModel().create_registration(form_result)
249 245 event = UserRegistered(user=new_user, session=self.session)
250 246 self.request.registry.notify(event)
251 247 self.session.flash(
252 248 _('You have successfully registered with RhodeCode'),
253 249 queue='success')
254 250 Session().commit()
255 251
256 252 redirect_ro = self.request.route_path('login')
257 253 raise HTTPFound(redirect_ro)
258 254
259 255 except formencode.Invalid as errors:
260 256 del errors.value['password']
261 257 del errors.value['password_confirmation']
262 258 return self.register(
263 259 defaults=errors.value, errors=errors.error_dict)
264 260
265 261 except UserCreationError as e:
266 262 # container auth or other auth functions that create users on
267 263 # the fly can throw this exception signaling that there's issue
268 264 # with user creation, explanation should be provided in
269 265 # Exception itself
270 266 self.session.flash(e, queue='error')
271 267 return self.register()
272 268
273 269 @view_config(
274 270 route_name='reset_password', request_method=('GET', 'POST'),
275 271 renderer='rhodecode:templates/password_reset.html')
276 272 def password_reset(self):
277 273 settings = SettingsModel().get_all_settings()
278 274 captcha_private_key = settings.get('rhodecode_captcha_private_key')
279 275 captcha_active = bool(captcha_private_key)
280 276 captcha_public_key = settings.get('rhodecode_captcha_public_key')
281 277
282 278 render_ctx = {
283 279 'captcha_active': captcha_active,
284 280 'captcha_public_key': captcha_public_key,
285 281 'defaults': {},
286 282 'errors': {},
287 283 }
288 284
289 285 if self.request.POST:
290 286 password_reset_form = PasswordResetForm()()
291 287 try:
292 288 form_result = password_reset_form.to_python(
293 289 self.request.params)
294 290 if captcha_active:
295 291 response = submit(
296 292 self.request.params.get('recaptcha_challenge_field'),
297 293 self.request.params.get('recaptcha_response_field'),
298 294 private_key=captcha_private_key,
299 295 remoteip=get_ip_addr(self.request.environ))
300 296 if captcha_active and not response.is_valid:
301 297 _value = form_result
302 298 _msg = _('bad captcha')
303 299 error_dict = {'recaptcha_field': _msg}
304 300 raise formencode.Invalid(_msg, _value, None,
305 301 error_dict=error_dict)
306 302
307 303 # Generate reset URL and send mail.
308 304 user_email = form_result['email']
309 305 user = User.get_by_email(user_email)
310 306 password_reset_url = self.request.route_url(
311 307 'reset_password_confirmation',
312 308 _query={'key': user.api_key})
313 309 UserModel().reset_password_link(
314 310 form_result, password_reset_url)
315 311
316 312 # Display success message and redirect.
317 313 self.session.flash(
318 314 _('Your password reset link was sent'),
319 315 queue='success')
320 316 return HTTPFound(self.request.route_path('login'))
321 317
322 318 except formencode.Invalid as errors:
323 319 render_ctx.update({
324 320 'defaults': errors.value,
325 321 'errors': errors.error_dict,
326 322 })
327 323
328 324 return render_ctx
329 325
330 326 @view_config(route_name='reset_password_confirmation',
331 327 request_method='GET')
332 328 def password_reset_confirmation(self):
333 329 if self.request.GET and self.request.GET.get('key'):
334 330 try:
335 331 user = User.get_by_auth_token(self.request.GET.get('key'))
336 332 data = {'email': user.email}
337 333 UserModel().reset_password(data)
338 334 self.session.flash(
339 335 _('Your password reset was successful, '
340 336 'a new password has been sent to your email'),
341 337 queue='success')
342 338 except Exception as e:
343 339 log.error(e)
344 340 return HTTPFound(self.request.route_path('reset_password'))
345 341
346 342 return HTTPFound(self.request.route_path('login'))
@@ -1,54 +1,55 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21
22 22 import pylons
23 from pyramid.i18n import get_localizer, TranslationStringFactory
23
24 from pyramid.i18n import get_localizer
24 25 from pyramid.threadlocal import get_current_request
25 26
26 tsf = TranslationStringFactory('rc_root')
27 from rhodecode.translation import _ as tsf
27 28
28 29
29 30 def add_renderer_globals(event):
30 31 # Put pylons stuff into the context. This will be removed as soon as
31 32 # migration to pyramid is finished.
32 33 conf = pylons.config._current_obj()
33 34 event['h'] = conf.get('pylons.h')
34 35 event['c'] = pylons.tmpl_context
35 36 event['url'] = pylons.url
36 37
37 38 # TODO: When executed in pyramid view context the request is not available
38 39 # in the event. Find a better solution to get the request.
39 40 request = event['request'] or get_current_request()
40 41
41 42 # Add Pyramid translation as '_' to context
42 43 event['_'] = request.translate
43 44 event['localizer'] = request.localizer
44 45
45 46
46 47 def add_localizer(event):
47 48 request = event.request
48 49 localizer = get_localizer(request)
49 50
50 51 def auto_translate(*args, **kwargs):
51 52 return localizer.translate(tsf(*args, **kwargs))
52 53
53 54 request.localizer = localizer
54 55 request.translate = auto_translate
General Comments 0
You need to be logged in to leave comments. Login now