comparison mercurial/hgweb/hgweb_mod.py @ 2466:e10665147d26

push over http: server side authorization support. new hgrc entries allow_push, deny_push, push_ssl control push over http. allow_push list controls push. if empty or not set, no user can push. if "*", any user (incl. unauthenticated user) can push. if list of user names, only authenticated users in list can push. deny_push list examined before allow_push. if "*", no user can push. if list of user names, no unauthenticated user can push, and no users in list can push. push_ssl requires https connection for push. default is true, so password sniffing can not be done.
author Vadim Gelfer <vadim.gelfer@gmail.com>
date Tue, 20 Jun 2006 15:23:01 -0700
parents 09b1c9ef317c
children 76ff5efe8181 d0db3462d568
comparison
equal deleted inserted replaced
2465:c91118f425d0 2466:e10665147d26
837 def do_capabilities(self, req): 837 def do_capabilities(self, req):
838 resp = 'unbundle' 838 resp = 'unbundle'
839 req.httphdr("application/mercurial-0.1", length=len(resp)) 839 req.httphdr("application/mercurial-0.1", length=len(resp))
840 req.write(resp) 840 req.write(resp)
841 841
842 def check_perm(self, req, op, default):
843 '''check permission for operation based on user auth.
844 return true if op allowed, else false.
845 default is policy to use if no config given.'''
846
847 user = req.env.get('REMOTE_USER')
848
849 deny = self.repo.ui.config('web', 'deny_' + op, '')
850 deny = deny.replace(',', ' ').split()
851
852 if deny and (not user or deny == ['*'] or user in deny):
853 return False
854
855 allow = self.repo.ui.config('web', 'allow_' + op, '')
856 allow = allow.replace(',', ' ').split()
857
858 return (allow and (allow == ['*'] or user in allow)) or default
859
842 def do_unbundle(self, req): 860 def do_unbundle(self, req):
861 def bail(response, headers={}):
862 length = int(req.env['CONTENT_LENGTH'])
863 for s in util.filechunkiter(req, limit=length):
864 # drain incoming bundle, else client will not see
865 # response when run outside cgi script
866 pass
867 req.httphdr("application/mercurial-0.1", headers=headers)
868 req.write('0\n')
869 req.write(response)
870
871 # require ssl by default, auth info cannot be sniffed and
872 # replayed
873 ssl_req = self.repo.ui.configbool('web', 'push_ssl', True)
874 if ssl_req and not req.env.get('HTTPS'):
875 bail(_('ssl required\n'))
876 return
877
878 # do not allow push unless explicitly allowed
879 if not self.check_perm(req, 'push', False):
880 bail(_('push not authorized\n'),
881 headers={'status': '401 Unauthorized'})
882 return
883
884 req.httphdr("application/mercurial-0.1")
885
843 their_heads = req.form['heads'][0].split(' ') 886 their_heads = req.form['heads'][0].split(' ')
844 887
845 def check_heads(): 888 def check_heads():
846 heads = map(hex, self.repo.heads()) 889 heads = map(hex, self.repo.heads())
847 return their_heads == [hex('force')] or their_heads == heads 890 return their_heads == [hex('force')] or their_heads == heads
848 891
849 req.httphdr("application/mercurial-0.1")
850
851 # fail early if possible 892 # fail early if possible
852 if not check_heads(): 893 if not check_heads():
853 req.write('0\n') 894 bail(_('unsynced changes\n'))
854 req.write(_('unsynced changes\n'))
855 return 895 return
856 896
857 # do not lock repo until all changegroup data is 897 # do not lock repo until all changegroup data is
858 # streamed. save to temporary file. 898 # streamed. save to temporary file.
859 899