Show More
@@ -0,0 +1,54 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
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 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
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/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import logging | |||
|
22 | ||||
|
23 | from . import config_keys | |||
|
24 | from .events import SshKeyFileChangeEvent | |||
|
25 | from .subscribers import generate_ssh_authorized_keys_file_subscriber | |||
|
26 | ||||
|
27 | from rhodecode.config.middleware import _bool_setting, _string_setting | |||
|
28 | ||||
|
29 | log = logging.getLogger(__name__) | |||
|
30 | ||||
|
31 | ||||
|
32 | def _sanitize_settings_and_apply_defaults(settings): | |||
|
33 | """ | |||
|
34 | Set defaults, convert to python types and validate settings. | |||
|
35 | """ | |||
|
36 | _bool_setting(settings, config_keys.generate_authorized_keyfile, 'false') | |||
|
37 | _bool_setting(settings, config_keys.wrapper_allow_shell, 'false') | |||
|
38 | ||||
|
39 | _string_setting(settings, config_keys.authorized_keys_file_path, '', | |||
|
40 | lower=False) | |||
|
41 | _string_setting(settings, config_keys.wrapper_cmd, '', | |||
|
42 | lower=False) | |||
|
43 | _string_setting(settings, config_keys.authorized_keys_line_ssh_opts, '', | |||
|
44 | lower=False) | |||
|
45 | ||||
|
46 | ||||
|
47 | def includeme(config): | |||
|
48 | settings = config.registry.settings | |||
|
49 | _sanitize_settings_and_apply_defaults(settings) | |||
|
50 | ||||
|
51 | # if we have enable generation of file, subscribe to event | |||
|
52 | if settings[config_keys.generate_authorized_keyfile]: | |||
|
53 | config.add_subscriber( | |||
|
54 | generate_ssh_authorized_keys_file_subscriber, SshKeyFileChangeEvent) |
@@ -0,0 +1,28 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
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 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
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/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | ||||
|
22 | # Definition of setting keys used to configure this module. Defined here to | |||
|
23 | # avoid repetition of keys throughout the module. | |||
|
24 | generate_authorized_keyfile = 'ssh.generate_authorized_keyfile' | |||
|
25 | authorized_keys_file_path = 'ssh.authorized_keys_file_path' | |||
|
26 | authorized_keys_line_ssh_opts = 'ssh.authorized_keys_ssh_opts' | |||
|
27 | wrapper_cmd = 'ssh.wrapper_cmd' | |||
|
28 | wrapper_allow_shell = 'ssh.wrapper_cmd_allow_shell' |
@@ -0,0 +1,29 b'' | |||||
|
1 | # Copyright (C) 2016-2017 RhodeCode GmbH | |||
|
2 | # | |||
|
3 | # This program is free software: you can redistribute it and/or modify | |||
|
4 | # it under the terms of the GNU Affero General Public License, version 3 | |||
|
5 | # (only), as published by the Free Software Foundation. | |||
|
6 | # | |||
|
7 | # This program is distributed in the hope that it will be useful, | |||
|
8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
10 | # GNU General Public License for more details. | |||
|
11 | # | |||
|
12 | # You should have received a copy of the GNU Affero General Public License | |||
|
13 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
|
14 | # | |||
|
15 | # This program is dual-licensed. If you wish to learn more about the | |||
|
16 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
17 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
18 | ||||
|
19 | ||||
|
20 | from rhodecode.events.base import RhodecodeEvent | |||
|
21 | from rhodecode.translation import _ | |||
|
22 | ||||
|
23 | ||||
|
24 | class SshKeyFileChangeEvent(RhodecodeEvent): | |||
|
25 | """ | |||
|
26 | This event will be triggered on every modification of the stored SSH keys | |||
|
27 | """ | |||
|
28 | name = 'rhodecode-ssh-key-file-change' | |||
|
29 | display_name = _('RhodeCode SSH Key files changed.') |
@@ -0,0 +1,36 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
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 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
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/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import logging | |||
|
22 | ||||
|
23 | ||||
|
24 | from .utils import generate_ssh_authorized_keys_file | |||
|
25 | ||||
|
26 | ||||
|
27 | log = logging.getLogger(__name__) | |||
|
28 | ||||
|
29 | ||||
|
30 | def generate_ssh_authorized_keys_file_subscriber(event): | |||
|
31 | """ | |||
|
32 | Subscriber to the `SshKeyFileChangeEvent`. This triggers the | |||
|
33 | automatic generation of authorized_keys file on any change in | |||
|
34 | ssh keys management | |||
|
35 | """ | |||
|
36 | generate_ssh_authorized_keys_file(event.request.registry) |
@@ -0,0 +1,19 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
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 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
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/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
@@ -0,0 +1,68 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
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 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
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/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | ||||
|
22 | ||||
|
23 | import os | |||
|
24 | import pytest | |||
|
25 | import mock | |||
|
26 | ||||
|
27 | from rhodecode.apps.ssh_support import utils | |||
|
28 | from rhodecode.lib.utils2 import AttributeDict | |||
|
29 | ||||
|
30 | ||||
|
31 | class TestSshKeyFileGeneration(object): | |||
|
32 | @pytest.mark.parametrize('ssh_wrapper_cmd', ['/tmp/sshwrapper.py']) | |||
|
33 | @pytest.mark.parametrize('allow_shell', [True, False]) | |||
|
34 | @pytest.mark.parametrize('ssh_opts', [None, 'mycustom,option']) | |||
|
35 | def test_write_keyfile(self, tmpdir, ssh_wrapper_cmd, allow_shell, ssh_opts): | |||
|
36 | ||||
|
37 | authorized_keys_file_path = os.path.join(str(tmpdir), 'authorized_keys') | |||
|
38 | ||||
|
39 | def keys(): | |||
|
40 | return [ | |||
|
41 | AttributeDict({'user': AttributeDict(username='admin'), | |||
|
42 | 'ssh_key_data': 'ssh-rsa ADMIN_KEY'}), | |||
|
43 | AttributeDict({'user': AttributeDict(username='user'), | |||
|
44 | 'ssh_key_data': 'ssh-rsa USER_KEY'}), | |||
|
45 | ] | |||
|
46 | ||||
|
47 | with mock.patch('rhodecode.apps.ssh_support.utils.get_all_active_keys', | |||
|
48 | return_value=keys()): | |||
|
49 | utils._generate_ssh_authorized_keys_file( | |||
|
50 | authorized_keys_file_path, ssh_wrapper_cmd, | |||
|
51 | allow_shell, ssh_opts | |||
|
52 | ) | |||
|
53 | ||||
|
54 | assert os.path.isfile(authorized_keys_file_path) | |||
|
55 | with open(authorized_keys_file_path) as f: | |||
|
56 | content = f.read() | |||
|
57 | ||||
|
58 | assert 'command="/tmp/sshwrapper.py' in content | |||
|
59 | assert 'This file is managed by RhodeCode, ' \ | |||
|
60 | 'please do not edit it manually.' in content | |||
|
61 | ||||
|
62 | if allow_shell: | |||
|
63 | assert '--shell --user' in content | |||
|
64 | else: | |||
|
65 | assert '--user' in content | |||
|
66 | ||||
|
67 | if ssh_opts: | |||
|
68 | assert ssh_opts in content |
@@ -0,0 +1,107 b'' | |||||
|
1 | # -*- coding: utf-8 -*- | |||
|
2 | ||||
|
3 | # Copyright (C) 2016-2017 RhodeCode GmbH | |||
|
4 | # | |||
|
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 | |||
|
7 | # (only), as published by the Free Software Foundation. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
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/>. | |||
|
16 | # | |||
|
17 | # This program is dual-licensed. If you wish to learn more about the | |||
|
18 | # RhodeCode Enterprise Edition, including its added features, Support services, | |||
|
19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ | |||
|
20 | ||||
|
21 | import os | |||
|
22 | import stat | |||
|
23 | import logging | |||
|
24 | import tempfile | |||
|
25 | import datetime | |||
|
26 | ||||
|
27 | from . import config_keys | |||
|
28 | from rhodecode.model.db import true, joinedload, User, UserSshKeys | |||
|
29 | ||||
|
30 | ||||
|
31 | log = logging.getLogger(__name__) | |||
|
32 | ||||
|
33 | HEADER = \ | |||
|
34 | "# This file is managed by RhodeCode, please do not edit it manually. # \n" \ | |||
|
35 | "# Current entries: {}, create date: UTC:{}.\n" | |||
|
36 | ||||
|
37 | # Default SSH options for authorized_keys file, can be override via .ini | |||
|
38 | SSH_OPTS = 'no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding' | |||
|
39 | ||||
|
40 | ||||
|
41 | def get_all_active_keys(): | |||
|
42 | result = UserSshKeys.query() \ | |||
|
43 | .options(joinedload(UserSshKeys.user)) \ | |||
|
44 | .filter(UserSshKeys.user != User.get_default_user()) \ | |||
|
45 | .filter(User.active == true()) \ | |||
|
46 | .all() | |||
|
47 | return result | |||
|
48 | ||||
|
49 | ||||
|
50 | def _generate_ssh_authorized_keys_file( | |||
|
51 | authorized_keys_file_path, ssh_wrapper_cmd, allow_shell, ssh_opts): | |||
|
52 | all_active_keys = get_all_active_keys() | |||
|
53 | ||||
|
54 | if allow_shell: | |||
|
55 | ssh_wrapper_cmd = ssh_wrapper_cmd + ' --shell' | |||
|
56 | ||||
|
57 | if not os.path.isfile(authorized_keys_file_path): | |||
|
58 | with open(authorized_keys_file_path, 'w'): | |||
|
59 | pass | |||
|
60 | ||||
|
61 | if not os.access(authorized_keys_file_path, os.R_OK): | |||
|
62 | raise OSError('Access to file {} is without read access'.format( | |||
|
63 | authorized_keys_file_path)) | |||
|
64 | ||||
|
65 | line_tmpl = '{ssh_opts},command="{wrapper_command} --user {user}" {key}\n' | |||
|
66 | ||||
|
67 | fd, tmp_authorized_keys = tempfile.mkstemp( | |||
|
68 | '.authorized_keys_write', | |||
|
69 | dir=os.path.dirname(authorized_keys_file_path)) | |||
|
70 | ||||
|
71 | now = datetime.datetime.utcnow().isoformat() | |||
|
72 | keys_file = os.fdopen(fd, 'wb') | |||
|
73 | keys_file.write(HEADER.format(len(all_active_keys), now)) | |||
|
74 | ||||
|
75 | for user_key in all_active_keys: | |||
|
76 | username = user_key.user.username | |||
|
77 | keys_file.write( | |||
|
78 | line_tmpl.format( | |||
|
79 | ssh_opts=ssh_opts or SSH_OPTS, | |||
|
80 | wrapper_command=ssh_wrapper_cmd, | |||
|
81 | user=username, key=user_key.ssh_key_data)) | |||
|
82 | log.debug('addkey: Key added for user: `%s`', username) | |||
|
83 | keys_file.close() | |||
|
84 | ||||
|
85 | # Explicitly setting read-only permissions to authorized_keys | |||
|
86 | os.chmod(tmp_authorized_keys, stat.S_IRUSR | stat.S_IWUSR) | |||
|
87 | # Rename is atomic operation | |||
|
88 | os.rename(tmp_authorized_keys, authorized_keys_file_path) | |||
|
89 | ||||
|
90 | ||||
|
91 | def generate_ssh_authorized_keys_file(registry): | |||
|
92 | log.info('Generating new authorized key file') | |||
|
93 | ||||
|
94 | authorized_keys_file_path = registry.settings.get( | |||
|
95 | config_keys.authorized_keys_file_path) | |||
|
96 | ||||
|
97 | ssh_wrapper_cmd = registry.settings.get( | |||
|
98 | config_keys.wrapper_cmd) | |||
|
99 | allow_shell = registry.settings.get( | |||
|
100 | config_keys.wrapper_allow_shell) | |||
|
101 | ssh_opts = registry.settings.get( | |||
|
102 | config_keys.authorized_keys_line_ssh_opts) | |||
|
103 | ||||
|
104 | _generate_ssh_authorized_keys_file( | |||
|
105 | authorized_keys_file_path, ssh_wrapper_cmd, allow_shell, ssh_opts) | |||
|
106 | ||||
|
107 | return 0 |
@@ -587,6 +587,27 b' svn.proxy.location_root = /' | |||||
587 | ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds. |
|
587 | ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds. | |
588 | #svn.proxy.reload_timeout = 10 |
|
588 | #svn.proxy.reload_timeout = 10 | |
589 |
|
589 | |||
|
590 | ############################################################ | |||
|
591 | ### SSH Support Settings ### | |||
|
592 | ############################################################ | |||
|
593 | ||||
|
594 | ## Defines if the authorized_keys file should be written on any change of | |||
|
595 | ## user ssh keys | |||
|
596 | ssh.generate_authorized_keyfile = false | |||
|
597 | ||||
|
598 | ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding` | |||
|
599 | # ssh.authorized_keys_ssh_opts = | |||
|
600 | ||||
|
601 | ## File to generate the authorized keys together with options | |||
|
602 | ssh.authorized_keys_file_path = /home/USER/.ssh/authorized_keys | |||
|
603 | ||||
|
604 | ## Command to execute as an SSH wrapper, available from | |||
|
605 | ## https://code.rhodecode.com/rhodecode-ssh | |||
|
606 | ssh.wrapper_cmd = /home/USER/rhodecode-ssh/sshwrapper.py | |||
|
607 | ||||
|
608 | ## Allow shell when executing the command | |||
|
609 | ssh.wrapper_cmd_allow_shell = false | |||
|
610 | ||||
590 | ## Dummy marker to add new entries after. |
|
611 | ## Dummy marker to add new entries after. | |
591 | ## Add any custom entries below. Please don't remove. |
|
612 | ## Add any custom entries below. Please don't remove. | |
592 | custom.conf = 1 |
|
613 | custom.conf = 1 |
@@ -556,6 +556,27 b' svn.proxy.location_root = /' | |||||
556 | ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds. |
|
556 | ## be killed. Setting it to zero means no timeout. Defaults to 10 seconds. | |
557 | #svn.proxy.reload_timeout = 10 |
|
557 | #svn.proxy.reload_timeout = 10 | |
558 |
|
558 | |||
|
559 | ############################################################ | |||
|
560 | ### SSH Support Settings ### | |||
|
561 | ############################################################ | |||
|
562 | ||||
|
563 | ## Defines if the authorized_keys file should be written on any change of | |||
|
564 | ## user ssh keys | |||
|
565 | ssh.generate_authorized_keyfile = false | |||
|
566 | ||||
|
567 | ## Options for ssh, default is `no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding` | |||
|
568 | # ssh.authorized_keys_ssh_opts = | |||
|
569 | ||||
|
570 | ## File to generate the authorized keys together with options | |||
|
571 | ssh.authorized_keys_file_path = /home/USER/.ssh/authorized_keys | |||
|
572 | ||||
|
573 | ## Command to execute as an SSH wrapper, available from | |||
|
574 | ## https://code.rhodecode.com/rhodecode-ssh | |||
|
575 | ssh.wrapper_cmd = /home/USER/rhodecode-ssh/sshwrapper.py | |||
|
576 | ||||
|
577 | ## Allow shell when executing the command | |||
|
578 | ssh.wrapper_cmd_allow_shell = false | |||
|
579 | ||||
559 | ## Dummy marker to add new entries after. |
|
580 | ## Dummy marker to add new entries after. | |
560 | ## Add any custom entries below. Please don't remove. |
|
581 | ## Add any custom entries below. Please don't remove. | |
561 | custom.conf = 1 |
|
582 | custom.conf = 1 |
@@ -28,6 +28,8 b' from sqlalchemy.sql.functions import coa' | |||||
28 | from sqlalchemy.exc import IntegrityError |
|
28 | from sqlalchemy.exc import IntegrityError | |
29 |
|
29 | |||
30 | from rhodecode.apps._base import BaseAppView, DataGridAppView |
|
30 | from rhodecode.apps._base import BaseAppView, DataGridAppView | |
|
31 | from rhodecode.apps.ssh_support import SshKeyFileChangeEvent | |||
|
32 | from rhodecode.events import trigger | |||
31 |
|
33 | |||
32 | from rhodecode.lib import audit_logger |
|
34 | from rhodecode.lib import audit_logger | |
33 | from rhodecode.lib.ext_json import json |
|
35 | from rhodecode.lib.ext_json import json | |
@@ -327,6 +329,9 b' class AdminUsersView(BaseAppView, DataGr' | |||||
327 | user=self._rhodecode_user, ) |
|
329 | user=self._rhodecode_user, ) | |
328 | Session().commit() |
|
330 | Session().commit() | |
329 |
|
331 | |||
|
332 | # Trigger an event on change of keys. | |||
|
333 | trigger(SshKeyFileChangeEvent(), self.request.registry) | |||
|
334 | ||||
330 | h.flash(_("Ssh Key successfully created"), category='success') |
|
335 | h.flash(_("Ssh Key successfully created"), category='success') | |
331 |
|
336 | |||
332 | except IntegrityError: |
|
337 | except IntegrityError: | |
@@ -368,6 +373,8 b' class AdminUsersView(BaseAppView, DataGr' | |||||
368 | 'data': {'ssh_key': ssh_key_data, 'user': user_data}}, |
|
373 | 'data': {'ssh_key': ssh_key_data, 'user': user_data}}, | |
369 | user=self._rhodecode_user,) |
|
374 | user=self._rhodecode_user,) | |
370 | Session().commit() |
|
375 | Session().commit() | |
|
376 | # Trigger an event on change of keys. | |||
|
377 | trigger(SshKeyFileChangeEvent(), self.request.registry) | |||
371 | h.flash(_("Ssh key successfully deleted"), category='success') |
|
378 | h.flash(_("Ssh key successfully deleted"), category='success') | |
372 |
|
379 | |||
373 | return HTTPFound(h.route_path('edit_user_ssh_keys', user_id=user_id)) |
|
380 | return HTTPFound(h.route_path('edit_user_ssh_keys', user_id=user_id)) |
@@ -300,6 +300,7 b' def includeme(config):' | |||||
300 | config.include('rhodecode.apps.user_profile') |
|
300 | config.include('rhodecode.apps.user_profile') | |
301 | config.include('rhodecode.apps.my_account') |
|
301 | config.include('rhodecode.apps.my_account') | |
302 | config.include('rhodecode.apps.svn_support') |
|
302 | config.include('rhodecode.apps.svn_support') | |
|
303 | config.include('rhodecode.apps.ssh_support') | |||
303 | config.include('rhodecode.apps.gist') |
|
304 | config.include('rhodecode.apps.gist') | |
304 |
|
305 | |||
305 | config.include('rhodecode.apps.debug_style') |
|
306 | config.include('rhodecode.apps.debug_style') |
General Comments 0
You need to be logged in to leave comments.
Login now