|  | 1 | = Fine grained permissions | 
          
            |  | 2 | [[PageOutline(2-5, Contents, floated)]] | 
          
            |  | 3 | [[TracGuideToc]] | 
          
            |  | 4 |  | 
          
            |  | 5 | There is a general mechanism in place that allows custom **permission policies** to grant or deny any action on any Trac resource, or even specific versions of a resource. | 
          
            |  | 6 |  | 
          
            |  | 7 | That mechanism is `AuthzPolicy`, an optional component in `tracopt.perm.authz_policy.*` which is not activated by default. It can be activated via the //Plugins// panel in the Trac administration module. | 
          
            |  | 8 |  | 
          
            |  | 9 | See TracPermissions for a more general introduction to Trac permissions and permission policies. | 
          
            |  | 10 |  | 
          
            |  | 11 | == Permission Policies | 
          
            |  | 12 |  | 
          
            |  | 13 | A great diversity of permission policies can be implemented and Trac comes with a few examples. | 
          
            |  | 14 |  | 
          
            |  | 15 | The active policies are determined by a [TracIni#trac-permission_policies-option configuration setting]: | 
          
            |  | 16 |  | 
          
            |  | 17 | {{{#!ini | 
          
            |  | 18 | [trac] | 
          
            |  | 19 | permission_policies = DefaultWikiPolicy, | 
          
            |  | 20 | DefaultTicketPolicy, | 
          
            |  | 21 | DefaultPermissionPolicy, | 
          
            |  | 22 | LegacyAttachmentPolicy | 
          
            |  | 23 | }}} | 
          
            |  | 24 |  | 
          
            |  | 25 | * [#DefaultWikiPolicyandDefaultTicketPolicy DefaultWikiPolicy] controls readonly access to wiki pages. | 
          
            |  | 26 | * [#DefaultWikiPolicyandDefaultTicketPolicy DefaultTicketPolicy] provides elevated privileges in the ticket system for authenticated users. | 
          
            |  | 27 | * !DefaultPermissionPolicy checks for the traditional coarse-grained permissions described in TracPermissions. | 
          
            |  | 28 | * !LegacyAttachmentPolicy uses the coarse-grained permissions to check permissions on attachments. | 
          
            |  | 29 |  | 
          
            |  | 30 | Among the optional choices, there is [#AuthzPolicy], a very generic permission policy, based on an Authz-style system. See [trac:source:branches/1.4-stable/tracopt/perm/authz_policy.py authz_policy.py] for details. | 
          
            |  | 31 |  | 
          
            |  | 32 | Another permission policy [#AuthzSourcePolicy], uses the [http://svnbook.red-bean.com/nightly/en/svn.serverconfig.pathbasedauthz.html path-based authorization] defined by Subversion to enforce permissions on the version control system. | 
          
            |  | 33 |  | 
          
            |  | 34 | See also [trac:source:branches/1.4-stable/sample-plugins/permissions sample-plugins/permissions] for more examples. | 
          
            |  | 35 |  | 
          
            |  | 36 | === !AuthzPolicy | 
          
            |  | 37 | ==== Configuration | 
          
            |  | 38 |  | 
          
            |  | 39 | * Put an empty conf file (`authzpolicy.conf`) in a secure location on the server, not readable by users other than the webuser. If the file contains non-ASCII characters, the UTF-8 encoding should be used. | 
          
            |  | 40 | * Update your `trac.ini`: | 
          
            |  | 41 | 1. modify the [TracIni#trac-permission_policies-option permission_policies] option in the `[trac]` section: | 
          
            |  | 42 | {{{#!ini | 
          
            |  | 43 | [trac] | 
          
            |  | 44 | permission_policies = AuthzPolicy, DefaultWikiPolicy, DefaultTicketPolicy, DefaultPermissionPolicy, LegacyAttachmentPolicy | 
          
            |  | 45 | }}} | 
          
            |  | 46 | 1. add a new `[authz_policy]` section and point the `authz_file` option to the conf file: | 
          
            |  | 47 | {{{#!ini | 
          
            |  | 48 | [authz_policy] | 
          
            |  | 49 | authz_file = /some/trac/env/conf/authzpolicy.conf | 
          
            |  | 50 | }}} | 
          
            |  | 51 | 1. enable the plugin through [/admin/general/plugin WebAdmin] or by editing the `[components]` section: | 
          
            |  | 52 | {{{#!ini | 
          
            |  | 53 | [components] | 
          
            |  | 54 | tracopt.perm.authz_policy.* = enabled | 
          
            |  | 55 | }}} | 
          
            |  | 56 |  | 
          
            |  | 57 | ==== Usage Notes | 
          
            |  | 58 |  | 
          
            |  | 59 | Note the order in which permission policies are specified: policies are implemented in the sequence provided and therefore may override earlier policy specifications. | 
          
            |  | 60 |  | 
          
            |  | 61 | A policy will return either `True`, `False` or `None` for a given permission check. `True` is returned if the policy explicitly grants the permission. `False` is returned if the policy explicitly denies the permission. `None` is returned if the policy is unable to either grant or deny the permission. | 
          
            |  | 62 |  | 
          
            |  | 63 | '''Note''': Only if the return value is `None` will the ''next'' permission policy be consulted. If none of the policies explicitly grants the permission, the final result will be `False`, i.e. permission denied. | 
          
            |  | 64 |  | 
          
            |  | 65 | The `authzpolicy.conf` file is a `.ini` style configuration file: | 
          
            |  | 66 | {{{#!ini | 
          
            |  | 67 | [wiki:PrivatePage@*] | 
          
            |  | 68 | john = WIKI_VIEW, !WIKI_MODIFY | 
          
            |  | 69 | jack = WIKI_VIEW | 
          
            |  | 70 | * = | 
          
            |  | 71 | }}} | 
          
            |  | 72 | * Each section of the config is a glob pattern used to match against a Trac resource descriptor. These descriptors are in the form: | 
          
            |  | 73 | {{{ | 
          
            |  | 74 | <realm>:<id>@<version>[/<realm>:<id>@<version> ...] | 
          
            |  | 75 | }}} | 
          
            |  | 76 |  | 
          
            |  | 77 | Resources are ordered left to right, from parent to child. If any component is inapplicable, `*` is substituted. If the version pattern is not specified explicitly, all versions (`@*`) is added implicitly. Example: Match the WikiStart page: | 
          
            |  | 78 | {{{#!ini | 
          
            |  | 79 | [wiki:*] | 
          
            |  | 80 | [wiki:WikiStart*] | 
          
            |  | 81 | [wiki:WikiStart@*] | 
          
            |  | 82 | [wiki:WikiStart] | 
          
            |  | 83 | }}} | 
          
            |  | 84 |  | 
          
            |  | 85 | Example: Match the attachment `wiki:WikiStart@117/attachment:FOO.JPG@*` on WikiStart: | 
          
            |  | 86 | {{{#!ini | 
          
            |  | 87 | [wiki:*] | 
          
            |  | 88 | [wiki:WikiStart*] | 
          
            |  | 89 | [wiki:WikiStart@*] | 
          
            |  | 90 | [wiki:WikiStart@*/attachment:*] | 
          
            |  | 91 | [wiki:WikiStart@117/attachment:FOO.JPG] | 
          
            |  | 92 | }}} | 
          
            |  | 93 |  | 
          
            |  | 94 | * Sections are checked against the current Trac resource descriptor '''IN ORDER''' of appearance in the configuration file. '''ORDER IS CRITICAL'''. | 
          
            |  | 95 |  | 
          
            |  | 96 | * Once a section matches, the current username is matched against the keys (usernames) of the section, '''IN ORDER'''. | 
          
            |  | 97 | * If a key (username) is prefixed with a `@`, it is treated as a group. | 
          
            |  | 98 | * If a value (permission) is prefixed with a `!`, the permission is denied rather than granted. | 
          
            |  | 99 |  | 
          
            |  | 100 | The username will match any of 'anonymous', 'authenticated', <username> or '*', using normal Trac permission rules. | 
          
            |  | 101 |  | 
          
            |  | 102 | '''Note''': Other groups which are created by user (e.g. by 'adding subjects to groups' on web interface page //Admin / Permissions//) cannot be used. See [trac:#5648] for details about this missing feature. | 
          
            |  | 103 |  | 
          
            |  | 104 | For example, if the `authz_file` contains: | 
          
            |  | 105 | {{{#!ini | 
          
            |  | 106 | [wiki:WikiStart@*] | 
          
            |  | 107 | * = WIKI_VIEW | 
          
            |  | 108 |  | 
          
            |  | 109 | [wiki:PrivatePage@*] | 
          
            |  | 110 | john = WIKI_VIEW | 
          
            |  | 111 | * = !WIKI_VIEW | 
          
            |  | 112 | }}} | 
          
            |  | 113 | and the default permissions are set like this: | 
          
            |  | 114 | {{{ | 
          
            |  | 115 | john           WIKI_VIEW | 
          
            |  | 116 | jack           WIKI_VIEW | 
          
            |  | 117 | # anonymous has no WIKI_VIEW | 
          
            |  | 118 | }}} | 
          
            |  | 119 |  | 
          
            |  | 120 | Then: | 
          
            |  | 121 | * All versions of WikiStart will be viewable by everybody, including anonymous | 
          
            |  | 122 | * !PrivatePage will be viewable only by john | 
          
            |  | 123 | * other pages will be viewable only by john and jack | 
          
            |  | 124 |  | 
          
            |  | 125 | Groups: | 
          
            |  | 126 | {{{#!ini | 
          
            |  | 127 | [groups] | 
          
            |  | 128 | admins = john, jack | 
          
            |  | 129 | devs = alice, bob | 
          
            |  | 130 |  | 
          
            |  | 131 | [wiki:Dev@*] | 
          
            |  | 132 | @admins = TRAC_ADMIN | 
          
            |  | 133 | @devs = WIKI_VIEW | 
          
            |  | 134 | * = | 
          
            |  | 135 |  | 
          
            |  | 136 | [*] | 
          
            |  | 137 | @admins = TRAC_ADMIN | 
          
            |  | 138 | * = | 
          
            |  | 139 | }}} | 
          
            |  | 140 |  | 
          
            |  | 141 | Then: | 
          
            |  | 142 | - everything is blocked (whitelist approach), but | 
          
            |  | 143 | - admins get all TRAC_ADMIN everywhere and | 
          
            |  | 144 | - devs can view wiki pages. | 
          
            |  | 145 |  | 
          
            |  | 146 | Some repository examples (Browse Source specific): | 
          
            |  | 147 | {{{#!ini | 
          
            |  | 148 | # A single repository: | 
          
            |  | 149 | [repository:test_repo@*] | 
          
            |  | 150 | john = BROWSER_VIEW, FILE_VIEW | 
          
            |  | 151 | # John has BROWSER_VIEW and FILE_VIEW for the entire test_repo | 
          
            |  | 152 |  | 
          
            |  | 153 | # The default repository (requires Trac 1.0.2 or later): | 
          
            |  | 154 | [repository:@*] | 
          
            |  | 155 | john = BROWSER_VIEW, FILE_VIEW | 
          
            |  | 156 | # John has BROWSER_VIEW and FILE_VIEW for the entire default repository | 
          
            |  | 157 |  | 
          
            |  | 158 | # All repositories: | 
          
            |  | 159 | [repository:*@*] | 
          
            |  | 160 | jack = BROWSER_VIEW, FILE_VIEW | 
          
            |  | 161 | # Jack has BROWSER_VIEW and FILE_VIEW for all repositories | 
          
            |  | 162 | }}} | 
          
            |  | 163 |  | 
          
            |  | 164 | Very granular repository access: | 
          
            |  | 165 | {{{#!ini | 
          
            |  | 166 | # John has BROWSER_VIEW and FILE_VIEW access to trunk/src/some/location/ only | 
          
            |  | 167 | [repository:test_repo@*/source:trunk/src/some/location/*@*] | 
          
            |  | 168 | john = BROWSER_VIEW, FILE_VIEW | 
          
            |  | 169 |  | 
          
            |  | 170 | # John has BROWSER_VIEW and FILE_VIEW access to only revision 1 of all files at trunk/src/some/location only | 
          
            |  | 171 | [repository:test_repo@*/source:trunk/src/some/location/*@1] | 
          
            |  | 172 | john = BROWSER_VIEW, FILE_VIEW | 
          
            |  | 173 |  | 
          
            |  | 174 | # John has BROWSER_VIEW and FILE_VIEW access to all revisions of 'somefile' at trunk/src/some/location only | 
          
            |  | 175 | [repository:test_repo@*/source:trunk/src/some/location/somefile@*] | 
          
            |  | 176 | john = BROWSER_VIEW, FILE_VIEW | 
          
            |  | 177 |  | 
          
            |  | 178 | # John has BROWSER_VIEW and FILE_VIEW access to only revision 1 of 'somefile' at trunk/src/some/location only | 
          
            |  | 179 | [repository:test_repo@*/source:trunk/src/some/location/somefile@1] | 
          
            |  | 180 | john = BROWSER_VIEW, FILE_VIEW | 
          
            |  | 181 | }}} | 
          
            |  | 182 |  | 
          
            |  | 183 | Note: In order for Timeline to work/visible for John, we must add CHANGESET_VIEW to the above permission list. | 
          
            |  | 184 |  | 
          
            |  | 185 | ==== Missing Features | 
          
            |  | 186 |  | 
          
            |  | 187 | Although possible with the !DefaultPermissionPolicy handling (see Admin panel), fine-grained permissions still miss those grouping features (see [trac:#9573], [trac:#5648]). Patches are partially available, see authz_policy.2.patch, part of [trac:ticket:6680 #6680]. | 
          
            |  | 188 |  | 
          
            |  | 189 | You cannot do the following: | 
          
            |  | 190 | {{{#!ini | 
          
            |  | 191 | [groups] | 
          
            |  | 192 | team1 = a, b, c | 
          
            |  | 193 | team2 = d, e, f | 
          
            |  | 194 | team3 = g, h, i | 
          
            |  | 195 | departmentA = team1, team2 | 
          
            |  | 196 | }}} | 
          
            |  | 197 |  | 
          
            |  | 198 | Permission groups are not supported either, so you cannot do the following: | 
          
            |  | 199 | {{{#!ini | 
          
            |  | 200 | [groups] | 
          
            |  | 201 | permission_level_1 = WIKI_VIEW, TICKET_VIEW | 
          
            |  | 202 | permission_level_2 = permission_level_1, WIKI_MODIFY, TICKET_MODIFY | 
          
            |  | 203 | [*] | 
          
            |  | 204 | @team1 = permission_level_1 | 
          
            |  | 205 | @team2 = permission_level_2 | 
          
            |  | 206 | @team3 = permission_level_2, TICKET_CREATE | 
          
            |  | 207 | }}} | 
          
            |  | 208 |  | 
          
            |  | 209 | === !AuthzSourcePolicy (`mod_authz_svn`-like permission policy) #AuthzSourcePolicy | 
          
            |  | 210 |  | 
          
            |  | 211 | `AuthzSourcePolicy` can be used for restricting access to the repository. Granular permission control needs a definition file, which is the one used by Subversion's `mod_authz_svn`. | 
          
            |  | 212 | More information about this file format and about its usage in Subversion is available in the [http://svnbook.red-bean.com/en/1.7/svn.serverconfig.pathbasedauthz.html Path-Based Authorization] section in the Server Configuration chapter of the svn book. | 
          
            |  | 213 |  | 
          
            |  | 214 | Example: | 
          
            |  | 215 | {{{#!ini | 
          
            |  | 216 | [/] | 
          
            |  | 217 | * = r | 
          
            |  | 218 |  | 
          
            |  | 219 | [/branches/calc/bug-142] | 
          
            |  | 220 | harry = rw | 
          
            |  | 221 | sally = r | 
          
            |  | 222 |  | 
          
            |  | 223 | [/branches/calc/bug-142/secret] | 
          
            |  | 224 | harry = | 
          
            |  | 225 | }}} | 
          
            |  | 226 |  | 
          
            |  | 227 | * '''/''' = ''Everyone has read access by default'' | 
          
            |  | 228 | * '''/branches/calc/bug-142''' = ''harry has read/write access, sally read only'' | 
          
            |  | 229 | * '''/branches/calc/bug-142/secret''' = ''harry has no access, sally has read access (inherited as a sub folder permission)'' | 
          
            |  | 230 |  | 
          
            |  | 231 | ==== Trac Configuration | 
          
            |  | 232 |  | 
          
            |  | 233 | To activate granular permissions you __must__ specify the {{{authz_file}}} option in the `[svn]` section of trac.ini. If this option is set to null or not specified, the permissions will not be used. | 
          
            |  | 234 |  | 
          
            |  | 235 | {{{#!ini | 
          
            |  | 236 | [svn] | 
          
            |  | 237 | authz_file = /path/to/svnaccessfile | 
          
            |  | 238 | }}} | 
          
            |  | 239 |  | 
          
            |  | 240 | If you want to support the use of the `[`''modulename''`:/`''some''`/`''path''`]` syntax within the `authz_file`, add: | 
          
            |  | 241 |  | 
          
            |  | 242 | {{{#!ini | 
          
            |  | 243 | authz_module_name = modulename | 
          
            |  | 244 | }}} | 
          
            |  | 245 |  | 
          
            |  | 246 | where ''modulename'' refers to the same repository indicated by the `<name>.dir` entry in the `[repositories]` section. As an example, if the `somemodule.dir` entry in the `[repositories]` section is `/srv/active/svn/somemodule`, that would yield the following: | 
          
            |  | 247 |  | 
          
            |  | 248 | {{{ #!ini | 
          
            |  | 249 | [svn] | 
          
            |  | 250 | authz_file = /path/to/svnaccessfile | 
          
            |  | 251 | authz_module_name = somemodule | 
          
            |  | 252 | ... | 
          
            |  | 253 | [repositories] | 
          
            |  | 254 | somemodule.dir = /srv/active/svn/somemodule | 
          
            |  | 255 | }}} | 
          
            |  | 256 |  | 
          
            |  | 257 | where the svn access file, {{{/path/to/svnaccessfile}}}, contains entries such as {{{[somemodule:/some/path]}}}. | 
          
            |  | 258 |  | 
          
            |  | 259 | '''Note:''' Usernames inside the Authz file __must__ be the same as those used inside trac. | 
          
            |  | 260 |  | 
          
            |  | 261 | Make sure you have ''!AuthzSourcePolicy'' included in the permission_policies list in trac.ini, otherwise the authz permissions file will be ignored. | 
          
            |  | 262 |  | 
          
            |  | 263 | {{{#!ini | 
          
            |  | 264 | [trac] | 
          
            |  | 265 | permission_policies = AuthzSourcePolicy, DefaultWikiPolicy, DefaultTicketPolicy, DefaultPermissionPolicy, LegacyAttachmentPolicy | 
          
            |  | 266 | }}} | 
          
            |  | 267 |  | 
          
            |  | 268 | ==== Subversion Configuration | 
          
            |  | 269 |  | 
          
            |  | 270 | The same access file is typically applied to the corresponding Subversion repository using an Apache directive like this: | 
          
            |  | 271 | {{{#!apache | 
          
            |  | 272 | <Location /repos> | 
          
            |  | 273 | DAV svn | 
          
            |  | 274 | SVNParentPath /usr/local/svn | 
          
            |  | 275 |  | 
          
            |  | 276 | # our access control policy | 
          
            |  | 277 | AuthzSVNAccessFile /path/to/svnaccessfile | 
          
            |  | 278 | </Location> | 
          
            |  | 279 | }}} | 
          
            |  | 280 |  | 
          
            |  | 281 | For information about how to restrict access to entire projects in a multiple project environment see [trac:wiki:TracMultipleProjectsSVNAccess]. | 
          
            |  | 282 |  | 
          
            |  | 283 | === !DefaultWikiPolicy and !DefaultTicketPolicy | 
          
            |  | 284 |  | 
          
            |  | 285 | Since 1.1.2, the read-only attribute of wiki pages is enabled and enforced when `DefaultWikiPolicy` is in the list of active permission policies (`DefaultWikiPolicy` was named `ReadonlyWikiPolicy` from Trac 1.1.2 to 1.3.1). The default for new Trac installations in 1.3.2 and later is: | 
          
            |  | 286 | {{{#!ini | 
          
            |  | 287 | [trac] | 
          
            |  | 288 | permission_policies = DefaultWikiPolicy, | 
          
            |  | 289 | DefaultTicketPolicy, | 
          
            |  | 290 | DefaultPermissionPolicy, | 
          
            |  | 291 | LegacyAttachmentPolicy | 
          
            |  | 292 | }}} | 
          
            |  | 293 |  | 
          
            |  | 294 | `DefaultWikiPolicy` returns `False` to deny modify, delete and rename actions on wiki pages when the page has the read-only attribute set and the user does not have `WIKI_ADMIN`, regardless of `WIKI_MODIFY`, `WIKI_DELETE` and `WIKI_RENAME` permissions. It returns `None` for all other cases, which causes the next permission policy in the list to be consulted. | 
          
            |  | 295 |  | 
          
            |  | 296 | Since 1.3.2 `DefaultTicketPolicy` implements the following behaviors: | 
          
            |  | 297 | * Authenticated user can edit their own comments. | 
          
            |  | 298 | * Authenticated user with `TICKET_APPEND` or `TICKET_CHGPROP` can modify the description of a ticket they reported. | 
          
            |  | 299 | * User with `MILESTONE_VIEW` can change  the ticket milestone. | 
          
            |  | 300 |  | 
          
            |  | 301 | The wiki- and ticket-specific behaviors are implemented in permission policies so they can be easily replaced in case other behavior is desired. | 
          
            |  | 302 |  | 
          
            |  | 303 | When upgrading from earlier versions of Trac, `DefaultWikiPolicy, DefaultTicketPolicy` will be appended to the list of `permission_policies` when upgrading the environment, provided that `permission_policies` has the default value (`ReadonlyWikiPolicy, DefaultPermissionPolicy, LegacyAttachmentPolicy` if upgrading from Trac 1.1.2 or later). If any non-default `permission_polices` are active, `DefaultWikiPolicy, DefaultTicketPolicy` **will need to be manually added** to the list. A message will be echoed to the console when upgrading the environment, indicating if any action needs to be taken. | 
          
            |  | 304 |  | 
          
            |  | 305 | **!DefaultWikiPolicy and !DefaultTicketPolicy must be listed //before// !DefaultPermissionPolicy**. The latter returns `True` to allow modify, delete or rename actions when the user has the respective `WIKI_*` permission, without consideration for the read-only attribute. Similarly, some of the behaviors implemented in `DefaultTicketPolicy` won't be considered if `DefaultPermissionPolicy` is executed first. | 
          
            |  | 306 |  | 
          
            |  | 307 | When active, the [#AuthzPolicy] should therefore come before `DefaultWikiPolicy, DefaultTicketPolicy`, allowing it to grant or deny the actions on individual resources, which is the usual ordering for `AuthzPolicy` in the `permission_policies` list. | 
          
            |  | 308 | {{{#!ini | 
          
            |  | 309 | [trac] | 
          
            |  | 310 | permission_policies = AuthzPolicy, | 
          
            |  | 311 | DefaultWikiPolicy, | 
          
            |  | 312 | DefaultTicketPolicy, | 
          
            |  | 313 | DefaultPermissionPolicy, | 
          
            |  | 314 | LegacyAttachmentPolicy | 
          
            |  | 315 | }}} | 
          
            |  | 316 |  | 
          
            |  | 317 | The placement of [#AuthzSourcePolicy] relative to `DefaultWikiPolicy, DefaultTicketPolicy` does not matter since they don't perform checks on the same realms. | 
          
            |  | 318 |  | 
          
            |  | 319 | For all other permission policies, the user will need to decide the proper ordering. Generally, if the permission policy should be capable of overriding the checks performed by `DefaultWikiPolicy` or `DefaultTicketPolicy`, it should come before the policy it overrides. If `DefaultWikiPolicy` or `DefaultTicketPolicy` should override the check performed by another permission policy, as is the case for those policies relative to `DefaultPermissionPolicy`, then the overriding policy should come first. | 
          
            |  | 320 |  | 
          
            |  | 321 | == Debugging permissions | 
          
            |  | 322 |  | 
          
            |  | 323 | In trac.ini set: | 
          
            |  | 324 | {{{#!ini | 
          
            |  | 325 | [logging] | 
          
            |  | 326 | log_file = trac.log | 
          
            |  | 327 | log_level = DEBUG | 
          
            |  | 328 | log_type = file | 
          
            |  | 329 | }}} | 
          
            |  | 330 |  | 
          
            |  | 331 | Display the trac.log to understand what checks are being performed: | 
          
            |  | 332 | {{{#!sh | 
          
            |  | 333 | tail -n 0 -f log/trac.log | egrep '\[perm\]|\[authz_policy\]' | 
          
            |  | 334 | }}} | 
          
            |  | 335 |  | 
          
            |  | 336 | See the sourced documentation of the plugin for more info. | 
          
            |  | 337 |  | 
          
            |  | 338 | ---- | 
          
            |  | 339 | See also: TracPermissions, | 
          
            |  | 340 | [https://trac-hacks.org/wiki/FineGrainedPageAuthzEditorPlugin FineGrainedPageAuthzEditorPlugin] for a simple editor. |