Attachment 'hierachical-acl.diff'
Download 1 * looking for arch@arch.thinkmo.de--2003-archives/moin--main--1.3--patch-557 to compare with
2 * build pristine tree for arch@arch.thinkmo.de--2003-archives/moin--main--1.3--patch-557
3 * from pristine cache: arch@arch.thinkmo.de--2003-archives/moin--main--1.3--patch-556
4 * patching for revision: arch@arch.thinkmo.de--2003-archives/moin--main--1.3--patch-557
5 * comparing to arch@arch.thinkmo.de--2003-archives/moin--main--1.3--patch-557
6 M MoinMoin/PageEditor.py
7 M MoinMoin/multiconfig.py
8 M MoinMoin/security.py
9 M MoinMoin/wikiacl.py
10
11 * modified files
12
13 --- orig/MoinMoin/PageEditor.py
14 +++ mod/MoinMoin/PageEditor.py
15 @@ -904,8 +904,8 @@
16 # rights. This is a good place to update acl cache - instead
17 # of wating for next request.
18 acl = self.getACL(self.request)
19 - if (not acl.may(self.request, self.request.user.name, "admin") and
20 - parseACL(self.request, newtext) != acl and
21 + if (not self.request.user.may.admin(self.page_name) and
22 + parseACL(self.request, newtext).acl != acl.acl and
23 action != "SAVE/REVERT"):
24 msg = _("You can't change ACLs on this page since you have no admin rights on it!")
25 raise self.NoAdmin, msg
26
27
28 --- orig/MoinMoin/multiconfig.py
29 +++ mod/MoinMoin/multiconfig.py
30 @@ -151,6 +151,7 @@
31 FIXME: update according to MoinMoin:UpdateConfiguration
32 """
33 acl_enabled = 0
34 + acl_hierarchic = 0
35 # All acl_right lines must use unicode!
36 acl_rights_default = u"Trusted:read,write,delete,revert Known:read,write,delete,revert All:read,write"
37 acl_rights_before = u""
38 @@ -321,6 +322,13 @@
39 # e.g u'%(page_front_page)s' % self
40 self.navi_bar = [elem % self for elem in self.navi_bar]
41
42 + # precompile acl strings
43 + if self.acl_enabled:
44 + from wikiacl import AccessControlList
45 + self.acl_default = AccessControlList(None, [self.acl_rights_default], cfg=self)
46 + self.acl_before = AccessControlList(None, [self.acl_rights_before], cfg=self)
47 + self.acl_after = AccessControlList(None, [self.acl_rights_after], cfg=self)
48 +
49 def _config_check(self):
50 """ Check namespace and warn about unknown names
51
52
53
54 --- orig/MoinMoin/security.py
55 +++ mod/MoinMoin/security.py
56 @@ -22,8 +22,21 @@
57 class Permissions:
58 """ Basic interface for user permissions and system policy.
59
60 - Note that you still need to allow some of the related actions, this
61 - just controls their behaviour, not their activation.
62 + Note that you still need to allow some of the related actions, this
63 + just controls their behavior, not their activation.
64 +
65 + When sub classing this class, you must extend the class methods, not
66 + replace them, or you might break the acl in the wiki. Correct sub
67 + classing look like this:
68 +
69 + def read(self, pagename):
70 + # Your special security rule
71 + if somehting:
72 + return false
73 +
74 + # Do not return True or you break acl!
75 + # This call will use the default acl rules
76 + return Permissions.read(pagename)
77 """
78
79 def __init__(self, user):
80 @@ -32,27 +45,102 @@
81 from MoinMoin.Page import Page
82 self.Page = Page
83 self.name = user.name
84 + self.user = user
85 self.request = user._request
86
87 def save(self, editor, newtext, rev, **kw):
88 """ Check whether user may save a page.
89
90 - `editor` is the PageEditor instance, the other arguments are
91 - those of the `PageEditor.saveText` method.
92 + Default implementation ignore newtext, rev and kw, and just try
93 + to get permission for write.
94 +
95 + @param editor: PageEditor instance.
96 + @param newtext: new page text, you can enable of disable saving according
97 + to the content of the text, e.g. prevent link spam.
98 + @param rev: new revision number? XXX
99 + @param kw: XXX
100 + @rtype: bool
101 + @return: True if you can save or False
102 """
103 return self.write(editor.page_name)
104
105 def __getattr__(self, attr):
106 - """ if attr is one of the rights in acl_rights_valid, then return a
107 - checking function for it. Else raise an error.
108 + """ Shortcut to export getPermission function for all known acl rights
109 +
110 + if attr is one of the rights in acl_rights_valid, then return a
111 + checking function for it. Else use normal getattr().
112 +
113 + @param attr: one of acl known rights as defined in acl_rights_valid
114 + @rtype: function
115 + @return: checking function for that right, accepting a pagename
116 """
117 - request = self.request
118 - Page = self.Page
119 - if attr in request.cfg.acl_rights_valid:
120 - return lambda pagename, Page=Page, request=request, attr=attr: Page(request, pagename).getACL(request).may(request, self.name, attr)
121 + if attr in self.request.cfg.acl_rights_valid:
122 + self._right = attr
123 + return self._getPermission
124 else:
125 raise AttributeError, attr
126
127 + def _getPermission(self, pagename):
128 + """ Get permission by transversing page hierarchy
129 +
130 + If cfg.acl_hierarchic, we check each page in the hierarchy. If all
131 + pages agree, we have permission. If one page in the hierarchy
132 + does not agree, we don't. Otherwise, only pagename is checked.
133 +
134 + This method should not be called by users, use __getattr__
135 + instead. If you want to get permission for delete, try:
136 + instance.delete(pagename).
137 +
138 + @param pagename: pagename to get permission from
139 + @rtype: bool
140 + @return: True if you have permission or False
141 + """
142 + from MoinMoin.Page import Page
143 +
144 + # Use page hierarchy or only pagename, according to wiki config.
145 + if self.request.cfg.acl_hierarchic:
146 + pages = pagename.split('/')
147 + else:
148 + pages = [pagename]
149 +
150 + open('/tmp/acl.log','a').write('may(%s): pages %s\n'%(self._right, pages,))
151 + # check before
152 + allowed = self.request.cfg.acl_before.may(self.request, self.user.name, self._right)
153 + if allowed is not None:
154 + open('/tmp/acl.log','a').write('may: before returns %s\n'%(allowed,))
155 + return allowed
156 +
157 + # Get permission
158 + some_acl = False
159 + for i in range(len(pages), 0, -1):
160 + # Create the next pagename in the hierarchy
161 + # starting with the leave, going to the root
162 + name = '/'.join(pages[:i])
163 + # Get page acl and ask for permission
164 + acl = Page(self.request, name).getACL(self.request)
165 + open('/tmp/acl.log','a').write('may: checking acl of %s (%s)\n'%(name, `acl.acl`))
166 + if acl.acl:
167 + some_acl = True
168 + allowed = acl.may(self.request, self.user.name, self._right)
169 + if allowed is not None:
170 + open('/tmp/acl.log','a').write('may: acl of %s (%s) returns %s\n'%(name, `acl.acl`, allowed,))
171 + return allowed
172 + if not some_acl:
173 + allowed = self.request.cfg.acl_default.may(self.request, self.user.name, self._right)
174 + if allowed is not None:
175 + open('/tmp/acl.log','a').write('may: default returns %s\n'%(allowed,))
176 + return allowed
177 +
178 + # check after
179 + allowed = self.request.cfg.acl_after.may(self.request, self.user.name, self._right)
180 + if allowed is not None:
181 + open('/tmp/acl.log','a').write('may: after returns %s\n'%(allowed,))
182 + return allowed
183 +
184 + # sane default permission, if you want True,
185 + # just put 'All:read' (or more) into your acl_rights_after
186 + return False
187 +
188
189 # make an alias for the default policy
190 Default = Permissions
191
192
193 --- orig/MoinMoin/wikiacl.py
194 +++ mod/MoinMoin/wikiacl.py
195 @@ -113,33 +113,24 @@
196
197 special_users = ["All", "Known", "Trusted"]
198
199 - def __init__(self, request, lines=[]):
200 + def __init__(self, request, lines=[], cfg=None):
201 """Initialize an ACL, starting from <nothing>.
202 """
203 - self.setLines(request.cfg, lines)
204 + if cfg is not None:
205 + self.setLines(cfg, lines)
206 + else:
207 + self.setLines(request.cfg, lines)
208
209 def setLines(self, cfg, lines=[]):
210 self.clean()
211 - self.addBefore(cfg)
212 - if not lines:
213 - self.addDefault(cfg)
214 - else:
215 - for line in lines:
216 - self.addLine(cfg, line)
217 - self.addAfter(cfg)
218 + for line in lines:
219 + self.addLine(cfg, line)
220
221 def clean(self):
222 self.acl = [] # [ ('User', {"read": 0, ...}), ... ]
223 self.acl_lines = []
224 self._is_group = {}
225
226 - def addBefore(self, cfg):
227 - self.addLine(cfg, cfg.acl_rights_before, remember=0)
228 - def addDefault(self, cfg):
229 - self.addLine(cfg, cfg.acl_rights_default, remember=0)
230 - def addAfter(self, cfg):
231 - self.addLine(cfg, cfg.acl_rights_after, remember=0)
232 -
233 def addLine(self, cfg, aclstring, remember=1):
234 """ Add another ACL line
235
236 @@ -182,7 +173,7 @@
237 rightsdict[right] = (right in rights)
238 self.acl.append((entry, rightsdict))
239
240 - def may(self, request, name, dowhat):
241 + def may(self, request, name, dowhat, recurse=False):
242 """May <name> <dowhat>?
243 Returns boolean answer.
244 """
245 @@ -210,7 +201,7 @@
246 allowed = rightsdict.get(dowhat)
247 if allowed is not None:
248 return allowed
249 - return 0
250 + return allowed
251
252 def getString(self, b='#acl ', e='\n'):
253 """print the acl strings we were fed with"""
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.