##// END OF EJS Templates
acl: 'util.never' used
Elifarley Callado Coelho Cruz -
r16764:ffb68b9d default
parent child Browse files
Show More
@@ -1,254 +1,254 b''
1 1 # acl.py - changeset access control for mercurial
2 2 #
3 3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 '''hooks for controlling repository access
9 9
10 10 This hook makes it possible to allow or deny write access to given
11 11 branches and paths of a repository when receiving incoming changesets
12 12 via pretxnchangegroup and pretxncommit.
13 13
14 14 The authorization is matched based on the local user name on the
15 15 system where the hook runs, and not the committer of the original
16 16 changeset (since the latter is merely informative).
17 17
18 18 The acl hook is best used along with a restricted shell like hgsh,
19 19 preventing authenticating users from doing anything other than pushing
20 20 or pulling. The hook is not safe to use if users have interactive
21 21 shell access, as they can then disable the hook. Nor is it safe if
22 22 remote users share an account, because then there is no way to
23 23 distinguish them.
24 24
25 25 The order in which access checks are performed is:
26 26
27 27 1) Deny list for branches (section ``acl.deny.branches``)
28 28 2) Allow list for branches (section ``acl.allow.branches``)
29 29 3) Deny list for paths (section ``acl.deny``)
30 30 4) Allow list for paths (section ``acl.allow``)
31 31
32 32 The allow and deny sections take key-value pairs.
33 33
34 34 Branch-based Access Control
35 35 ...........................
36 36
37 37 Use the ``acl.deny.branches`` and ``acl.allow.branches`` sections to
38 38 have branch-based access control. Keys in these sections can be
39 39 either:
40 40
41 41 - a branch name, or
42 42 - an asterisk, to match any branch;
43 43
44 44 The corresponding values can be either:
45 45
46 46 - a comma-separated list containing users and groups, or
47 47 - an asterisk, to match anyone;
48 48
49 49 Path-based Access Control
50 50 .........................
51 51
52 52 Use the ``acl.deny`` and ``acl.allow`` sections to have path-based
53 53 access control. Keys in these sections accept a subtree pattern (with
54 54 a glob syntax by default). The corresponding values follow the same
55 55 syntax as the other sections above.
56 56
57 57 Groups
58 58 ......
59 59
60 60 Group names must be prefixed with an ``@`` symbol. Specifying a group
61 61 name has the same effect as specifying all the users in that group.
62 62
63 63 You can define group members in the ``acl.groups`` section.
64 64 If a group name is not defined there, and Mercurial is running under
65 65 a Unix-like system, the list of users will be taken from the OS.
66 66 Otherwise, an exception will be raised.
67 67
68 68 Example Configuration
69 69 .....................
70 70
71 71 ::
72 72
73 73 [hooks]
74 74
75 75 # Use this if you want to check access restrictions at commit time
76 76 pretxncommit.acl = python:hgext.acl.hook
77 77
78 78 # Use this if you want to check access restrictions for pull, push,
79 79 # bundle and serve.
80 80 pretxnchangegroup.acl = python:hgext.acl.hook
81 81
82 82 [acl]
83 83 # Allow or deny access for incoming changes only if their source is
84 84 # listed here, let them pass otherwise. Source is "serve" for all
85 85 # remote access (http or ssh), "push", "pull" or "bundle" when the
86 86 # related commands are run locally.
87 87 # Default: serve
88 88 sources = serve
89 89
90 90 [acl.deny.branches]
91 91
92 92 # Everyone is denied to the frozen branch:
93 93 frozen-branch = *
94 94
95 95 # A bad user is denied on all branches:
96 96 * = bad-user
97 97
98 98 [acl.allow.branches]
99 99
100 100 # A few users are allowed on branch-a:
101 101 branch-a = user-1, user-2, user-3
102 102
103 103 # Only one user is allowed on branch-b:
104 104 branch-b = user-1
105 105
106 106 # The super user is allowed on any branch:
107 107 * = super-user
108 108
109 109 # Everyone is allowed on branch-for-tests:
110 110 branch-for-tests = *
111 111
112 112 [acl.deny]
113 113 # This list is checked first. If a match is found, acl.allow is not
114 114 # checked. All users are granted access if acl.deny is not present.
115 115 # Format for both lists: glob pattern = user, ..., @group, ...
116 116
117 117 # To match everyone, use an asterisk for the user:
118 118 # my/glob/pattern = *
119 119
120 120 # user6 will not have write access to any file:
121 121 ** = user6
122 122
123 123 # Group "hg-denied" will not have write access to any file:
124 124 ** = @hg-denied
125 125
126 126 # Nobody will be able to change "DONT-TOUCH-THIS.txt", despite
127 127 # everyone being able to change all other files. See below.
128 128 src/main/resources/DONT-TOUCH-THIS.txt = *
129 129
130 130 [acl.allow]
131 131 # if acl.allow is not present, all users are allowed by default
132 132 # empty acl.allow = no users allowed
133 133
134 134 # User "doc_writer" has write access to any file under the "docs"
135 135 # folder:
136 136 docs/** = doc_writer
137 137
138 138 # User "jack" and group "designers" have write access to any file
139 139 # under the "images" folder:
140 140 images/** = jack, @designers
141 141
142 142 # Everyone (except for "user6" and "@hg-denied" - see acl.deny above)
143 143 # will have write access to any file under the "resources" folder
144 144 # (except for 1 file. See acl.deny):
145 145 src/main/resources/** = *
146 146
147 147 .hgtags = release_engineer
148 148
149 149 '''
150 150
151 151 from mercurial.i18n import _
152 152 from mercurial import util, match
153 153 import getpass, urllib
154 154
155 155 testedwith = 'internal'
156 156
157 157 def _getusers(ui, group):
158 158
159 159 # First, try to use group definition from section [acl.groups]
160 160 hgrcusers = ui.configlist('acl.groups', group)
161 161 if hgrcusers:
162 162 return hgrcusers
163 163
164 164 ui.debug('acl: "%s" not defined in [acl.groups]\n' % group)
165 165 # If no users found in group definition, get users from OS-level group
166 166 try:
167 167 return util.groupmembers(group)
168 168 except KeyError:
169 169 raise util.Abort(_("group '%s' is undefined") % group)
170 170
171 171 def _usermatch(ui, user, usersorgroups):
172 172
173 173 if usersorgroups == '*':
174 174 return True
175 175
176 176 for ug in usersorgroups.replace(',', ' ').split():
177 177 if user == ug or ug.startswith('@') and user in _getusers(ui, ug[1:]):
178 178 return True
179 179
180 180 return False
181 181
182 182 def buildmatch(ui, repo, user, key):
183 183 '''return tuple of (match function, list enabled).'''
184 184 if not ui.has_section(key):
185 185 ui.debug('acl: %s not enabled\n' % key)
186 186 return None
187 187
188 188 pats = [pat for pat, users in ui.configitems(key)
189 189 if _usermatch(ui, user, users)]
190 190 ui.debug('acl: %s enabled, %d entries for user %s\n' %
191 191 (key, len(pats), user))
192 192
193 193 if not repo:
194 194 if pats:
195 195 return lambda b: '*' in pats or b in pats
196 return lambda b: False
196 return util.never
197 197
198 198 if pats:
199 199 return match.match(repo.root, '', pats)
200 200 return match.exact(repo.root, '', [])
201 201
202 202
203 203 def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
204 204 if hooktype not in ['pretxnchangegroup', 'pretxncommit']:
205 205 raise util.Abort(_('config error - hook type "%s" cannot stop '
206 206 'incoming changesets nor commits') % hooktype)
207 207 if (hooktype == 'pretxnchangegroup' and
208 208 source not in ui.config('acl', 'sources', 'serve').split()):
209 209 ui.debug('acl: changes have source "%s" - skipping\n' % source)
210 210 return
211 211
212 212 user = None
213 213 if source == 'serve' and 'url' in kwargs:
214 214 url = kwargs['url'].split(':')
215 215 if url[0] == 'remote' and url[1].startswith('http'):
216 216 user = urllib.unquote(url[3])
217 217
218 218 if user is None:
219 219 user = getpass.getuser()
220 220
221 221 ui.debug('acl: checking access for user "%s"\n' % user)
222 222
223 223 cfg = ui.config('acl', 'config')
224 224 if cfg:
225 225 ui.readconfig(cfg, sections = ['acl.groups', 'acl.allow.branches',
226 226 'acl.deny.branches', 'acl.allow', 'acl.deny'])
227 227
228 228 allowbranches = buildmatch(ui, None, user, 'acl.allow.branches')
229 229 denybranches = buildmatch(ui, None, user, 'acl.deny.branches')
230 230 allow = buildmatch(ui, repo, user, 'acl.allow')
231 231 deny = buildmatch(ui, repo, user, 'acl.deny')
232 232
233 233 for rev in xrange(repo[node], len(repo)):
234 234 ctx = repo[rev]
235 235 branch = ctx.branch()
236 236 if denybranches and denybranches(branch):
237 237 raise util.Abort(_('acl: user "%s" denied on branch "%s"'
238 238 ' (changeset "%s")')
239 239 % (user, branch, ctx))
240 240 if allowbranches and not allowbranches(branch):
241 241 raise util.Abort(_('acl: user "%s" not allowed on branch "%s"'
242 242 ' (changeset "%s")')
243 243 % (user, branch, ctx))
244 244 ui.debug('acl: branch access granted: "%s" on branch "%s"\n'
245 245 % (ctx, branch))
246 246
247 247 for f in ctx.files():
248 248 if deny and deny(f):
249 249 raise util.Abort(_('acl: user "%s" denied on "%s"'
250 250 ' (changeset "%s")') % (user, f, ctx))
251 251 if allow and not allow(f):
252 252 raise util.Abort(_('acl: user "%s" not allowed on "%s"'
253 253 ' (changeset "%s")') % (user, f, ctx))
254 254 ui.debug('acl: path access granted: "%s"\n' % ctx)
General Comments 0
You need to be logged in to leave comments. Login now