= LDAP extensions = == Abstract == LDAP support with group management has been added as a Trac extension. This extension enables to use existing LDAP groups to grant permissions rather than defining permissions for every single user on the system. The latest release also permits to store permissions (both users and groups permissions) in the LDAP directory itself rather than in the SQL backend. The original proposition about LDAP ACL is documented under ticket [http://projects.edgewall.com/trac/ticket/535 Trac#535] on the official web site. This software is [http://trac.edgewall.com/license.html licenced] with the same license as Trac. == Requirements == You need the Python LDAP module. It can be retrieved from [http://python-ldap.sourceforge.net/ python-ldap].[[BR]] LdapPlugin has been tested on a Debian Linux Sarge/Sid (2.4.x and 2.6.x) server, as well as on a Windows XP SP2 workstation, both running Python 2.3 with Trac 'development' releases. To use the egg file you need to have [http://peak.telecommunity.com/DevCenter/setuptools setuptools], version 0.6+ installed.[[BR]]Please refer to the [http://projects.edgewall.com/trac/wiki/TracPlugins TracPlugins] page for information about plugin installation. === Important note === You need to grab a recent version of Trac from the trunk to make the Ldap permission store extension work as expected.[[BR]] As the trunk API may vary without notice, the plugin may be broken if you run it with a different release. == Download == * Source code is available from http://trac-hacks.org/svn/ldapplugin. * You can also find [wiki:LdapPlugin#Testing unit tests] at the same location - under the `tests` directory -, which may help you deploy the plugin. == Installation == * Build the ''egg'' file following the plugin packaging [http://projects.edgewall.com/trac/wiki/TracDev/PluginDevelopment#Packaginganddeployingplugins instructions] * Copy the `dist/LdapPlugin-0.y.z-py2.3.egg` file in your ''plugins'' project directory. == Authentication == LdapPlugin does '''not''' perform authentication: Apache2 does, through the HTTP protocol, as with any other Trac installation.[[BR]] LdapPlugin retrieves the groups to which the authenticated user belongs and checks the [http://projects.edgewall.com/trac/wiki/TracPermissions TracPermissions] against these groups, along with the regular permissions for the user. You probably want to use Apache2 LDAP authentication as well.[[BR]] This topic is out of scope of this document but you may find useful information on the official Apache2 [http://httpd.apache.org/docs-2.0/mod/mod_ldap.html mod_ldap] web site. Here is an example of a typical LDAP section of an Apache2 configuration file: {{{ PythonOption TracEnv "/local/var/trac/project" PythonOption TracUriRoot "/trac/project" AuthType Basic AuthName "Project" Order Allow,Deny Allow from All AuthLDAPURL "ldap://localhost:389/dc=example,dc=org?uid" Require group cn=tracusers,dc=example,dc=org }}} == Configuration == You need to customize the `trac.ini` file of your project, then[[BR]] 1. Create a new section `[ldap]` and, 1. Add the magic keyword `module` so that the Trac engine loads and uses this extension. 1. Optionnally add the path to your plugin directory 1. Configure the LDAP directives to fit your LDAP server configuration The section may also contain the following options (which are presented down here with their default values) {{{ [ldap] # enable LDAP support for Trac enable = false # LDAP directory host host = localhost # LDAP directory port port = 389 # BaseDN basedn = dc=example,dc=com # BaseDN for users (defaults to basedn) user_basedn = dc=example,dc=com # BaseDN for group of names (defaults to basedn) group_basedn = dc=example,dc=com # objectclass for groups groupname = groupofnames # dn entry in a groupname groupmember = member # attribute name for a group groupattr = cn # attribute name for a user uidattr = uid # attribute name to store trac permission permattr = tracperm # filter to search for dn with 'permattr' attributes permfilter = objectclass=* # time, in seconds, before a cached entry is purged out of the local cache. cache_ttl = 900 # maximum number of entries in the cache cache_size = 100 # whether to perform an authenticated bind for group resolution group_bind = false # user for authenticated group bind group_user = # password for authenticated group bind group_passwd = # whether to perform an authenticated bind for permision store operations store_bind = false # user for authenticated store bind store_user = # password for authenticated store bind store_passwd = # global permissions (vs. per-environment permissions) global_perms = false }}} You probably want to define at least `enable=true` and the `basedn`[[BR]] The meaning of the options are pretty straightforward for LDAP administrators. A typical setup for group resolution would look like this: {{{ [ldap] enable = true basedn = dc=example,dc=org }}} A typical setup for all LDAP support (group resolution and permission store) would look like this: {{{ [ldap] enable = true basedn = dc=example,dc=org store_bind = true store_user = cn=tracadmin,dc=example,dc=org store_passwd = mypasswd }}} == Authenticated LDAP connections == If the server requires an authenticated connection to retrieve group permissions, you want to set `group_bind = true` in the `[ldap]` section and define the credentials as follows: {{{ [ldap] group_bind = true group_user = joeuser group_passwd = joepassword }}} If the server requires an authenticated connection to modify group permissions, you want to set `store_bind = true` in the `[ldap]` section and define the credentials as follows: {{{ [ldap] group_bind = true group_user = joeuser group_passwd = joepassword }}} ''Note'': Most LDAP servers require authenticated bind to perform any kind of modifications. Anyway, it would be a bad idea to allow modifications from anybody. == Ldap permission store == If you wish to use the LDAP permission store feature, you need to tell Trac to use the LDAP extension rather than the internal default permission store which relies on the SQL backend. To achieve this setting, add the following line to the main `[trac]` section of your `trac.ini` configuration file: {{{ [trac] # ... permission_store = LdapPermissionStore }}} The extension differenciates '''group permissions''' from '''user permission'''. This permits to use distinct objectclasses in the LDAP directory, to store permission. For example thanks to the `groupattr` and `uidattr` attributes, you can define group permission to LDAP entries such as {{{ dn: cn=managers,dc=example,dc=org objectclass: groupofnames objectclass: trac member: uid=chandler,dc=example,dc=org member: uid=joey,dc=example,dc=org tracperm: WIKI_ADMIN tracperm: TICKET_ADMIN }}} and define user permission to LDAP entries such as {{{ dn: uid=courtney,dc=example,dc=org objectclass: user objectclass: trac tracperm: TICKET_VIEW tracperm: REPORT_CREATE tracperm: REPORT_VIEW }}} It is worth noting that the '''dn''' used for groups and for users may be different, which should make things easier to add [http://projects.edgewall.com/trac/wiki/TracPermissions TracPermissions] into your existing LDAP directory. To differenciate a group name from a user name in `trac-admin`, prefix the group name with the `@` characters. This syntax has been borrowed from [http://www.samba.org Samba] and many other software dealing with group management.[[BR]] One would grant the above permissions using the following `trac-admin` commands {{{ permission add @managers WIKI_ADMIN permission add @managers TICKET_ADMIN permission add courtney TICKET_VIEW permission add courtney REPORT_CREATE permission add courtney REPORT_VIEW }}} Please note that the LDAP permission store '''never''' attemps to create a new entry in the LDAP directory. To grant (or revoke) permissions to/from the LDAP directory, the targetted LDAP entry should exist in the directory and the attribute defined by the `permattr` option should be writtable for the `store_user` user. Please have a look at the LdapPluginTests page to get an overview of LDAP ACLs (access control lists) that manages LDAP operations on a directory. == Permissions == Once LDAP support has been activated, you can use `trac-admin` as usual to define [http://projects.edgewall.com/trac/wiki/TracPermissions TracPermissions].[[BR]] However, you can now use the existing groups defined in your LDAP directory to assign permissions. A LDAP group should start with the '`@`' character Example: {{{ Trac [/var/local/db/trac/public]> permission list User Action ------------------------------- @administrators TRAC_ADMIN @betatesters WIKI_CREATE @betatesters WIKI_MODIFY eblot TRAC_ADMIN anonymous BROWSER_VIEW anonymous CHANGESET_VIEW anonymous FILE_VIEW anonymous LOG_VIEW anonymous SEARCH_VIEW anonymous TIMELINE_VIEW anonymous WIKI_VIEW }}} Here, people who are declared in the 'administrator' LDAP group have the `TRAC_ADMIN` permission, and people who are declared in the 'betatesters' LDAP group have the `WIKI_CREATE` and `WIKI_MODIFY` permission. You can obviously still use permissions for regular user such as ''eblot'' in the example above. '''Note''': Please remember that ''anonymous'' and ''authenticated'' are special users but are considered by the permission backend just like any other regular user.[[BR]] This means that you need to add both these special users in your LDAP directory if you wish to assign permission to these joker entries. The [wiki:LdapPluginTests#Initializingthedirectory directory configuration] proposed in the [wiki:LdapPluginTests test] page may give you some hints about how to setup your LDAP directory. === Global vs. Environment permissions === Starting from release '''v0.3.0''', permissions are not defined globally (unless `global_perms` is set in the environment configuration file), but on per-environment basis. With environment-wide permissions, it is now possible to define distinct permissions for each Trac environment (as long as their name differ) even if they access the same LDAP directory.[[BR]] The Trac LDAP permission attribute value are prefixed with the environment name.[[BR]] Using the previous example, assuming the environment name is named "test", permission attributes would become: {{{ dn: uid=courtney,dc=example,dc=org objectclass: user objectclass: trac tracperm: test:TICKET_VIEW tracperm: test:REPORT_CREATE tracperm: test:REPORT_VIEW }}} It is still possible to use global permissions by setting in the `[ldap]` section of the environment configuration file: {{{ global_perms = true }}} When a directory contains global permission directives, those permissions apply on every Trac environment accessing the LDAP directory, whichever the `global_perms` value. However, permissions are always created using the current environment permission setting. From the administrative point of view (`trac-admin`, [http://projects.edgewall.com/trac/wiki/WebAdmin WebAdmin], ...), there are no changes: permission are defined and retrieved as usual. ''Note:'' The environment ''name'' is based on the root directory of the Trac environment. This means that if you use different environment with the same name, such as: `/var/local/trac/test` and `/var/db/test`, they are both named "test" and share the same permissions. This is a known limitation of the current implementation. == Known limitations == * Only LDAP v3 protocol is supported. This extension may work with v2 protocol as well, if the v3 specifier is removed from the code. == !ToDo list == * Add user detail support so that the full name and email address are retrieved from the LDAP server. It would require a new extension point in Trac engine. * There's probably a lot of room for improvement (and debugging) ;-) == Testing == The LdapPluginTests page gives some hints about how to test the Ldap extension for Trac == History == * '''v0.0''': First attempt to write a LDAP bridge for Trac based on Trac 0.8, which required some hacks into the Trac engine. * '''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: * includes a cache to dramatically reduce LDAP requests * 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 * '''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 be 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. * '''v0.2.1''': Bug fixing * '''v0.2.2''': Introduce support for disting DN for users and groups (implemented suggestion described in #75) * '''v0.2.3''': Update to support the new boolean parsing introduced in the official Trac trunk * '''v0.3.0''': Introduce per-environment permissions: permissions are defined to the current environment and do not overlap with other Trac environments using the same LDAP directory, unless the `global_perms` configuration parameters is set. == Author/Contributors == '''Author:''' [wiki:eblot eblot] [[BR]] '''Contributors:''' [[TagIt(eblot,0.9,plugin)]]