##// END OF EJS Templates
feat(vcs clients filtering): added changes related to vcs client filtering needed for EE. Fixes: RCCE-41
ilin.s -
r5522:33fc2e7c default
parent child Browse files
Show More
@@ -0,0 +1,62 b''
1 <style>
2 .form-group {
3 margin-bottom: 15px;
4 }
5
6 .form-group label {
7 display: flex;
8 align-items: left;
9 font-weight: bold;
10 }
11
12 .form-control {
13 width: 60%;
14 padding: 10px;
15 font-size: 1rem;
16 line-height: 1.5;
17 border: 1px solid #ced4da;
18 border-radius: 4px;
19 box-sizing: border-box;
20 }
21
22 .btn-primary {
23 background-color: #007bff;
24 border: none;
25 padding: 10px 20px;
26 color: white;
27 font-size: 1rem;
28 border-radius: 4px;
29 cursor: pointer;
30 }
31
32 .btn-primary:hover {
33 background-color: #0056b3;
34 }
35 .form-group .help_block {
36 display: block;
37 width: 100%;
38 margin-top: 10px;
39 text-align: left;
40 font-size: 0.875rem;
41 }
42 </style>
43
44 <div>
45 <div class="form-group">
46 ${h.secure_form(h.route_path('check_2fa'), request=request, id='allowed_clients_form')}
47 <p><label for="git">${_('git')}:</label>
48 ${h.text('git', class_="form-control", value=initial_git)}</p>
49 <p><label for="hg">${_('hg')}:</label>
50 ${h.text('hg', class_="form-control", value=initial_hg)}</p>
51 <p><label for="svn">${_('svn')}:</label>
52 ${h.text('svn', class_="form-control", value=initial_svn)}</p>
53 %for k, v in errors.items():
54 <span class="error-message">${k}: ${v}</span>
55 <br />
56 %endfor
57 <p class="help_block">${_('Set rules for allowed git, hg or svn client versions. You can set exact version (for example 2.0.9) or use comparison operators to set earliest or latest version (>=2.6.0)')}</p>
58
59 ${h.submit('send', _('Save'), class_="btn btn-primary")}
60 ${h.end_form()}
61 </div>
62 </div>
@@ -49,7 +49,7 b' def admin_routes(config):'
49
49
50 config.add_route(
50 config.add_route(
51 'admin_security',
51 'admin_security',
52 pattern=ADMIN_PREFIX + '/security')
52 pattern='/security')
53 config.add_view(
53 config.add_view(
54 AdminSecurityView,
54 AdminSecurityView,
55 attr='security' ,
55 attr='security',
@@ -58,13 +58,22 b' def admin_routes(config):'
58
58
59 config.add_route(
59 config.add_route(
60 name='admin_security_update',
60 name='admin_security_update',
61 pattern=ADMIN_PREFIX + '/security/update')
61 pattern='/security/update')
62 config.add_view(
62 config.add_view(
63 AdminSecurityView,
63 AdminSecurityView,
64 attr='security_update',
64 attr='security_update',
65 route_name='admin_security_update', request_method='POST',
65 route_name='admin_security_update', request_method='POST',
66 renderer='rhodecode:templates/admin/security/security.mako')
66 renderer='rhodecode:templates/admin/security/security.mako')
67
67
68 config.add_route(
69 name='admin_security_modify_allowed_vcs_client_versions',
70 pattern='/security/modify/allowed_vcs_client_versions')
71 config.add_view(
72 AdminSecurityView,
73 attr='vcs_whitelisted_client_versions_edit',
74 route_name='admin_security_modify_allowed_vcs_client_versions', request_method=('GET', 'POST'),
75 renderer='rhodecode:templates/admin/security/edit_allowed_vcs_client_versions.mako')
76
68
77
69 config.add_route(
78 config.add_route(
70 name='admin_audit_logs',
79 name='admin_audit_logs',
@@ -17,8 +17,13 b''
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19 import logging
19 import logging
20 import formencode
20
21
22 from rhodecode import BACKENDS
21 from rhodecode.apps._base import BaseAppView
23 from rhodecode.apps._base import BaseAppView
24 from rhodecode.model.meta import Session
25 from rhodecode.model.settings import SettingsModel
26 from rhodecode.model.forms import WhitelistedVcsClientsForm
22 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
27 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
23
28
24 log = logging.getLogger(__name__)
29 log = logging.getLogger(__name__)
@@ -37,3 +42,31 b' class AdminSecurityView(BaseAppView):'
37 c.active = 'security'
42 c.active = 'security'
38 return self._get_template_context(c)
43 return self._get_template_context(c)
39
44
45 @LoginRequired()
46 @HasPermissionAllDecorator('hg.admin')
47 def vcs_whitelisted_client_versions_edit(self):
48 _ = self.request.translate
49 c = self.load_default_context()
50 render_ctx = {}
51 settings = SettingsModel()
52 form = WhitelistedVcsClientsForm(_, )()
53 if self.request.method == 'POST':
54 try:
55 result = form.to_python(self.request.POST)
56 for k, v in result.items():
57 if v:
58 setting = settings.create_or_update_setting(name=f'{k}_allowed_clients', val=v)
59 Session().add(setting)
60 Session().commit()
61
62 except formencode.Invalid as errors:
63 render_ctx.update({
64 'errors': errors.error_dict
65 })
66 for key in BACKENDS.keys():
67 verbose_name = f"initial_{key}"
68 if existing := settings.get_setting_by_name(name=f'{key}_allowed_clients'):
69 render_ctx[verbose_name] = existing.app_settings_value
70 else:
71 render_ctx[verbose_name] = '*'
72 return self._get_template_context(c, **render_ctx)
@@ -102,6 +102,11 b' class HTTPRequirementError(HTTPClientErr'
102 self.args = (message, )
102 self.args = (message, )
103
103
104
104
105 class ClientNotSupportedError(HTTPRequirementError):
106 title = explanation = 'Client Not Supported'
107 reason = None
108
109
105 class HTTPLockedRC(HTTPClientError):
110 class HTTPLockedRC(HTTPClientError):
106 """
111 """
107 Special Exception For locked Repos in RhodeCode, the return code can
112 Special Exception For locked Repos in RhodeCode, the return code can
@@ -30,7 +30,7 b' from rhodecode.lib import helpers as h'
30 from rhodecode.lib import audit_logger
30 from rhodecode.lib import audit_logger
31 from rhodecode.lib.utils2 import safe_str, user_agent_normalizer
31 from rhodecode.lib.utils2 import safe_str, user_agent_normalizer
32 from rhodecode.lib.exceptions import (
32 from rhodecode.lib.exceptions import (
33 HTTPLockedRC, HTTPBranchProtected, UserCreationError)
33 HTTPLockedRC, HTTPBranchProtected, UserCreationError, ClientNotSupportedError)
34 from rhodecode.model.db import Repository, User
34 from rhodecode.model.db import Repository, User
35 from rhodecode.lib.statsd_client import StatsdClient
35 from rhodecode.lib.statsd_client import StatsdClient
36
36
@@ -64,6 +64,18 b' def is_shadow_repo(extras):'
64 return extras['is_shadow_repo']
64 return extras['is_shadow_repo']
65
65
66
66
67 def check_vcs_client(extras):
68 """
69 Checks if vcs client is allowed (Only works in enterprise edition)
70 """
71 try:
72 from rc_ee.lib.security.utils import is_vcs_client_whitelisted
73 except ModuleNotFoundError:
74 is_vcs_client_whitelisted = lambda *x: True
75 backend = extras.get('scm')
76 if not is_vcs_client_whitelisted(extras.get('user_agent'), backend):
77 raise ClientNotSupportedError(f"Your {backend} client is forbidden")
78
67 def _get_scm_size(alias, root_path):
79 def _get_scm_size(alias, root_path):
68
80
69 if not alias.startswith('.'):
81 if not alias.startswith('.'):
@@ -108,6 +120,7 b' def pre_push(extras):'
108 It bans pushing when the repository is locked.
120 It bans pushing when the repository is locked.
109 """
121 """
110
122
123 check_vcs_client(extras)
111 user = User.get_by_username(extras.username)
124 user = User.get_by_username(extras.username)
112 output = ''
125 output = ''
113 if extras.locked_by[0] and user.user_id != int(extras.locked_by[0]):
126 if extras.locked_by[0] and user.user_id != int(extras.locked_by[0]):
@@ -180,6 +193,7 b' def pre_pull(extras):'
180 It bans pulling when the repository is locked.
193 It bans pulling when the repository is locked.
181 """
194 """
182
195
196 check_vcs_client(extras)
183 output = ''
197 output = ''
184 if extras.locked_by[0]:
198 if extras.locked_by[0]:
185 locked_by = User.get(extras.locked_by[0]).username
199 locked_by = User.get(extras.locked_by[0]).username
@@ -84,8 +84,11 b' def adopt_for_celery(func):'
84 @wraps(func)
84 @wraps(func)
85 def wrapper(extras):
85 def wrapper(extras):
86 extras = AttributeDict(extras)
86 extras = AttributeDict(extras)
87 try:
87 # HooksResponse implements to_json method which must be used there.
88 # HooksResponse implements to_json method which must be used there.
88 return func(extras).to_json()
89 return func(extras).to_json()
90 except Exception as e:
91 return {'status': 128, 'exception': type(e).__name__, 'exception_args': e.args}
89 return wrapper
92 return wrapper
90
93
91
94
@@ -129,6 +129,20 b' def TOTPForm(localizer, user, allow_reco'
129 return _TOTPForm
129 return _TOTPForm
130
130
131
131
132 def WhitelistedVcsClientsForm(localizer):
133 _ = localizer
134
135 class _WhitelistedVcsClientsForm(formencode.Schema):
136 regexp = r'^(?:\s*[<>=~^!]*\s*\d{1,2}\.\d{1,2}(?:\.\d{1,2})?\s*|\*)\s*(?:,\s*[<>=~^!]*\s*\d{1,2}\.\d{1,2}(?:\.\d{1,2})?\s*|\s*\*\s*)*$'
137 allow_extra_fields = True
138 filter_extra_fields = True
139 git = v.Regex(regexp)
140 hg = v.Regex(regexp)
141 svn = v.Regex(regexp)
142
143 return _WhitelistedVcsClientsForm
144
145
132 def UserForm(localizer, edit=False, available_languages=None, old_data=None):
146 def UserForm(localizer, edit=False, available_languages=None, old_data=None):
133 old_data = old_data or {}
147 old_data = old_data or {}
134 available_languages = available_languages or []
148 available_languages = available_languages or []
@@ -86,6 +86,7 b' function registerRCRoutes() {'
86 pyroutes.register('admin_settings_vcs_update', '/_admin/settings/vcs/update', []);
86 pyroutes.register('admin_settings_vcs_update', '/_admin/settings/vcs/update', []);
87 pyroutes.register('admin_settings_visual', '/_admin/settings/visual', []);
87 pyroutes.register('admin_settings_visual', '/_admin/settings/visual', []);
88 pyroutes.register('admin_settings_visual_update', '/_admin/settings/visual/update', []);
88 pyroutes.register('admin_settings_visual_update', '/_admin/settings/visual/update', []);
89 pyroutes.register('admin_security_modify_allowed_vcs_client_versions', '/_admin/security/modify/allowed_vcs_client_versions', []);
89 pyroutes.register('apiv2', '/_admin/api', []);
90 pyroutes.register('apiv2', '/_admin/api', []);
90 pyroutes.register('atom_feed_home', '/%(repo_name)s/feed-atom', ['repo_name']);
91 pyroutes.register('atom_feed_home', '/%(repo_name)s/feed-atom', ['repo_name']);
91 pyroutes.register('atom_feed_home_old', '/%(repo_name)s/feed/atom', ['repo_name']);
92 pyroutes.register('atom_feed_home_old', '/%(repo_name)s/feed/atom', ['repo_name']);
@@ -28,13 +28,52 b''
28 <div class="panel-body">
28 <div class="panel-body">
29 <h4>${_('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='<a href="mailto:sales@rhodecode.com">sales@rhodecode.com</a>')|n}</h4>
29 <h4>${_('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='<a href="mailto:sales@rhodecode.com">sales@rhodecode.com</a>')|n}</h4>
30 <p>
30 <p>
31 You can scan your repositories for exposed secrets, passwords, etc
31 ${_('You can scan your repositories for exposed secrets, passwords, etc')}
32 </p>
32 </p>
33 </div>
33 </div>
34 </div>
34 </div>
35
35
36 <div class="panel panel-default">
37 <div class="panel-heading">
38 <h3 class="panel-title">${_('Allowed client versions')}</h3>
39 </div>
40 <div class="panel-body">
41 %if c.rhodecode_edition_id != 'EE':
42 <h4>${_('This feature is available in RhodeCode EE edition only. Contact {sales_email} to obtain a trial license.').format(sales_email='<a href="mailto:sales@rhodecode.com">sales@rhodecode.com</a>')|n}</h4>
43 <p>
44 ${_('Some outdated client versions may have security vulnerabilities. This section have rules for whitelisting versions of clients for Git, Mercurial and SVN.')}
45 </p>
46 %else:
47 <div class="inner form" id="container">
48 </div>
49 %endif
50 </div>
51
36 </div>
52 </div>
37
53
54 <script>
55 $(document).ready(function() {
56 $.ajax({
57 url: pyroutes.url('admin_security_modify_allowed_vcs_client_versions'),
58 type: 'GET',
59 success: function(response) {
60 $('#container').html(response);
61 },
62 });
63 $(document).on('submit', '#allowed_clients_form', function(event) {
64 event.preventDefault();
65 var formData = $(this).serialize();
66
67 $.ajax({
68 url: pyroutes.url('admin_security_modify_allowed_vcs_client_versions'),
69 type: 'POST',
70 data: formData,
71 success: function(response) {
72 $('#container').html(response);
73 },
74 });
75 });
76 });
77 </script>
38
78
39 </%def>
79 </%def>
40
General Comments 0
You need to be logged in to leave comments. Login now