##// END OF EJS Templates
Rewrite simehg for enabling cloning with raw url for anonymous access + some optimizations for making less queries when authenticating users....
marcink -
r910:811fa5d4 beta
parent child Browse files
Show More
@@ -76,13 +76,16 b' class SummaryController(BaseController):'
76 76 e = request.environ
77 77
78 78 if self.rhodecode_user.username == 'default':
79 password = ':default'
79 #for default(anonymous) user we don't need to pass credentials
80 username = ''
81 password = ''
80 82 else:
83 username = str(c.rhodecode_user.username)
81 84 password = ''
82 85
83 86 uri = u'%(protocol)s://%(user)s%(password)s@%(host)s%(prefix)s/%(repo_name)s' % {
84 87 'protocol': e.get('wsgi.url_scheme'),
85 'user':str(c.rhodecode_user.username),
88 'user':username,
86 89 'password':password,
87 90 'host':e.get('HTTP_HOST'),
88 91 'prefix':e.get('SCRIPT_NAME'),
@@ -26,19 +26,23 b''
26 26 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
27 27 # MA 02110-1301, USA.
28 28
29 import os
30 import logging
31 import traceback
32
29 33 from mercurial.error import RepoError
30 34 from mercurial.hgweb import hgweb
31 35 from mercurial.hgweb.request import wsgiapplication
36
32 37 from paste.auth.basic import AuthBasicAuthenticator
33 38 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
39
34 40 from rhodecode.lib.auth import authfunc, HasPermissionAnyMiddleware
35 41 from rhodecode.lib.utils import make_ui, invalidate_cache, \
36 42 check_repo_fast, ui_sections
37 43 from rhodecode.model.user import UserModel
44
38 45 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
39 import logging
40 import os
41 import traceback
42 46
43 47 log = logging.getLogger(__name__)
44 48
@@ -59,7 +63,7 b' class SimpleHg(object):'
59 63 #authenticate this mercurial request using authfunc
60 64 self.authenticate = AuthBasicAuthenticator('', authfunc)
61 65 self.ipaddr = '0.0.0.0'
62 self.repository = None
66 self.repo_name = None
63 67 self.username = None
64 68 self.action = None
65 69
@@ -72,12 +76,41 b' class SimpleHg(object):'
72 76 self.ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0'))
73 77 # skip passing error to error controller
74 78 environ['pylons.status_code_redirect'] = True
75 #===================================================================
76 # AUTHENTICATE THIS MERCURIAL REQUEST
77 #===================================================================
78 username = REMOTE_USER(environ)
79
80 #======================================================================
81 # GET ACTION PULL or PUSH
82 #======================================================================
83 self.action = self.__get_action(environ)
84 try:
85 #==================================================================
86 # GET REPOSITORY NAME
87 #==================================================================
88 self.repo_name = self.__get_repository(environ)
89 except:
90 return HTTPInternalServerError()(environ, start_response)
79 91
80 if not username:
92 #======================================================================
93 # CHECK ANONYMOUS PERMISSION
94 #======================================================================
95 if self.action in ['pull', 'push']:
96 anonymous_user = self.__get_user('default')
97 self.username = anonymous_user.username
98 anonymous_perm = self.__check_permission(self.action, anonymous_user ,
99 self.repo_name)
100
101 if anonymous_perm is not True or anonymous_user.active is False:
102 if anonymous_perm is not True:
103 log.debug('Not enough credentials to access this repository'
104 'as anonymous user')
105 if anonymous_user.active is False:
106 log.debug('Anonymous access is disabled, running '
107 'authentication')
108 #==================================================================
109 # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE NEED
110 # TO AUTHENTICATE AND ASK FOR AUTHENTICATED USER PERMISSIONS
111 #==================================================================
112
113 if not REMOTE_USER(environ):
81 114 self.authenticate.realm = self.config['rhodecode_realm']
82 115 result = self.authenticate(environ)
83 116 if isinstance(result, str):
@@ -86,23 +119,13 b' class SimpleHg(object):'
86 119 else:
87 120 return result.wsgi_application(environ, start_response)
88 121
89 #=======================================================================
90 # GET REPOSITORY
91 #=======================================================================
92 try:
93 repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
94 if repo_name.endswith('/'):
95 repo_name = repo_name.rstrip('/')
96 self.repository = repo_name
97 except:
98 log.error(traceback.format_exc())
99 return HTTPInternalServerError()(environ, start_response)
100 122
101 #===================================================================
102 # CHECK PERMISSIONS FOR THIS REQUEST
103 #===================================================================
104 self.action = self.__get_action(environ)
105 if self.action:
123 #==================================================================
124 # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME FROM
125 # BASIC AUTH
126 #==================================================================
127
128 if self.action in ['pull', 'push']:
106 129 username = self.__get_environ_user(environ)
107 130 try:
108 131 user = self.__get_user(username)
@@ -112,24 +135,14 b' class SimpleHg(object):'
112 135 return HTTPInternalServerError()(environ, start_response)
113 136
114 137 #check permissions for this repository
115 if self.action == 'push':
116 if not HasPermissionAnyMiddleware('repository.write',
117 'repository.admin')\
118 (user, repo_name):
119 return HTTPForbidden()(environ, start_response)
120
121 else:
122 #any other action need at least read permission
123 if not HasPermissionAnyMiddleware('repository.read',
124 'repository.write',
125 'repository.admin')\
126 (user, repo_name):
138 perm = self.__check_permission(self.action, user, self.repo_name)
139 if perm is not True:
127 140 return HTTPForbidden()(environ, start_response)
128 141
129 142 self.extras = {'ip':self.ipaddr,
130 143 'username':self.username,
131 144 'action':self.action,
132 'repository':self.repository}
145 'repository':self.repo_name}
133 146
134 147 #===================================================================
135 148 # MERCURIAL REQUEST HANDLING
@@ -137,10 +150,10 b' class SimpleHg(object):'
137 150 environ['PATH_INFO'] = '/'#since we wrap into hgweb, reset the path
138 151 self.baseui = make_ui('db')
139 152 self.basepath = self.config['base_path']
140 self.repo_path = os.path.join(self.basepath, repo_name)
153 self.repo_path = os.path.join(self.basepath, self.repo_name)
141 154
142 155 #quick check if that dir exists...
143 if check_repo_fast(repo_name, self.basepath):
156 if check_repo_fast(self.repo_name, self.basepath):
144 157 return HTTPNotFound()(environ, start_response)
145 158 try:
146 159 app = wsgiapplication(self.__make_app)
@@ -153,15 +166,60 b' class SimpleHg(object):'
153 166
154 167 #invalidate cache on push
155 168 if self.action == 'push':
156 self.__invalidate_cache(repo_name)
169 self.__invalidate_cache(self.repo_name)
157 170
158 171 return app(environ, start_response)
159 172
160 173
161 174 def __make_app(self):
175 """Make an wsgi application using hgweb, and my generated baseui
176 instance
177 """
178
162 179 hgserve = hgweb(str(self.repo_path), baseui=self.baseui)
163 180 return self.__load_web_settings(hgserve, self.extras)
164 181
182
183 def __check_permission(self, action, user, repo_name):
184 """Checks permissions using action (push/pull) user and repository
185 name
186
187 :param action: push or pull action
188 :param user: user instance
189 :param repo_name: repository name
190 """
191 if action == 'push':
192 if not HasPermissionAnyMiddleware('repository.write',
193 'repository.admin')\
194 (user, repo_name):
195 return False
196
197 else:
198 #any other action need at least read permission
199 if not HasPermissionAnyMiddleware('repository.read',
200 'repository.write',
201 'repository.admin')\
202 (user, repo_name):
203 return False
204
205 return True
206
207
208 def __get_repository(self, environ):
209 """Get's repository name out of PATH_INFO header
210
211 :param environ: environ where PATH_INFO is stored
212 """
213 try:
214 repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
215 if repo_name.endswith('/'):
216 repo_name = repo_name.rstrip('/')
217 except:
218 log.error(traceback.format_exc())
219 raise
220
221 return repo_name
222
165 223 def __get_environ_user(self, environ):
166 224 return environ.get('REMOTE_USER')
167 225
@@ -171,6 +229,7 b' class SimpleHg(object):'
171 229 def __get_action(self, environ):
172 230 """Maps mercurial request commands into a clone,pull or push command.
173 231 This should always return a valid command string
232
174 233 :param environ:
175 234 """
176 235 mapping = {'changegroup': 'pull',
@@ -23,7 +23,7 b' from rhodecode.tests import TESTS_TMP_PA'
23 23 USER = 'test_admin'
24 24 PASS = 'test12'
25 25 HOST = '127.0.0.1:5000'
26
26 DEBUG = True
27 27 log = logging.getLogger(__name__)
28 28
29 29
@@ -38,16 +38,18 b' class Command(object):'
38 38
39 39 command = cmd + ' ' + ' '.join(args)
40 40 log.debug('Executing %s' % command)
41 if DEBUG:
41 42 print command
42 43 p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE, cwd=self.cwd)
43 44 stdout, stderr = p.communicate()
45 if DEBUG:
44 46 print stdout, stderr
45 47 return stdout, stderr
46 48
47 49
48 #===============================================================================
50 #==============================================================================
49 51 # TESTS
50 #===============================================================================
52 #==============================================================================
51 53 def test_clone():
52 54 cwd = path = jn(TESTS_TMP_PATH, HG_REPO)
53 55
@@ -215,9 +217,10 b' def test_push_wrong_path():'
215 217
216 218 if __name__ == '__main__':
217 219 test_clone()
218 test_clone_wrong_credentials()
220
221 #test_clone_wrong_credentials()
219 222 ##test_clone_anonymous_ok()
220
223 test_pull()
221 224 #test_push_new_file()
222 225 #test_push_wrong_path()
223 226 #test_push_wrong_credentials()
General Comments 0
You need to be logged in to leave comments. Login now