Modify

Opened 18 years ago

Closed 18 years ago

#221 closed defect (fixed)

Patch for 0.9.3

Reported by: heinlein@… Owned by: puffy
Priority: normal Component: WikiRbacPatch
Severity: major Keywords:
Cc: Trac Release: 0.9

Description

The existing patch doesn't apply cleanly on 0.9.3 or 0.9.4. Here's a diff that works for us. It was written for 0.9.3, but it seems to work on 0.9.4 just as well.

The biggest change from 0.9.2 is that 0.9.3 no longer uses the escape() routine, opting instead for one called Markup().

The only other issue I encountered is that in the very last section of the original (0.9.2) patch of web_ui.py, self.authz.has_authorization() was passed only three parameters. As far as I can tell, it needs four -- so the second one is now req.authname. I'm most definitely not a python hacker, so you might want to double check that for me.

Anyway, the patch seems to work here, but I don't have a set of regression tests, so my QA is mostly along the lines of, "That page works... And that one... And that one... OK, everything looks right."

Thanks for all your work coding this up. We needed just this sort of access control on our intranet wiki.

--Paul

--- trac/wiki/web_ui.py.orig	2006-02-13 15:32:40.000000000 -0800
+++ trac/wiki/web_ui.py	2006-02-13 15:32:09.000000000 -0800
@@ -32,13 +32,15 @@
 from trac.web import IRequestHandler
 from trac.wiki.model import WikiPage
 from trac.wiki.formatter import wiki_to_html, wiki_to_oneliner
-
+from trac.wiki.rbac import WikiAuthorizer
 
 class WikiModule(Component):
 
     implements(INavigationContributor, IPermissionRequestor, IRequestHandler,
                ITimelineEventProvider, ISearchSource)
 
+    authz = property(fget=lambda self: self._get_authz())
+
     # INavigationContributor methods
 
     def get_active_navigation_item(self, req):
@@ -74,6 +76,7 @@
         pagename = req.args.get('page', 'WikiStart')
         version = req.args.get('version')
 
+        self.authz.assert_authorization(req.perm, req.authname, pagename, 'WIKI_VIEW')
         db = self.env.get_db_cnx()
         page = WikiPage(self.env, pagename, version, db)
 
@@ -118,6 +121,13 @@
         req.hdf['wiki.action'] = action
         req.hdf['wiki.page_name'] = page.name
         req.hdf['wiki.current_href'] = self.env.href.wiki(page.name)
+        for permission in self.get_permission_actions():
+            if isinstance(permission, (list, tuple)):
+                               permission = permission[0]
+            self.log.debug("PERMISSION: %s", permission)
+            req.hdf['trac.acl.' + permission] =\
+                self.authz.has_authorization(req.perm, req.authname, page.name, permission)
+
         return 'wiki.cs', None
 
     # ITimelineEventProvider methods
@@ -135,24 +145,29 @@
                            "FROM wiki WHERE time>=%s AND time<=%s",
                            (start, stop))
             for t,name,comment,author in cursor:
-                title = Markup('<em>%s</em> edited by %s', name, author)
-                if format == 'rss':
-                    href = self.env.abs_href.wiki(name)
-                    comment = wiki_to_html(comment or '--', self.env, req, db,
-                                           absurls=True)
-                else:
-                    href = self.env.href.wiki(name)
-                    comment = wiki_to_oneliner(comment, self.env, db,
-                                               shorten=True)
-                yield 'wiki', href, title, t, author, comment
+                if self.authz.has_authorization(req.perm, req.authname, name, 'WIKI_VIEW'):
+                    title = Markup('<em>%s</em> edited by %s', name, author)
+                    if format == 'rss':
+                        href = self.env.abs_href.wiki(name)
+                        comment = wiki_to_html(comment or '--', self.env, req, db,
+                                               absurls=True)
+                    else:
+                        href = self.env.href.wiki(name)
+                        comment = wiki_to_oneliner(comment, self.env, db,
+                                                   shorten=True)
+                    yield 'wiki', href, title, t, author, comment
 
     # Internal methods
 
+    def _get_authz(self):
+        return WikiAuthorizer(self.env)
+
     def _do_delete(self, req, db, page):
         if page.readonly:
             req.perm.assert_permission('WIKI_ADMIN')
         else:
             req.perm.assert_permission('WIKI_DELETE')
+            self.authz.assert_authorization(req.perm, req.authname, page.name, 'WIKI_DELETE')
 
         if req.args.has_key('cancel'):
             req.redirect(self.env.href.wiki(page.name))
