##// END OF EJS Templates
SSH: disable visually support ssh keys if we have them disabled in the .ini
marcink -
r2045:2161e3c4 default
parent child Browse files
Show More
@@ -1,151 +1,154 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 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 logging
21 import logging
22
22
23 from pyramid.httpexceptions import HTTPFound
23 from pyramid.httpexceptions import HTTPFound
24 from pyramid.view import view_config
24 from pyramid.view import view_config
25
25
26 from rhodecode.apps._base import BaseAppView, DataGridAppView
26 from rhodecode.apps._base import BaseAppView, DataGridAppView
27 from rhodecode.apps.ssh_support import SshKeyFileChangeEvent
27 from rhodecode.apps.ssh_support import SshKeyFileChangeEvent
28 from rhodecode.events import trigger
28 from rhodecode.events import trigger
29 from rhodecode.lib import helpers as h
29 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.auth import LoginRequired, NotAnonymous, CSRFRequired
31 from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired
32 from rhodecode.model.db import IntegrityError, UserSshKeys
32 from rhodecode.model.db import IntegrityError, UserSshKeys
33 from rhodecode.model.meta import Session
33 from rhodecode.model.meta import Session
34 from rhodecode.model.ssh_key import SshKeyModel
34 from rhodecode.model.ssh_key import SshKeyModel
35
35
36 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
37
37
38
38
39 class MyAccountSshKeysView(BaseAppView, DataGridAppView):
39 class MyAccountSshKeysView(BaseAppView, DataGridAppView):
40
40
41 def load_default_context(self):
41 def load_default_context(self):
42 c = self._get_local_tmpl_context()
42 c = self._get_local_tmpl_context()
43 c.user = c.auth_user.get_instance()
43 c.user = c.auth_user.get_instance()
44
45 c.ssh_enabled = self.request.registry.settings.get(
46 'ssh.generate_authorized_keyfile')
44 self._register_global_c(c)
47 self._register_global_c(c)
45 return c
48 return c
46
49
47 @LoginRequired()
50 @LoginRequired()
48 @NotAnonymous()
51 @NotAnonymous()
49 @view_config(
52 @view_config(
50 route_name='my_account_ssh_keys', request_method='GET',
53 route_name='my_account_ssh_keys', request_method='GET',
51 renderer='rhodecode:templates/admin/my_account/my_account.mako')
54 renderer='rhodecode:templates/admin/my_account/my_account.mako')
52 def my_account_ssh_keys(self):
55 def my_account_ssh_keys(self):
53 _ = self.request.translate
56 _ = self.request.translate
54
57
55 c = self.load_default_context()
58 c = self.load_default_context()
56 c.active = 'ssh_keys'
59 c.active = 'ssh_keys'
57 c.default_key = self.request.GET.get('default_key')
60 c.default_key = self.request.GET.get('default_key')
58 c.user_ssh_keys = SshKeyModel().get_ssh_keys(c.user.user_id)
61 c.user_ssh_keys = SshKeyModel().get_ssh_keys(c.user.user_id)
59 return self._get_template_context(c)
62 return self._get_template_context(c)
60
63
61 @LoginRequired()
64 @LoginRequired()
62 @NotAnonymous()
65 @NotAnonymous()
63 @view_config(
66 @view_config(
64 route_name='my_account_ssh_keys_generate', request_method='GET',
67 route_name='my_account_ssh_keys_generate', request_method='GET',
65 renderer='rhodecode:templates/admin/my_account/my_account.mako')
68 renderer='rhodecode:templates/admin/my_account/my_account.mako')
66 def ssh_keys_generate_keypair(self):
69 def ssh_keys_generate_keypair(self):
67 _ = self.request.translate
70 _ = self.request.translate
68 c = self.load_default_context()
71 c = self.load_default_context()
69
72
70 c.active = 'ssh_keys_generate'
73 c.active = 'ssh_keys_generate'
71 comment = 'RhodeCode-SSH {}'.format(c.user.email or '')
74 comment = 'RhodeCode-SSH {}'.format(c.user.email or '')
72 c.private, c.public = SshKeyModel().generate_keypair(comment=comment)
75 c.private, c.public = SshKeyModel().generate_keypair(comment=comment)
73 c.target_form_url = h.route_path(
76 c.target_form_url = h.route_path(
74 'my_account_ssh_keys', _query=dict(default_key=c.public))
77 'my_account_ssh_keys', _query=dict(default_key=c.public))
75 return self._get_template_context(c)
78 return self._get_template_context(c)
76
79
77 @LoginRequired()
80 @LoginRequired()
78 @NotAnonymous()
81 @NotAnonymous()
79 @CSRFRequired()
82 @CSRFRequired()
80 @view_config(
83 @view_config(
81 route_name='my_account_ssh_keys_add', request_method='POST',)
84 route_name='my_account_ssh_keys_add', request_method='POST',)
82 def my_account_ssh_keys_add(self):
85 def my_account_ssh_keys_add(self):
83 _ = self.request.translate
86 _ = self.request.translate
84 c = self.load_default_context()
87 c = self.load_default_context()
85
88
86 user_data = c.user.get_api_data()
89 user_data = c.user.get_api_data()
87 key_data = self.request.POST.get('key_data')
90 key_data = self.request.POST.get('key_data')
88 description = self.request.POST.get('description')
91 description = self.request.POST.get('description')
89
92
90 try:
93 try:
91 if not key_data:
94 if not key_data:
92 raise ValueError('Please add a valid public key')
95 raise ValueError('Please add a valid public key')
93
96
94 key = SshKeyModel().parse_key(key_data.strip())
97 key = SshKeyModel().parse_key(key_data.strip())
95 fingerprint = key.hash_md5()
98 fingerprint = key.hash_md5()
96
99
97 ssh_key = SshKeyModel().create(
100 ssh_key = SshKeyModel().create(
98 c.user.user_id, fingerprint, key_data, description)
101 c.user.user_id, fingerprint, key_data, description)
99 ssh_key_data = ssh_key.get_api_data()
102 ssh_key_data = ssh_key.get_api_data()
100
103
101 audit_logger.store_web(
104 audit_logger.store_web(
102 'user.edit.ssh_key.add', action_data={
105 'user.edit.ssh_key.add', action_data={
103 'data': {'ssh_key': ssh_key_data, 'user': user_data}},
106 'data': {'ssh_key': ssh_key_data, 'user': user_data}},
104 user=self._rhodecode_user, )
107 user=self._rhodecode_user, )
105 Session().commit()
108 Session().commit()
106
109
107 # Trigger an event on change of keys.
110 # Trigger an event on change of keys.
108 trigger(SshKeyFileChangeEvent(), self.request.registry)
111 trigger(SshKeyFileChangeEvent(), self.request.registry)
109
112
110 h.flash(_("Ssh Key successfully created"), category='success')
113 h.flash(_("Ssh Key successfully created"), category='success')
111
114
112 except IntegrityError:
115 except IntegrityError:
113 log.exception("Exception during ssh key saving")
116 log.exception("Exception during ssh key saving")
114 h.flash(_('An error occurred during ssh key saving: {}').format(
117 h.flash(_('An error occurred during ssh key saving: {}').format(
115 'Such key already exists, please use a different one'),
118 'Such key already exists, please use a different one'),
116 category='error')
119 category='error')
117 except Exception as e:
120 except Exception as e:
118 log.exception("Exception during ssh key saving")
121 log.exception("Exception during ssh key saving")
119 h.flash(_('An error occurred during ssh key saving: {}').format(e),
122 h.flash(_('An error occurred during ssh key saving: {}').format(e),
120 category='error')
123 category='error')
121
124
122 return HTTPFound(h.route_path('my_account_ssh_keys'))
125 return HTTPFound(h.route_path('my_account_ssh_keys'))
123
126
124 @LoginRequired()
127 @LoginRequired()
125 @NotAnonymous()
128 @NotAnonymous()
126 @CSRFRequired()
129 @CSRFRequired()
127 @view_config(
130 @view_config(
128 route_name='my_account_ssh_keys_delete', request_method='POST')
131 route_name='my_account_ssh_keys_delete', request_method='POST')
129 def my_account_ssh_keys_delete(self):
132 def my_account_ssh_keys_delete(self):
130 _ = self.request.translate
133 _ = self.request.translate
131 c = self.load_default_context()
134 c = self.load_default_context()
132
135
133 user_data = c.user.get_api_data()
136 user_data = c.user.get_api_data()
134
137
135 del_ssh_key = self.request.POST.get('del_ssh_key')
138 del_ssh_key = self.request.POST.get('del_ssh_key')
136
139
137 if del_ssh_key:
140 if del_ssh_key:
138 ssh_key = UserSshKeys.get_or_404(del_ssh_key)
141 ssh_key = UserSshKeys.get_or_404(del_ssh_key)
139 ssh_key_data = ssh_key.get_api_data()
142 ssh_key_data = ssh_key.get_api_data()
140
143
141 SshKeyModel().delete(del_ssh_key, c.user.user_id)
144 SshKeyModel().delete(del_ssh_key, c.user.user_id)
142 audit_logger.store_web(
145 audit_logger.store_web(
143 'user.edit.ssh_key.delete', action_data={
146 'user.edit.ssh_key.delete', action_data={
144 'data': {'ssh_key': ssh_key_data, 'user': user_data}},
147 'data': {'ssh_key': ssh_key_data, 'user': user_data}},
145 user=self._rhodecode_user,)
148 user=self._rhodecode_user,)
146 Session().commit()
149 Session().commit()
147 # Trigger an event on change of keys.
150 # Trigger an event on change of keys.
148 trigger(SshKeyFileChangeEvent(), self.request.registry)
151 trigger(SshKeyFileChangeEvent(), self.request.registry)
149 h.flash(_("Ssh key successfully deleted"), category='success')
152 h.flash(_("Ssh key successfully deleted"), category='success')
150
153
151 return HTTPFound(h.route_path('my_account_ssh_keys'))
154 return HTTPFound(h.route_path('my_account_ssh_keys'))
@@ -1,78 +1,84 b''
1 <div class="panel panel-default">
1 <div class="panel panel-default">
2 <div class="panel-heading">
2 <div class="panel-heading">
3 <h3 class="panel-title">${_('SSH Keys')}</h3>
3 <h3 class="panel-title">${_('SSH Keys')}</h3>
4 </div>
4 </div>
5 <div class="panel-body">
5 <div class="panel-body">
6 <div class="sshkeys_wrap">
6 <div class="sshkeys_wrap">
7 <table class="rctable ssh_keys">
7 <table class="rctable ssh_keys">
8 <tr>
8 <tr>
9 <th>${_('Fingerprint')}</th>
9 <th>${_('Fingerprint')}</th>
10 <th>${_('Description')}</th>
10 <th>${_('Description')}</th>
11 <th>${_('Created')}</th>
11 <th>${_('Created')}</th>
12 <th>${_('Action')}</th>
12 <th>${_('Action')}</th>
13 </tr>
13 </tr>
14 %if c.user_ssh_keys:
14 % if not c.ssh_enabled:
15 %for ssh_key in c.user_ssh_keys:
15 <tr><td colspan="4"><div class="">${_('SSH Keys usage is currently disabled, please ask your administrator to enable them.')}</div></td></tr>
16 <tr class="">
16 % else:
17 <td class="">
17 %if c.user_ssh_keys:
18 <code>${ssh_key.ssh_key_fingerprint}</code>
18 %for ssh_key in c.user_ssh_keys:
19 </td>
19 <tr class="">
20 <td class="td-wrap">${ssh_key.description}</td>
20 <td class="">
21 <td class="td-tags">${h.format_date(ssh_key.created_on)}</td>
21 <code>${ssh_key.ssh_key_fingerprint}</code>
22 </td>
23 <td class="td-wrap">${ssh_key.description}</td>
24 <td class="td-tags">${h.format_date(ssh_key.created_on)}</td>
22
25
23 <td class="td-action">
26 <td class="td-action">
24 ${h.secure_form(h.route_path('my_account_ssh_keys_delete'), method='POST', request=request)}
27 ${h.secure_form(h.route_path('my_account_ssh_keys_delete'), method='POST', request=request)}
25 ${h.hidden('del_ssh_key', ssh_key.ssh_key_id)}
28 ${h.hidden('del_ssh_key', ssh_key.ssh_key_id)}
26 <button class="btn btn-link btn-danger" type="submit"
29 <button class="btn btn-link btn-danger" type="submit"
27 onclick="return confirm('${_('Confirm to remove ssh key %s') % ssh_key.ssh_key_fingerprint}');">
30 onclick="return confirm('${_('Confirm to remove ssh key %s') % ssh_key.ssh_key_fingerprint}');">
28 ${_('Delete')}
31 ${_('Delete')}
29 </button>
32 </button>
30 ${h.end_form()}
33 ${h.end_form()}
31 </td>
34 </td>
32 </tr>
35 </tr>
33 %endfor
36 %endfor
34 %else:
37 %else:
35 <tr><td><div class="ip">${_('No additional ssh keys specified')}</div></td></tr>
38 <tr><td colspan="4"><div class="">${_('No additional ssh keys specified')}</div></td></tr>
36 %endif
39 %endif
40 % endif
37 </table>
41 </table>
38 </div>
42 </div>
39
43
44 % if c.ssh_enabled:
40 <div class="user_ssh_keys">
45 <div class="user_ssh_keys">
41 ${h.secure_form(h.route_path('my_account_ssh_keys_add'), method='POST', request=request)}
46 ${h.secure_form(h.route_path('my_account_ssh_keys_add'), method='POST', request=request)}
42 <div class="form form-vertical">
47 <div class="form form-vertical">
43 <!-- fields -->
48 <!-- fields -->
44 <div class="fields">
49 <div class="fields">
45 <div class="field">
50 <div class="field">
46 <div class="label">
51 <div class="label">
47 <label for="new_email">${_('New ssh key')}:</label>
52 <label for="new_email">${_('New ssh key')}:</label>
48 </div>
53 </div>
49 <div class="input">
54 <div class="input">
50 ${h.text('description', class_='medium', placeholder=_('Description'))}
55 ${h.text('description', class_='medium', placeholder=_('Description'))}
51 <a href="${h.route_path('my_account_ssh_keys_generate')}">${_('Generate random RSA key')}</a>
56 <a href="${h.route_path('my_account_ssh_keys_generate')}">${_('Generate random RSA key')}</a>
52 </div>
57 </div>
53 </div>
58 </div>
54
59
55 <div class="field">
60 <div class="field">
56 <div class="textarea text-area editor">
61 <div class="textarea text-area editor">
57 ${h.textarea('key_data',c.default_key, size=30, placeholder=_("Public key, begins with 'ssh-rsa', 'ssh-dss', 'ssh-ed25519', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', or 'ecdsa-sha2-nistp521'"))}
62 ${h.textarea('key_data',c.default_key, size=30, placeholder=_("Public key, begins with 'ssh-rsa', 'ssh-dss', 'ssh-ed25519', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', or 'ecdsa-sha2-nistp521'"))}
58 </div>
63 </div>
59 </div>
64 </div>
60
65
61 <div class="buttons">
66 <div class="buttons">
62 ${h.submit('save',_('Add'),class_="btn")}
67 ${h.submit('save',_('Add'),class_="btn")}
63 ${h.reset('reset',_('Reset'),class_="btn")}
68 ${h.reset('reset',_('Reset'),class_="btn")}
64 </div>
69 </div>
65 </div>
70 </div>
66 </div>
71 </div>
67 ${h.end_form()}
72 ${h.end_form()}
68 </div>
73 </div>
74 % endif
69 </div>
75 </div>
70 </div>
76 </div>
71
77
72 <script>
78 <script>
73
79
74 $(document).ready(function(){
80 $(document).ready(function(){
75
81
76
82
77 });
83 });
78 </script>
84 </script>
General Comments 0
You need to be logged in to leave comments. Login now