id,summary,reporter,owner,description,type,status,priority,component,severity,resolution,keywords,cc,release
221,Patch for 0.9.3,heinlein@madboa.com,puffy,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.\r\n\r\nThe biggest change from 0.9.2 is that 0.9.3 no longer uses the `escape()` routine_ opting instead for one called `Markup()`.\r\n\r\nThe 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.\r\n\r\nAnyway_ 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."\r\n\r\nThanks for all your work coding this up. We needed just this sort of access control on our intranet wiki.\r\n\r\n--Paul\r\n\r\n{{{\r\n--- trac/wiki/web_ui.py.orig	2006-02-13 15:32:40.000000000 -0800\r\n+++ trac/wiki/web_ui.py	2006-02-13 15:32:09.000000000 -0800\r\n@@ -32_13 +32_15 @@\r\n from trac.web import IRequestHandler\r\n from trac.wiki.model import WikiPage\r\n from trac.wiki.formatter import wiki_to_html_ wiki_to_oneliner\r\n-\r\n+from trac.wiki.rbac import WikiAuthorizer\r\n \r\n class WikiModule(Component):\r\n \r\n     implements(INavigationContributor_ IPermissionRequestor_ IRequestHandler_\r\n                ITimelineEventProvider_ ISearchSource)\r\n \r\n+    authz = property(fget=lambda self: self._get_authz())\r\n+\r\n     # INavigationContributor methods\r\n \r\n     def get_active_navigation_item(self_ req):\r\n@@ -74_6 +76_7 @@\r\n         pagename = req.args.get('page'_ 'WikiStart')\r\n         version = req.args.get('version')\r\n \r\n+        self.authz.assert_authorization(req.perm_ req.authname_ pagename_ 'WIKI_VIEW')\r\n         db = self.env.get_db_cnx()\r\n         page = WikiPage(self.env_ pagename_ version_ db)\r\n \r\n@@ -118_6 +121_13 @@\r\n         req.hdf['wiki.action'] = action\r\n         req.hdf['wiki.page_name'] = page.name\r\n         req.hdf['wiki.current_href'] = self.env.href.wiki(page.name)\r\n+        for permission in self.get_permission_actions():\r\n+            if isinstance(permission_ (list_ tuple)):\r\n+                               permission = permission[0]\r\n+            self.log.debug("PERMISSION: %s"_ permission)\r\n+            req.hdf['trac.acl.' + permission] =\\\r\n+                self.authz.has_authorization(req.perm_ req.authname_ page.name_ permission)\r\n+\r\n         return 'wiki.cs'_ None\r\n \r\n     # ITimelineEventProvider methods\r\n@@ -135_24 +145_29 @@\r\n                            "FROM wiki WHERE time>=%s AND time<=%s"_\r\n                            (start_ stop))\r\n             for t_name_comment_author in cursor:\r\n-                title = Markup('<em>%s</em> edited by %s'_ name_ author)\r\n-                if format == 'rss':\r\n-                    href = self.env.abs_href.wiki(name)\r\n-                    comment = wiki_to_html(comment or '--'_ self.env_ req_ db_\r\n-                                           absurls=True)\r\n-                else:\r\n-                    href = self.env.href.wiki(name)\r\n-                    comment = wiki_to_oneliner(comment_ self.env_ db_\r\n-                                               shorten=True)\r\n-                yield 'wiki'_ href_ title_ t_ author_ comment\r\n+                if self.authz.has_authorization(req.perm_ req.authname_ name_ 'WIKI_VIEW'):\r\n+                    title = Markup('<em>%s</em> edited by %s'_ name_ author)\r\n+                    if format == 'rss':\r\n+                        href = self.env.abs_href.wiki(name)\r\n+                        comment = wiki_to_html(comment or '--'_ self.env_ req_ db_\r\n+                                               absurls=True)\r\n+                    else:\r\n+                        href = self.env.href.wiki(name)\r\n+                        comment = wiki_to_oneliner(comment_ self.env_ db_\r\n+                                                   shorten=True)\r\n+                    yield 'wiki'_ href_ title_ t_ author_ comment\r\n \r\n     # Internal methods\r\n \r\n+    def _get_authz(self):\r\n+        return WikiAuthorizer(self.env)\r\n+\r\n     def _do_delete(self_ req_ db_ page):\r\n         if page.readonly:\r\n             req.perm.assert_permission('WIKI_ADMIN')\r\n         else:\r\n             req.perm.assert_permission('WIKI_DELETE')\r\n+            self.authz.assert_authorization(req.perm_ req.authname_ page.name_ 'WIKI_DELETE')\r\n \r\n         if req.args.has_key('cancel'):\r\n             req.redirect(self.env.href.wiki(page.name))\r\n@@ -174_8 +189_10 @@\r\n             req.perm.assert_permission('WIKI_ADMIN')\r\n         elif not page.exists:\r\n             req.perm.assert_permission('WIKI_CREATE')\r\n+            self.authz.assert_authorization(req.perm_ req.authname_ page.name_ 'WIKI_CREATE')\r\n         else:\r\n             req.perm.assert_permission('WIKI_MODIFY')\r\n+            self.authz.assert_authorization(req.perm_ req.authname_ page.name_ 'WIKI_MODIFY')\r\n \r\n         page.text = req.args.get('text')\r\n         if req.perm.has_permission('WIKI_ADMIN'):\r\n@@ -192_6 +209_7 @@\r\n             req.perm.assert_permission('WIKI_ADMIN')\r\n         else:\r\n             req.perm.assert_permission('WIKI_DELETE')\r\n+            self.authz.assert_authorization(req.perm_ req.authname_ page.name_ 'WIKI_DELETE')\r\n \r\n         version = None\r\n         if req.args.has_key('delete_version'):\r\n@@ -210_6 +228_7 @@\r\n \r\n     def _render_diff(self_ req_ db_ page):\r\n         req.perm.assert_permission('WIKI_VIEW')\r\n+        self.authz.assert_authorization(req.perm_ req.authname_ page.name_ 'WIKI_VIEW')\r\n \r\n         if not page.exists:\r\n             raise TracError_ "Version %s of page %s does not exist" \\\r\n@@ -277_6 +296_7 @@\r\n \r\n     def _render_editor(self_ req_ db_ page_ preview=False):\r\n         req.perm.assert_permission('WIKI_MODIFY')\r\n+        self.authz.assert_authorization(req.perm_ req.authname_ page.name_ 'WIKI_MODIFY')\r\n \r\n         if req.args.has_key('text'):\r\n             page.text = req.args.get('text')\r\n@@ -320_6 +340_7 @@\r\n         page.\r\n         """\r\n         req.perm.assert_permission('WIKI_VIEW')\r\n+        self.authz.assert_authorization(req.perm_ req.authname_ page.name_ 'WIKI_VIEW')\r\n \r\n         if not page.exists:\r\n             raise TracError_ "Page %s does not exist" % page.name\r\n@@ -344_6 +365_7 @@\r\n \r\n     def _render_view(self_ req_ db_ page):\r\n         req.perm.assert_permission('WIKI_VIEW')\r\n+        self.authz.assert_authorization(req.perm_ req.authname_ page.name_ 'WIKI_VIEW')\r\n \r\n         if page.name == 'WikiStart':\r\n             req.hdf['title'] = ''\r\n@@ -365_7 +387_8 @@\r\n             history_href = self.env.href.wiki(page.name_ action='history')\r\n             req.hdf['wiki.history_href'] = history_href\r\n         else:\r\n-            if not req.perm.has_permission('WIKI_CREATE'):\r\n+            if not req.perm.has_permission('WIKI_CREATE') and\\\r\n+                self.authz.has_authorization(req.perm_ req.authname_ page.name_ 'WIKI_CREATE'):\r\n                 raise TracError('Page %s not found' % page.name)\r\n             req.hdf['wiki.page_html'] = Markup('<p>Describe "%s" here</p>'_\r\n                                                page.name)\r\n@@ -375_7 +398_8 @@\r\n         for attachment in Attachment.select(self.env_ 'wiki'_ page.name_ db):\r\n             attachments.append(attachment_to_hdf(self.env_ db_ req_ attachment))\r\n         req.hdf['wiki.attachments'] = attachments\r\n-        if req.perm.has_permission('WIKI_MODIFY'):\r\n+        if req.perm.has_permission('WIKI_MODIFY') and\\\r\n+            self.authz.has_authorization(req.perm_ req.authname_ page.name_ 'WIKI_MODIFY'):\r\n             attach_href = self.env.href.attachment('wiki'_ page.name)\r\n             req.hdf['wiki.attach_href'] = attach_href\r\n \r\n@@ -399_7 +423_8 @@\r\n                        "AND " + sql_query_ args)\r\n \r\n         for name_ date_ author_ text in cursor:\r\n-            yield (self.env.href.wiki(name)_\r\n-                   '%s: %s' % (name_ shorten_line(text))_\r\n-                   date_ author_\r\n-                   shorten_result(text_ query.split()))\r\n+            if self.authz.has_authorization(req.perm_ req.authname_ name_ 'WIKI_VIEW'):\r\n+                yield (self.env.href.wiki(name)_\r\n+                    '%s: %s' % (name_ shorten_line(text))_\r\n+                    date_ author_\r\n+                    shorten_result(text_ query.split()))\r\n--- trac/wiki/rbac.py.orig	2006-02-13 15:32:45.000000000 -0800\r\n+++ trac/wiki/rbac.py	2006-02-13 15:29:34.000000000 -0800\r\n@@ -0_0 +1_82 @@\r\n+from trac.core import *\r\n+from trac.perm import PermissionError\r\n+from trac.versioncontrol.svn_authz import RealSubversionAuthorizer\r\n+from trac.versioncontrol import Authorizer_ PermissionDenied\r\n+\r\n+def SubversionAuthorizer(env_ authname):\r\n+	authz_file = env.config.get('wiki'_ 'authz_file') or\\\r\n+		env.config.get('trac'_ 'authz_file')\r\n+	if not authz_file:\r\n+		return Authorizer()\r\n+	\r\n+	module_name = env.config.get('wiki'_ 'authz_svn_module_name')\r\n+	db = env.get_db_cnx()\r\n+	return ExtendedSubversionAuthorizer(db_ authname_ module_name_ authz_file)\r\n+\r\n+class IWikiAuthzProvider(Interface):\r\n+	"""Interface for classes that provide some method of checking a\r\n+		user's access to a portion of the wiki."""\r\n+\r\n+	def has_authorization(user_ path_ operation):\r\n+		"""Verify that the given username is authorized to perform\r\n+			the given operation on the given path.\r\n+			returns boolean."""\r\n+\r\n+class WikiAuthorizer(Component):\r\n+	providers = ExtensionPoint(IWikiAuthzProvider)\r\n+\r\n+	def _accumulate(self_ current_ result):\r\n+		authmode = self.env.config.get('wiki'_ 'authorization_mode')\r\n+\r\n+		if authmode == 'require_all':\r\n+			return current & result\r\n+		elif authmode == 'require_one':\r\n+			return current | result\r\n+		else:\r\n+			return True\r\n+\r\n+	def has_authorization(self_ perm_ user_ path_ operation):\r\n+		if not perm.has_permission('WIKI_VIEW'):\r\n+			return False\r\n+\r\n+		authzed = True\r\n+		for provider in self.providers:\r\n+			authzed = self._accumulate(authzed_ provider.has_authorization(user_ path_ operation))\r\n+		return authzed or perm.has_permission('TRAC_ADMIN')\r\n+\r\n+	def assert_authorization(self_ perm_ user_ path_ operation):\r\n+		if not self.has_authorization(perm_ user_ path_ operation):\r\n+			raise PermissionDenied_\\\r\n+				'%s authorization on %s is necessary to perform this operation.' % (operation_ 'wiki:' + path)\r\n+\r\n+\r\n+class WikiSubversionAuthorizer(Component):\r\n+	implements(IWikiAuthzProvider)\r\n+\r\n+	def has_authorization(self_ user_ path_ operation):\r\n+		path = '/' + path\r\n+		authorizer = SubversionAuthorizer(self.env_ user)\r\n+		self.log.debug("Authorize %s check for: %s on %s:%s"_ operation_ user_ authorizer.module_name_ path)\r\n+		return authorizer.has_authorization(path_ operation)\r\n+\r\n+class ExtendedSubversionAuthorizer(RealSubversionAuthorizer):\r\n+	"""Provides extended semantics for the subversion-based authorization"""\r\n+\r\n+	opmap = {'WIKI_CREATE':'c'_ 'WIKI_DELETE':'d'_ 'WIKI_MODIFY':'w'_ 'WIKI_VIEW':'r'_ 'WIKI_ADMIN':'a'}\r\n+\r\n+	def has_authorization(self_ path_ op):\r\n+		self._set_opcheck('WIKI_ADMIN')\r\n+		if self.has_permission(path):\r\n+			return True\r\n+		else:\r\n+			self._set_opcheck(op)\r\n+			return self.has_permission(path)\r\n+\r\n+	def _set_opcheck(self_ op):\r\n+		op = self.opmap[op]\r\n+		self._get_permission = lambda section_ subject: self.__get_permission(section_ subject_ op)\r\n+\r\n+	def __get_permission(self_ section_ subject_ op):\r\n+		if self.conf_authz.has_option(section_ subject):\r\n+			return op in self.conf_authz.get(section_ subject)\r\n+		return None\r\n}}},defect,closed,normal,WikiRbacPatch,major,fixed,,,0.9