@@ -174,8 +189,10 @@
             req.perm.assert_permission('WIKI_ADMIN')
         elif not page.exists:
             req.perm.assert_permission('WIKI_CREATE')
+            self.authz.assert_authorization(req.perm, req.authname, page.name, 'WIKI_CREATE')
         else:
             req.perm.assert_permission('WIKI_MODIFY')
+            self.authz.assert_authorization(req.perm, req.authname, page.name, 'WIKI_MODIFY')
 
         page.text = req.args.get('text')
         if req.perm.has_permission('WIKI_ADMIN'):
@@ -192,6 +209,7 @@
             req.perm.assert_permission('WIKI_ADMIN')
         else:
             req.perm.assert_permission('WIKI_DELETE')
+            self.authz.assert_authorization(req.perm, req.authname, page.name, 'WIKI_DELETE')
 
         version = None
         if req.args.has_key('delete_version'):
@@ -210,6 +228,7 @@
 
     def _render_diff(self, req, db, page):
         req.perm.assert_permission('WIKI_VIEW')
+        self.authz.assert_authorization(req.perm, req.authname, page.name, 'WIKI_VIEW')
 
         if not page.exists:
             raise TracError, "Version %s of page %s does not exist" \
@@ -277,6 +296,7 @@
 
     def _render_editor(self, req, db, page, preview=False):
         req.perm.assert_permission('WIKI_MODIFY')
+        self.authz.assert_authorization(req.perm, req.authname, page.name, 'WIKI_MODIFY')
 
         if req.args.has_key('text'):
             page.text = req.args.get('text')
@@ -320,6 +340,7 @@
         page.
         """
         req.perm.assert_permission('WIKI_VIEW')
+        self.authz.assert_authorization(req.perm, req.authname, page.name, 'WIKI_VIEW')
 
         if not page.exists:
             raise TracError, "Page %s does not exist" % page.name
@@ -344,6 +365,7 @@
 
     def _render_view(self, req, db, page):
         req.perm.assert_permission('WIKI_VIEW')
+        self.authz.assert_authorization(req.perm, req.authname, page.name, 'WIKI_VIEW')
 
         if page.name == 'WikiStart':
             req.hdf['title'] = ''
@@ -365,7 +387,8 @@
             history_href = self.env.href.wiki(page.name, action='history')
             req.hdf['wiki.history_href'] = history_href
         else:
-            if not req.perm.has_permission('WIKI_CREATE'):
+            if not req.perm.has_permission('WIKI_CREATE') and\
+                self.authz.has_authorization(req.perm, req.authname, page.name, 'WIKI_CREATE'):
                 raise TracError('Page %s not found' % page.name)
             req.hdf['wiki.page_html'] = Markup('<p>Describe "%s" here</p>',
                                                page.name)
@@ -375,7 +398,8 @@
         for attachment in Attachment.select(self.env, 'wiki', page.name, db):
             attachments.append(attachment_to_hdf(self.env, db, req, attachment))
         req.hdf['wiki.attachments'] = attachments
-        if req.perm.has_permission('WIKI_MODIFY'):
+        if req.perm.has_permission('WIKI_MODIFY') and\
+            self.authz.has_authorization(req.perm, req.authname, page.name, 'WIKI_MODIFY'):
             attach_href = self.env.href.attachment('wiki', page.name)
             req.hdf['wiki.attach_href'] = attach_href
 
@@ -399,7 +423,8 @@
                        "AND " + sql_query, args)
 
         for name, date, author, text in cursor:
-            yield (self.env.href.wiki(name),
-                   '%s: %s' % (name, shorten_line(text)),
-                   date, author,
-                   shorten_result(text, query.split()))
+            if self.authz.has_authorization(req.perm, req.authname, name, 'WIKI_VIEW'):
+                yield (self.env.href.wiki(name),
+                    '%s: %s' % (name, shorten_line(text)),
+                    date, author,
+                    shorten_result(text, query.split()))
--- trac/wiki/rbac.py.orig	2006-02-13 15:32:45.000000000 -0800
+++ trac/wiki/rbac.py	2006-02-13 15:29:34.000000000 -0800
@@ -0,0 +1,82 @@
+from trac.core import *
+from trac.perm import PermissionError
+from trac.versioncontrol.svn_authz import RealSubversionAuthorizer
+from trac.versioncontrol import Authorizer, PermissionDenied
+
+def SubversionAuthorizer(env, authname):
+	authz_file = env.config.get('wiki', 'authz_file') or\
+		env.config.get('trac', 'authz_file')
+	if not authz_file:
+		return Authorizer()
+	
+	module_name = env.config.get('wiki', 'authz_svn_module_name')
+	db = env.get_db_cnx()
+	return ExtendedSubversionAuthorizer(db, authname, module_name, authz_file)
+
+class IWikiAuthzProvider(Interface):
+	"""Interface for classes that provide some method of checking a
+		user's access to a portion of the wiki."""
+
+	def has_authorization(user, path, operation):
+		"""Verify that the given username is authorized to perform
+			the given operation on the given path.
+			returns boolean."""
+
+class WikiAuthorizer(Component):
+	providers = ExtensionPoint(IWikiAuthzProvider)
+
+	def _accumulate(self, current, result):
+		authmode = self.env.config.get('wiki', 'authorization_mode')
+
+		if authmode == 'require_all':
+			return current & result
+		elif authmode == 'require_one':
+			return current | result
+		else:
+			return True
+
+	def has_authorization(self, perm, user, path, operation):
+		if not perm.has_permission('WIKI_VIEW'):
+			return False
+
+		authzed = True
+		for provider in self.providers:
+			authzed = self._accumulate(authzed, provider.has_authorization(user, path, operation))
+		return authzed or perm.has_permission('TRAC_ADMIN')
+
+	def assert_authorization(self, perm, user, path, operation):
+		if not self.has_authorization(perm, user, path, operation):
+			raise PermissionDenied,\
+				'%s authorization on %s is necessary to perform this operation.' % (operation, 'wiki:' + path)
+
+
+class WikiSubversionAuthorizer(Component):
+	implements(IWikiAuthzProvider)
+
+	def has_authorization(self, user, path, operation):
+		path = '/' + path
+		authorizer = SubversionAuthorizer(self.env, user)
+		self.log.debug("Authorize %s check for: %s on %s:%s", operation, user, authorizer.module_name, path)
+		return authorizer.has_authorization(path, operation)
+
+class ExtendedSubversionAuthorizer(RealSubversionAuthorizer):
+	"""Provides extended semantics for the subversion-based authorization"""
+
+	opmap = {'WIKI_CREATE':'c', 'WIKI_DELETE':'d', 'WIKI_MODIFY':'w', 'WIKI_VIEW':'r', 'WIKI_ADMIN':'a'}
+
+	def has_authorization(self, path, op):
+		self._set_opcheck('WIKI_ADMIN')
+		if self.has_permission(path):
+			return True
+		else:
+			self._set_opcheck(op)
+			return self.has_permission(path)
+
+	def _set_opcheck(self, op):
+		op = self.opmap[op]
+		self._get_permission = lambda section, subject: self.__get_permission(section, subject, op)
+
+	def __get_permission(self, section, subject, op):
+		if self.conf_authz.has_option(section, subject):
+			return op in self.conf_authz.get(section, subject)
+		return None

