##// END OF EJS Templates
ssh: always expand the path for the generated authorized_keys file....
marcink -
r2211:1517e3b2 default
parent child Browse files
Show More
@@ -1,121 +1,125 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 os
21 import os
22 import stat
22 import stat
23 import logging
23 import logging
24 import tempfile
24 import tempfile
25 import datetime
25 import datetime
26
26
27 from . import config_keys
27 from . import config_keys
28 from rhodecode.model.db import true, joinedload, User, UserSshKeys
28 from rhodecode.model.db import true, joinedload, User, UserSshKeys
29
29
30
30
31 log = logging.getLogger(__name__)
31 log = logging.getLogger(__name__)
32
32
33 HEADER = \
33 HEADER = \
34 "# This file is managed by RhodeCode, please do not edit it manually. # \n" \
34 "# This file is managed by RhodeCode, please do not edit it manually. # \n" \
35 "# Current entries: {}, create date: UTC:{}.\n"
35 "# Current entries: {}, create date: UTC:{}.\n"
36
36
37 # Default SSH options for authorized_keys file, can be override via .ini
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'
38 SSH_OPTS = 'no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding'
39
39
40
40
41 def get_all_active_keys():
41 def get_all_active_keys():
42 result = UserSshKeys.query() \
42 result = UserSshKeys.query() \
43 .options(joinedload(UserSshKeys.user)) \
43 .options(joinedload(UserSshKeys.user)) \
44 .filter(UserSshKeys.user != User.get_default_user()) \
44 .filter(UserSshKeys.user != User.get_default_user()) \
45 .filter(User.active == true()) \
45 .filter(User.active == true()) \
46 .all()
46 .all()
47 return result
47 return result
48
48
49
49
50 def _generate_ssh_authorized_keys_file(
50 def _generate_ssh_authorized_keys_file(
51 authorized_keys_file_path, ssh_wrapper_cmd, allow_shell, ssh_opts, debug):
51 authorized_keys_file_path, ssh_wrapper_cmd, allow_shell, ssh_opts, debug):
52
52
53 authorized_keys_file_path = os.path.abspath(
54 os.path.expanduser(authorized_keys_file_path))
55
53 import rhodecode
56 import rhodecode
54 all_active_keys = get_all_active_keys()
57 all_active_keys = get_all_active_keys()
55
58
56 if allow_shell:
59 if allow_shell:
57 ssh_wrapper_cmd = ssh_wrapper_cmd + ' --shell'
60 ssh_wrapper_cmd = ssh_wrapper_cmd + ' --shell'
58 if debug:
61 if debug:
59 ssh_wrapper_cmd = ssh_wrapper_cmd + ' --debug'
62 ssh_wrapper_cmd = ssh_wrapper_cmd + ' --debug'
60
63
61 if not os.path.isfile(authorized_keys_file_path):
64 if not os.path.isfile(authorized_keys_file_path):
65 log.debug('Creating file at %s', authorized_keys_file_path)
62 with open(authorized_keys_file_path, 'w'):
66 with open(authorized_keys_file_path, 'w'):
63 pass
67 pass
64
68
65 if not os.access(authorized_keys_file_path, os.R_OK):
69 if not os.access(authorized_keys_file_path, os.R_OK):
66 raise OSError('Access to file {} is without read access'.format(
70 raise OSError('Access to file {} is without read access'.format(
67 authorized_keys_file_path))
71 authorized_keys_file_path))
68
72
69 line_tmpl = '{ssh_opts},command="{wrapper_command} {ini_path} --user-id={user_id} --user={user} --key-id={user_key_id}" {key}\n'
73 line_tmpl = '{ssh_opts},command="{wrapper_command} {ini_path} --user-id={user_id} --user={user} --key-id={user_key_id}" {key}\n'
70
74
71 fd, tmp_authorized_keys = tempfile.mkstemp(
75 fd, tmp_authorized_keys = tempfile.mkstemp(
72 '.authorized_keys_write',
76 '.authorized_keys_write',
73 dir=os.path.dirname(authorized_keys_file_path))
77 dir=os.path.dirname(authorized_keys_file_path))
74
78
75 now = datetime.datetime.utcnow().isoformat()
79 now = datetime.datetime.utcnow().isoformat()
76 keys_file = os.fdopen(fd, 'wb')
80 keys_file = os.fdopen(fd, 'wb')
77 keys_file.write(HEADER.format(len(all_active_keys), now))
81 keys_file.write(HEADER.format(len(all_active_keys), now))
78 ini_path = rhodecode.CONFIG['__file__']
82 ini_path = rhodecode.CONFIG['__file__']
79
83
80 for user_key in all_active_keys:
84 for user_key in all_active_keys:
81 username = user_key.user.username
85 username = user_key.user.username
82 user_id = user_key.user.user_id
86 user_id = user_key.user.user_id
83
87
84 keys_file.write(
88 keys_file.write(
85 line_tmpl.format(
89 line_tmpl.format(
86 ssh_opts=ssh_opts or SSH_OPTS,
90 ssh_opts=ssh_opts or SSH_OPTS,
87 wrapper_command=ssh_wrapper_cmd,
91 wrapper_command=ssh_wrapper_cmd,
88 ini_path=ini_path,
92 ini_path=ini_path,
89 user_id=user_id,
93 user_id=user_id,
90 user=username,
94 user=username,
91 user_key_id=user_key.ssh_key_id,
95 user_key_id=user_key.ssh_key_id,
92 key=user_key.ssh_key_data))
96 key=user_key.ssh_key_data))
93 log.debug('addkey: Key added for user: `%s`', username)
97 log.debug('addkey: Key added for user: `%s`', username)
94 keys_file.close()
98 keys_file.close()
95
99
96 # Explicitly setting read-only permissions to authorized_keys
100 # Explicitly setting read-only permissions to authorized_keys
97 os.chmod(tmp_authorized_keys, stat.S_IRUSR | stat.S_IWUSR)
101 os.chmod(tmp_authorized_keys, stat.S_IRUSR | stat.S_IWUSR)
98 # Rename is atomic operation
102 # Rename is atomic operation
99 os.rename(tmp_authorized_keys, authorized_keys_file_path)
103 os.rename(tmp_authorized_keys, authorized_keys_file_path)
100
104
101
105
102 def generate_ssh_authorized_keys_file(registry):
106 def generate_ssh_authorized_keys_file(registry):
103 log.info('Generating new authorized key file')
107 log.info('Generating new authorized key file')
104
108
105 authorized_keys_file_path = registry.settings.get(
109 authorized_keys_file_path = registry.settings.get(
106 config_keys.authorized_keys_file_path)
110 config_keys.authorized_keys_file_path)
107
111
108 ssh_wrapper_cmd = registry.settings.get(
112 ssh_wrapper_cmd = registry.settings.get(
109 config_keys.wrapper_cmd)
113 config_keys.wrapper_cmd)
110 allow_shell = registry.settings.get(
114 allow_shell = registry.settings.get(
111 config_keys.wrapper_allow_shell)
115 config_keys.wrapper_allow_shell)
112 ssh_opts = registry.settings.get(
116 ssh_opts = registry.settings.get(
113 config_keys.authorized_keys_line_ssh_opts)
117 config_keys.authorized_keys_line_ssh_opts)
114 debug = registry.settings.get(
118 debug = registry.settings.get(
115 config_keys.enable_debug_logging)
119 config_keys.enable_debug_logging)
116
120
117 _generate_ssh_authorized_keys_file(
121 _generate_ssh_authorized_keys_file(
118 authorized_keys_file_path, ssh_wrapper_cmd, allow_shell, ssh_opts,
122 authorized_keys_file_path, ssh_wrapper_cmd, allow_shell, ssh_opts,
119 debug)
123 debug)
120
124
121 return 0
125 return 0
General Comments 0
You need to be logged in to leave comments. Login now