| 1 | = LDAP extensions = |
| 2 | |
| 3 | == Abstract == |
| 4 | |
| 5 | LDAP support with group management has been added as a Trac extension. This |
| 6 | extension allows to use existing LDAP groups to grant permissions, rather than |
| 7 | defining permissions for every single user on the system. The latest release also |
| 8 | permits to store permissions (both users and groups permissions) in the LDAP |
| 9 | directory itself, rather than in the SQL backend. |
| 10 | |
| 11 | The original proposition about LDAP ACL is documented under ticket |
| 12 | [http://projects.edgewall.com/trac/ticket/535 Trac#535] on the official web site. |
| 13 | |
| 14 | This software is [http://trac.edgewall.com/license.html licensed] with the same |
| 15 | license than Trac. |
| 16 | |
| 17 | == History == |
| 18 | |
| 19 | * '''v0.0''': First attempt to write a LDAP bridge for Trac, based on Trac 0.8, which required some hacks into the Trac engine. Too bad |
| 20 | * '''v0.1''': A new implementation has started on September, 1st '05, to profit from the new [http://projects.edgewall.com/trac/wiki/TracPlugins TracPlugins] module architecture introduced in Trac 0.9-pre.[[BR]] This implementation should bring the following improvements: |
| 21 | * includes a cache to dramatically reduce LDAP requests |
| 22 | * better handling of LDAP errors[[BR]]This extension works with Trac 0.9-pre1, and requires the [http://peak.telecommunity.com/DevCenter/setuptools setuptools], version 0.5a13 |
| 23 | * '''v0.2''': This new release fixes up a couple of bugs, and works with Trac 0.9-pre2. It requires the [http://peak.telecommunity.com/DevCenter/setuptools setuptools], version 0.6+.[[BR]]It introduces support for LDAP permission store: TracPermissions can now stored into the LDAP directory, rather than in the SQL backend.[[BR]]Each feature (LDAP as a provider of group permissions, LDAP as a permission store) are independent and can be enabled or disabled on demand. |
| 24 | |
| 25 | == Requirements == |
| 26 | |
| 27 | You need the Python LDAP module. It can be retrieved from |
| 28 | [http://python-ldap.sourceforge.net/ python-ldap].[[BR]] LdapPlugin has been |
| 29 | tested on a Debian Linux Sarge/Sid (2.4.x and 2.6.x) server, as well as on a |
| 30 | Windows XP SP2 workstation, both running Python 2.3, with Trac-0.9b2. |
| 31 | |
| 32 | To use the egg file, you need to have |
| 33 | [http://peak.telecommunity.com/DevCenter/setuptools setuptools], version 0.6+ |
| 34 | installed.[[BR]]Please refer to the |
| 35 | [http://projects.edgewall.com/trac/wiki/TracPlugins TracPlugins] page for |
| 36 | information about plugin installation. |
| 37 | |
| 38 | === Important note === |
| 39 | |
| 40 | As per Trac-0.9b2, `trac-admin` bypasses the !PermissionStore system. |
| 41 | This makes this extension pretty useless as the permissions cannot be changed from |
| 42 | the administration tool.[[BR]] |
| 43 | You therefore need to grab a recent version of Trac from the trunk (post Trac-0.9b2) |
| 44 | to make the Ldap permission store extension work, starting from |
| 45 | [http://projects.edgewall.com/trac/changeset/2358 2358]. |
| 46 | |
| 47 | == Download == |
| 48 | |
| 49 | * Download the [http://anciens.enib.fr/svn/external/tasks/trac/ldap-task/extensions/dist/Ldap_Permissions-0.2.1-py2.3.egg egg] |
| 50 | file, for use with Trac-0.9b2. |
| 51 | * Source code is available [http://anciens.enib.fr/trac/public/browser/tasks/trac/ldap-task/extensions/ldapperm here]. |
| 52 | It has been written against Trac [http://projects.edgewall.com/trac/changeset/2353 trunk:2353].[[BR]] |
| 53 | You can also find [wiki:LdapPlugin#Testing unit tests] at this location, which may |
| 54 | |
| 55 | help you to deploy the extension. |
| 56 | |
| 57 | == Installation == |
| 58 | |
| 59 | Simply copy the [http://anciens.enib.fr/svn/external/tasks/trac/ldap-task/extensions/dist/Ldap_Permissions-0.2-py2.3.egg egg] |
| 60 | file in your project ''plugins'' directory. |
| 61 | |
| 62 | == Authentication == |
| 63 | |
| 64 | LdapPlugin does '''not''' perform authentication: Apache2 does, through the HTTP |
| 65 | protocol, as with any other Trac installation.[[BR]] |
| 66 | LdapPlugin retrieves the groups to which the authenticated user belongs, and |
| 67 | checks the [http://projects.edgewall.com/trac/wiki/TracPermissions TracPermissions] |
| 68 | against these groups, along with the regular permissions for the user. |
| 69 | |
| 70 | You probably want to use Apache2 LDAP authentication as well.[[BR]] |
| 71 | This topic is out of scope of this document, but you may find useful information |
| 72 | on the official Apache2 [http://httpd.apache.org/docs-2.0/mod/mod_ldap.html mod_ldap] |
| 73 | web site. |
| 74 | |
| 75 | Here is an example of a typical LDAP section of an Apache2 configuration file: |
| 76 | |
| 77 | {{{ |
| 78 | <Location /trac/project> |
| 79 | PythonOption TracEnv "/local/var/trac/project" |
| 80 | PythonOption TracUriRoot "/trac/project" |
| 81 | AuthType Basic |
| 82 | AuthName "Project" |
| 83 | Order Allow,Deny |
| 84 | Allow from All |
| 85 | AuthLDAPURL "ldap://localhost:389/dc=example,dc=org?uid" |
| 86 | Require group cn=tracusers,dc=example,dc=org |
| 87 | </Location> |
| 88 | }}} |
| 89 | |
| 90 | == Configuration == |
| 91 | |
| 92 | You need to customize the `trac.ini` file of your project, then[[BR]] |
| 93 | 1. Create a new section `[ldap]` and, |
| 94 | 1. Add the magic keyword `module` so that the Trac engine loads and uses |
| 95 | this extension. |
| 96 | 1. Optionnally add the path to your plugin directory |
| 97 | 1. Configure the LDAP directives to fit to your LDAP server configuration |
| 98 | |
| 99 | The section may also contain the following options (which are presented down |
| 100 | here with their default values) |
| 101 | {{{ |
| 102 | [ldap] |
| 103 | # enable LDAP support for Trac |
| 104 | enable = false |
| 105 | # LDAP directory host |
| 106 | host = localhost |
| 107 | # LDAP directory port |
| 108 | port = 389 |
| 109 | # BaseDN |
| 110 | basedn = dc=example,dc=com |
| 111 | # objectclass for groups |
| 112 | groupname = groupofnames |
| 113 | # dn entry in a groupname |
| 114 | groupmember = member |
| 115 | # attribute name for a group |
| 116 | groupattr = cn |
| 117 | # attribute name for a user |
| 118 | uidattr = uid |
| 119 | # attribute name to store trac permission |
| 120 | permattr = tracperm |
| 121 | # filter to search for dn with 'permattr' attributes |
| 122 | permfilter = objectclass=* |
| 123 | # time, in seconds, before a cached entry is purged out of the local cache. |
| 124 | cache_ttl = 900 |
| 125 | # maximum number of entries in the cache |
| 126 | cache_size = 100 |
| 127 | # whether to perform an authenticated bind for group resolution |
| 128 | group_bind = false |
| 129 | # user for authenticated group bind |
| 130 | group_user = |
| 131 | # password for authenticated group bind |
| 132 | group_passwd = |
| 133 | # whether to perform an authenticated bind for permision store operations |
| 134 | store_bind = false |
| 135 | # user for authenticated store bind |
| 136 | store_user = |
| 137 | # password for authenticated store bind |
| 138 | store_passwd = |
| 139 | }}} |
| 140 | |
| 141 | You'd probably want to define at least `enable=true` and the `basedn`[[BR]] |
| 142 | The meaning of the options are pretty straightforward for LDAP administrators. |
| 143 | |
| 144 | A typical setup for group resolution would look like |
| 145 | |
| 146 | {{{ |
| 147 | [ldap] |
| 148 | enable = true |
| 149 | basedn = dc=example,dc=org |
| 150 | }}} |
| 151 | |
| 152 | A typical setup for all LDAP support (group resolution and permission store |
| 153 | would look like |
| 154 | |
| 155 | {{{ |
| 156 | [ldap] |
| 157 | enable = true |
| 158 | basedn = dc=example,dc=org |
| 159 | store_bind = true |
| 160 | store_user = cn=tracadmin,dc=example,dc=org |
| 161 | |
| 162 | store_passwd = mypasswd |
| 163 | }}} |
| 164 | |
| 165 | == Authenticated LDAP connections == |
| 166 | |
| 167 | If your server requires an authenticated connection to retrieve group permissions, |
| 168 | you want to set `group_bind = true` in the `[ldap]` section, and define |
| 169 | the credentials, as follow: |
| 170 | |
| 171 | {{{ |
| 172 | [ldap] |
| 173 | group_bind = true |
| 174 | group_user = joeuser |
| 175 | group_passwd = joepassword |
| 176 | }}} |
| 177 | |
| 178 | If your server requires an authenticated connection to modify group permissions, |
| 179 | you want to set `store_bind = true` in the `[ldap]` section, and define |
| 180 | the credentials, as follow: |
| 181 | |
| 182 | {{{ |
| 183 | [ldap] |
| 184 | group_bind = true |
| 185 | group_user = joeuser |
| 186 | group_passwd = joepassword |
| 187 | }}} |
| 188 | |
| 189 | ''Note'': Most LDAP servers require authenticated bind to perform any kind of |
| 190 | modifications. Anyway, it would be a bad idea to allow modifications from |
| 191 | anybody. |
| 192 | |
| 193 | == Ldap permission store == |
| 194 | |
| 195 | If you wish to use the LDAP permission store feature, you need to tell Trac to |
| 196 | use the LDAP extension rather than the internal default permission store which |
| 197 | relies on the SQL backend. To achieve this setting, add the following line to |
| 198 | the main `[trac]` section of your `trac.ini` configuration file: |
| 199 | |
| 200 | {{{ |
| 201 | [trac] |
| 202 | # ... |
| 203 | permission_store = LdapPermissionStore |
| 204 | }}} |
| 205 | |
| 206 | The extensions differenciates '''group permissions''' from '''user permission'''. |
| 207 | This allow to use distinct objectclasses in the LDAP directory, to store |
| 208 | permission. For example, thanks to the `groupattr` and `uidattr` |
| 209 | attributes, you can define group permission to LDAP entries such as |
| 210 | {{{ |
| 211 | dn: cn=managers,dc=example,dc=org |
| 212 | objectclass: groupofnames |
| 213 | objectclass: trac |
| 214 | member: uid=chandler,dc=example,dc=org |
| 215 | member: uid=joey,dc=example,dc=org |
| 216 | tracperm: WIKI_ADMIN |
| 217 | tracperm: TICKET_ADMIN |
| 218 | }}} |
| 219 | and define user permission to LDAP entries such as |
| 220 | {{{ |
| 221 | dn: uid=courtney,dc=example,dc=org |
| 222 | objectclass: user |
| 223 | objectclass: trac |
| 224 | tracperm: TICKET_VIEW |
| 225 | tracperm: REPORT_CREATE |
| 226 | tracperm: REPORT_VIEW |
| 227 | }}} |
| 228 | |
| 229 | It is worth noting that the '''dn''' used for groups and for users may be |
| 230 | different, which should make things easier to add |
| 231 | [http://projects.edgewall.com/trac/wiki/TracPermissions TracPermissions] into |
| 232 | your existing LDAP directory. |
| 233 | |
| 234 | To differenciate a group name from a user name in `trac-admin`, prefix the group |
| 235 | name with the `@` characters. This syntax has been borrowed from [http://www.samba.org Samba] |
| 236 | and many other software dealing with group management.[[BR]] |
| 237 | One would grant the above permissions using the following `trac-admin` commands |
| 238 | {{{ |
| 239 | permission add @managers WIKI_ADMIN |
| 240 | permission add @managers TICKET_ADMIN |
| 241 | permission add courtney TICKET_VIEW |
| 242 | permission add courtney REPORT_CREATE |
| 243 | permission add courtney REPORT_VIEW |
| 244 | }}} |
| 245 | |
| 246 | Please note that the LDAP permission store '''never''' attemps to create a new |
| 247 | entry in the LDAP directory. To grant (or revoke) permissions to/from the LDAP |
| 248 | directory, the targetted LDAP entry should exist in the directory, and the |
| 249 | attribute defined by the `permattr` option should be writtable for the |
| 250 | `store_user` user. |
| 251 | |
| 252 | Please have a look at the LdapPluginTests page to get an overview of LDAP ACLs |
| 253 | (access control lists) that manages LDAP operations on a directory. |
| 254 | |
| 255 | == Permissions == |
| 256 | |
| 257 | Once LDAP support has been activated, you can use `trac-admin` as usual to |
| 258 | define [http://projects.edgewall.com/trac/wiki/TracPermissions TracPermissions].[[BR]] |
| 259 | However, you can now use the existing groups defined in your LDAP directory to |
| 260 | assign permissions. |
| 261 | |
| 262 | A LDAP group should start with the '`@`' character |
| 263 | |
| 264 | Example: |
| 265 | {{{ |
| 266 | Trac [/var/local/db/trac/public]> permission list |
| 267 | |
| 268 | User Action |
| 269 | ------------------------------- |
| 270 | @administrators TRAC_ADMIN |
| 271 | @betatesters WIKI_CREATE |
| 272 | @betatesters WIKI_MODIFY |
| 273 | eblot TRAC_ADMIN |
| 274 | anonymous BROWSER_VIEW |
| 275 | anonymous CHANGESET_VIEW |
| 276 | anonymous FILE_VIEW |
| 277 | anonymous LOG_VIEW |
| 278 | anonymous SEARCH_VIEW |
| 279 | anonymous TIMELINE_VIEW |
| 280 | anonymous WIKI_VIEW |
| 281 | }}} |
| 282 | |
| 283 | Here, people who are declared in the 'administrator' LDAP group have the |
| 284 | `TRAC_ADMIN` permission, and people who are declared in the 'betatesters' |
| 285 | LDAP group have the `WIKI_CREATE` and `WIKI_MODIFY` permission. |
| 286 | |
| 287 | You can obviously still use permissions for regular user, such as ''eblot'' in |
| 288 | the aforementionned example. |
| 289 | |
| 290 | '''Note''': Please remember that ''anonymous'' and ''authenticated'' are special users, |
| 291 | but are considered by the permission backend just like any other regular user.[[BR]] |
| 292 | This means that you need to add both these special users in your LDAP directory |
| 293 | if you wish to assign permission to these joker entries. |
| 294 | The [wiki:LdapPluginTests#Initializingthedirectory directory configuration] proposed in |
| 295 | the [wiki:LdapPluginTests test] page may give you some hints about how to setup |
| 296 | your LDAP directory. |
| 297 | |
| 298 | == Known limitations == |
| 299 | |
| 300 | * Only LDAP v3 protocol is supported. This extension may work with v2 protocol |
| 301 | as well, if the v3 specifier is removed from the code |
| 302 | |
| 303 | == !ToDo list == |
| 304 | |
| 305 | * Add user detail support, so that the full name and email address are |
| 306 | retrieved from the LDAP server. It would require a new extension point in |
| 307 | Trac engine. |
| 308 | * There's probably a lot of room for improvement (and debugging) ;-) |
| 309 | |
| 310 | == Testing == |
| 311 | |
| 312 | The LdapPluginTests page gives some hint about how to test the Ldap extension for |
| 313 | Trac |
| 314 | |
| 315 | == Questions == |
| 316 | |
| 317 | Contact: `manu_blot@gmail_com` (antispam: replace the underscore character |
| 318 | with a full stop) or through the official Trac |
| 319 | [http://projects.edgewall.com/trac/wiki/MailingList mailing list]. |
| 320 | |
| 321 | |
| 322 | [[TagIt(eblot)]] |