Attachments (1)

rbac-0.9.3.patch.txt (10.1 KB) - added by anonymous 18 years ago.
Patch for 0.9.3 or 0.9.4

Download all attachments as: .zip

Change History (6)

comment:1 Changed 18 years ago by mark@…

Trac Release: 0.9
Type: enhancementdefect

Hi Paul,

please attach your patch to this ticket. The inline one has its indentation broken.

Thanks,

Mark

Changed 18 years ago by anonymous

Attachment: rbac-0.9.3.patch.txt added

Patch for 0.9.3 or 0.9.4

comment:2 Changed 18 years ago by heinlein@…

The patch added a couple minutes ago by "anonymous" is mine. I forgot to enter my address before attaching the file.

Paul

comment:3 Changed 18 years ago by mark@…

Resolution: duplicate
Status: newclosed

I have just noticed there is no need for newer patches, as this functionality is already implemented: http://projects.edgewall.com/trac/wiki/FineGrainedPermissions

I believe puffy should mention that on WikiRbacPatch?'s-site.

Anyway, thanks for th updated patch!

comment:4 Changed 18 years ago by Noah Kantrowitz

Resolution: duplicate
Status: closedreopened

Trac's fine-grained permissions system has nothing to do with the wiki, it is for the repository browser only.

comment:5 Changed 18 years ago by kempf@…

Resolution: fixed
Status: reopenedclosed

fixed in [634]

Modify Ticket

Change Properties
Set your email in Preferences
Action
as closed The owner will remain puffy.
The resolution will be deleted. Next status will be 'reopened'.

Add Comment


E-mail address and name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.