##// END OF EJS Templates
ssh: use proper way of extracting the HOOK_PROTOCOL out of vcssettings....
marcink -
r2212:dc0a58ba default
parent child Browse files
Show More
@@ -1,150 +1,149 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 sys
22 import sys
23 import json
23 import json
24 import logging
24 import logging
25
25
26 from rhodecode.lib.hooks_daemon import prepare_callback_daemon
26 from rhodecode.lib.hooks_daemon import prepare_callback_daemon
27 from rhodecode.lib import hooks_utils
27 from rhodecode.lib.vcs.conf import settings as vcs_settings
28 from rhodecode.model.scm import ScmModel
28 from rhodecode.model.scm import ScmModel
29
29
30 log = logging.getLogger(__name__)
30 log = logging.getLogger(__name__)
31
31
32
32
33 class VcsServer(object):
33 class VcsServer(object):
34 _path = None # set executable path for hg/git/svn binary
34 _path = None # set executable path for hg/git/svn binary
35 backend = None # set in child classes
35 backend = None # set in child classes
36 tunnel = None # subprocess handling tunnel
36 tunnel = None # subprocess handling tunnel
37 write_perms = ['repository.admin', 'repository.write']
37 write_perms = ['repository.admin', 'repository.write']
38 read_perms = ['repository.read', 'repository.admin', 'repository.write']
38 read_perms = ['repository.read', 'repository.admin', 'repository.write']
39
39
40 def __init__(self, user, user_permissions, config, env):
40 def __init__(self, user, user_permissions, config, env):
41 self.user = user
41 self.user = user
42 self.user_permissions = user_permissions
42 self.user_permissions = user_permissions
43 self.config = config
43 self.config = config
44 self.env = env
44 self.env = env
45 self.stdin = sys.stdin
45 self.stdin = sys.stdin
46
46
47 self.repo_name = None
47 self.repo_name = None
48 self.repo_mode = None
48 self.repo_mode = None
49 self.store = ''
49 self.store = ''
50 self.ini_path = ''
50 self.ini_path = ''
51
51
52 def _invalidate_cache(self, repo_name):
52 def _invalidate_cache(self, repo_name):
53 """
53 """
54 Set's cache for this repository for invalidation on next access
54 Set's cache for this repository for invalidation on next access
55
55
56 :param repo_name: full repo name, also a cache key
56 :param repo_name: full repo name, also a cache key
57 """
57 """
58 ScmModel().mark_for_invalidation(repo_name)
58 ScmModel().mark_for_invalidation(repo_name)
59
59
60 def has_write_perm(self):
60 def has_write_perm(self):
61 permission = self.user_permissions.get(self.repo_name)
61 permission = self.user_permissions.get(self.repo_name)
62 if permission in ['repository.write', 'repository.admin']:
62 if permission in ['repository.write', 'repository.admin']:
63 return True
63 return True
64
64
65 return False
65 return False
66
66
67 def _check_permissions(self, action):
67 def _check_permissions(self, action):
68 permission = self.user_permissions.get(self.repo_name)
68 permission = self.user_permissions.get(self.repo_name)
69 log.debug(
69 log.debug(
70 'permission for %s on %s are: %s',
70 'permission for %s on %s are: %s',
71 self.user, self.repo_name, permission)
71 self.user, self.repo_name, permission)
72
72
73 if action == 'pull':
73 if action == 'pull':
74 if permission in self.read_perms:
74 if permission in self.read_perms:
75 log.info(
75 log.info(
76 'READ Permissions for User "%s" detected to repo "%s"!',
76 'READ Permissions for User "%s" detected to repo "%s"!',
77 self.user, self.repo_name)
77 self.user, self.repo_name)
78 return 0
78 return 0
79 else:
79 else:
80 if permission in self.write_perms:
80 if permission in self.write_perms:
81 log.info(
81 log.info(
82 'WRITE+ Permissions for User "%s" detected to repo "%s"!',
82 'WRITE+ Permissions for User "%s" detected to repo "%s"!',
83 self.user, self.repo_name)
83 self.user, self.repo_name)
84 return 0
84 return 0
85
85
86 log.error('Cannot properly fetch or allow user %s permissions. '
86 log.error('Cannot properly fetch or allow user %s permissions. '
87 'Return value is: %s, req action: %s',
87 'Return value is: %s, req action: %s',
88 self.user, permission, action)
88 self.user, permission, action)
89 return -2
89 return -2
90
90
91 def update_environment(self, action, extras=None):
91 def update_environment(self, action, extras=None):
92
92
93 scm_data = {
93 scm_data = {
94 'ip': os.environ['SSH_CLIENT'].split()[0],
94 'ip': os.environ['SSH_CLIENT'].split()[0],
95 'username': self.user.username,
95 'username': self.user.username,
96 'action': action,
96 'action': action,
97 'repository': self.repo_name,
97 'repository': self.repo_name,
98 'scm': self.backend,
98 'scm': self.backend,
99 'config': self.ini_path,
99 'config': self.ini_path,
100 'make_lock': None,
100 'make_lock': None,
101 'locked_by': [None, None],
101 'locked_by': [None, None],
102 'server_url': None,
102 'server_url': None,
103 'is_shadow_repo': False,
103 'is_shadow_repo': False,
104 'hooks_module': 'rhodecode.lib.hooks_daemon',
104 'hooks_module': 'rhodecode.lib.hooks_daemon',
105 'hooks': ['push', 'pull'],
105 'hooks': ['push', 'pull'],
106 'SSH': True,
106 'SSH': True,
107 'SSH_PERMISSIONS': self.user_permissions.get(self.repo_name)
107 'SSH_PERMISSIONS': self.user_permissions.get(self.repo_name)
108 }
108 }
109 if extras:
109 if extras:
110 scm_data.update(extras)
110 scm_data.update(extras)
111 os.putenv("RC_SCM_DATA", json.dumps(scm_data))
111 os.putenv("RC_SCM_DATA", json.dumps(scm_data))
112
112
113 def get_root_store(self):
113 def get_root_store(self):
114 root_store = self.store
114 root_store = self.store
115 if not root_store.endswith('/'):
115 if not root_store.endswith('/'):
116 # always append trailing slash
116 # always append trailing slash
117 root_store = root_store + '/'
117 root_store = root_store + '/'
118 return root_store
118 return root_store
119
119
120 def _handle_tunnel(self, extras):
120 def _handle_tunnel(self, extras):
121 # pre-auth
121 # pre-auth
122 action = 'pull'
122 action = 'pull'
123 exit_code = self._check_permissions(action)
123 exit_code = self._check_permissions(action)
124 if exit_code:
124 if exit_code:
125 return exit_code, False
125 return exit_code, False
126
126
127 req = self.env['request']
127 req = self.env['request']
128 server_url = req.host_url + req.script_name
128 server_url = req.host_url + req.script_name
129 extras['server_url'] = server_url
129 extras['server_url'] = server_url
130
130
131 log.debug('Using %s binaries from path %s', self.backend, self._path)
131 log.debug('Using %s binaries from path %s', self.backend, self._path)
132 exit_code = self.tunnel.run(extras)
132 exit_code = self.tunnel.run(extras)
133
133
134 return exit_code, action == "push"
134 return exit_code, action == "push"
135
135
136 def run(self):
136 def run(self):
137 extras = {}
137 extras = {}
138 HOOKS_PROTOCOL = self.config.get('app:main', 'vcs.hooks.protocol')
139
138
140 callback_daemon, extras = prepare_callback_daemon(
139 callback_daemon, extras = prepare_callback_daemon(
141 extras, protocol=HOOKS_PROTOCOL,
140 extras, protocol=vcs_settings.HOOKS_PROTOCOL,
142 use_direct_calls=False)
141 use_direct_calls=False)
143
142
144 with callback_daemon:
143 with callback_daemon:
145 try:
144 try:
146 return self._handle_tunnel(extras)
145 return self._handle_tunnel(extras)
147 finally:
146 finally:
148 log.debug('Running cleanup with cache invalidation')
147 log.debug('Running cleanup with cache invalidation')
149 if self.repo_name:
148 if self.repo_name:
150 self._invalidate_cache(self.repo_name)
149 self._invalidate_cache(self.repo_name)
General Comments 0
You need to be logged in to leave comments. Login now