Ticket #2293: ldappluginAD.2.patch

File ldappluginAD.2.patch, 40.8 kB (added by asklepios, 1 year ago)
  • 0.10/COPYING

    old new  
    11Copyright (C) 2005-2006 Emmanuel Blot <emmanuel.blot@free.fr> 
    22All rights reserved. 
    33 
     4Copyright (C) 2007-2008 Sirrix AG <www.sirrix.com>  
     5(Alexander Kasper wrote Active Directory Extension) 
     6All rights reserved 
     7 
    48Redistribution and use in source and binary forms, with or without 
    59modification, are permitted provided that the following conditions 
    610are met: 
  • 0.10/ad-schema/README

    old new  
     1Warning: please use a testenvironment since schemadefinitions for AD are complex, at multible places redundant and extrem ugly :)  
     2 
     300 importcommand is ldifde -i -f <filename> 
     401 command to get 'dn' is (replace DC=shoel,DC=local and shoel.local with your domain) 
     501.1.user for linux: ldapsearch -D loginname@shoel.local -h <hostip> -x -w **password** -LLL -b "DC=shoel,DC=local" '(&(objectclass=user)(sAMAccountName=<searchloginname>)' dn 
     601.1.group for linux: ldapsearch -D loginname@shoel.local -h <hostip> -x -w **password** -LLL -b "DC=shoel,DC=local" 'objectclass=group' sAMAccountName dn  
     701.2.user for windows: ldifde -f output.txt -l dn -r "(&(objectclass=user)(sAMAccountName=<searchloginname>))" -d "DC=shoel,DC=local" -b loginname shoel.local **password** 
     801.2.group for windows: ldifde -f output.txt -l dn,sAMAccountName -r "(objectclass=group)" -d "DC=shoel,DC=local" -b loginname shoel.local **password** 
     902 modfiy *.ldf to fir yout needs minimal replace shoel.local resp DC=shoel,DC=local with your domain 
     1003 Import TracADExtension.ldf 
     1104.1 to mark a User/Group as a TracGroup use make_User_TracUser.ldf or make_Group_TracGroup.ldf 
     1204.2 to give a attribute to a user / Group use add_TracPerm_to_User.ldf or add_TracPerm_to_Group.ldf 
     1305 the structure is TracPerm,TracGroup and TracUser are Attributes and TracExt is the coresponding class 
     1406 TracExt is an auxiliaryclass of the Buildin Classes User and Group 
     15 
  • 0.10/ad-schema/TracADextension.ldf

    old new  
     1dn: CN=TracPerm,CN=Schema,CN=Configuration,DC=shoel,DC=local 
     2changetype: add 
     3objectClass: top 
     4objectClass: attributeSchema 
     5cn: TracPerm 
     6distinguishedName: CN=TracPerm,CN=Schema,CN=Configuration,DC=shoel,DC=local 
     7instanceType: 4 
     8attributeID: 1.3.6.1.4.1.2342.2.1 
     9attributeSyntax: 2.5.5.3 
     10isSingleValued: FALSE 
     11showInAdvancedViewOnly: TRUE 
     12adminDisplayName: TracPerm 
     13adminDescription: Trac Permission Store 
     14oMSyntax: 27 
     15lDAPDisplayName: TracPerm 
     16name: TracPerm 
     17objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=shoel,DC=local 
     18 
     19dn: CN=TracGroup,CN=Schema,CN=Configuration,DC=shoel,DC=local 
     20changetype: add 
     21objectClass: top 
     22objectClass: attributeSchema 
     23cn: TracGroup 
     24distinguishedName: CN=TracGroup,CN=Schema,CN=Configuration,DC=shoel,DC=local 
     25instanceType: 4 
     26attributeID: 1.3.6.1.4.1.2342.2.2 
     27attributeSyntax: 2.5.5.3 
     28isSingleValued: FALSE 
     29showInAdvancedViewOnly: TRUE 
     30adminDisplayName: TracGroup 
     31adminDescription: Trac flag for a Group 
     32oMSyntax: 27 
     33lDAPDisplayName: TracGroup 
     34name: TracGroup 
     35objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=shoel,DC=local 
     36 
     37dn: CN=TracUser,CN=Schema,CN=Configuration,DC=shoel,DC=local 
     38changetype: add 
     39objectClass: top 
     40objectClass: attributeSchema 
     41cn: TracUser 
     42distinguishedName: CN=TracUser,CN=Schema,CN=Configuration,DC=shoel,DC=local 
     43instanceType: 4 
     44attributeID: 1.3.6.1.4.1.2342.2.3 
     45attributeSyntax: 2.5.5.3 
     46isSingleValued: FALSE 
     47showInAdvancedViewOnly: TRUE 
     48adminDisplayName: TracUser 
     49adminDescription: Trac flag for a User 
     50oMSyntax: 27 
     51lDAPDisplayName: TracUser 
     52name: TracUser 
     53objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=shoel,DC=local 
     54 
     55dn: 
     56changetype: modify 
     57add: schemaupdatenow 
     58schemaupdatenow: 1 
     59- 
     60 
     61dn: CN=TracExt,CN=Schema,CN=Configuration,DC=shoel,DC=local 
     62changetype: add 
     63objectClass: top 
     64objectClass: classSchema 
     65cn: TracExt 
     66distinguishedName: CN=TracExt,CN=Schema,CN=Configuration,DC=shoel,DC=local 
     67instanceType: 4 
     68governsID: 1.3.6.1.4.1.2342.1.3 
     69mayContain: TracPerm 
     70mayContain: TracGroup 
     71mayContain: TracUser 
     72showInAdvancedViewOnly: TRUE 
     73adminDisplayName: TracExt 
     74adminDescription: Extension for Trac 
     75objectClassCategory: 3 
     76lDAPDisplayName: TracExt 
     77name: Trac 
     78systemOnly: FALSE 
     79defaultObjectCategory: CN=TracExt,CN=Schema,CN=Configuration,DC=shoel,DC=local 
     80 
     81dn: 
     82changetype: modify 
     83add: schemaupdatenow 
     84schemaupdatenow: 1 
     85- 
     86 
     87dn: CN=User,CN=Schema,CN=Configuration,DC=shoel,DC=local 
     88changetype: modify 
     89add: auxiliaryClass 
     90auxiliaryClass: TracExt 
     91- 
     92 
     93dn: CN=Group,CN=Schema,CN=Configuration,DC=shoel,DC=local 
     94changetype: modify 
     95add: auxiliaryClass 
     96auxiliaryClass: TracExt 
     97- 
     98 
     99dn: 
     100changetype: modify 
     101add: schemaupdatenow 
     102schemaupdatenow: 1 
     103- 
     104 
  • 0.10/ad-schema/add_TracPerm_to_Group.ldf

    old new  
     1dn: CN=devel,ou=groups,OU=shoel,DC=shoel,DC=local 
     2changetype: modify 
     3add: TracPerm 
     4TracPerm: project:WIKI_VIEW 
     5- 
     6 
     7dn: 
     8changetype: modify 
     9add: schemaupdatenow 
     10schemaupdatenow: 1 
     11- 
     12 
  • 0.10/ad-schema/add_TracPerm_to_User.ldf

    old new  
     1dn: CN=asklepios as. shoel,ou=users,OU=shoel,DC=shoel,DC=local 
     2changetype: modify 
     3add: TracPerm 
     4TracPerm: project:WIKI_ADMIN 
     5- 
     6 
     7dn: 
     8changetype: modify 
     9add: schemaupdatenow 
     10schemaupdatenow: 1 
     11- 
  • 0.10/ad-schema/del_TracPerm_from_Group.ldf

    old new  
     1dn: CN=devel,ou=groups,OU=shoel,DC=shoel,DC=local 
     2changetype: modify 
     3delete: TracPerm 
     4TracPerm: project:WIKI_VIEW 
     5- 
     6 
     7dn: 
     8changetype: modify 
     9add: schemaupdatenow 
     10schemaupdatenow: 1 
     11- 
     12 
  • 0.10/ad-schema/del_TracPerm_from_User.ldf

    old new  
     1dn: CN=asklepios as. shoel,ou=users,OU=shoel,DC=shoel,DC=local 
     2changetype: modify 
     3delete: TracPerm 
     4TracPerm: project:WIKI_ADMIN 
     5- 
     6 
     7dn: 
     8changetype: modify 
     9add: schemaupdatenow 
     10schemaupdatenow: 1 
     11- 
  • 0.10/ad-schema/make_Group_TracGroup.ldf

    old new  
     1dn: CN=mitarbeiter,ou=groups,OU=shoel,DC=shoel,DC=local 
     2changetype: modify 
     3add: TracGroup 
     4TracGroup: TRUE 
     5- 
     6 
     7dn: 
     8changetype: modify 
     9add: schemaupdatenow 
     10schemaupdatenow: 1 
     11- 
     12 
  • 0.10/ad-schema/make_User_TracUser.ldf

    old new  
     1dn: CN=asklepios as. shoel,ou=users,OU=shoel,DC=shoel,DC=local 
     2changetype: modify 
     3add: TracUser 
     4TracUser: TRUE 
     5- 
     6 
     7dn: 
     8changetype: modify 
     9add: schemaupdatenow 
     10schemaupdatenow: 1 
     11- 
  • 0.10/ad-schema/unmake_Group_TracGroup.ldf

    old new  
     1dn: CN=mitarbeiter,ou=groups,OU=shoel,DC=shoel,DC=local 
     2changetype: modify 
     3delete: TracGroup 
     4TracGroup: TRUE 
     5- 
     6 
     7dn: 
     8changetype: modify 
     9add: schemaupdatenow 
     10schemaupdatenow: 1 
     11- 
     12 
  • 0.10/ad-schema/unmake_User_TracUser.ldf

    old new  
     1dn: CN=asklepios as. shoel,ou=users,OU=shoel,DC=shoel,DC=local 
     2changetype: modify 
     3delete: TracUser 
     4TracUser: TRUE 
     5- 
     6 
     7dn: 
     8changetype: modify 
     9add: schemaupdatenow 
     10schemaupdatenow: 1 
     11- 
  • 0.10/example_conf/auth_apache.conf

    old new  
     1<Location /testcase/> 
     2        AuthName "Trac LDAP Auth" 
     3        AuthType Basic 
     4        AuthBasicProvider ldap 
     5        AuthzLDAPAuthoritative on 
     6        AuthLDAPURL 'ldap://192.168.0.2:389/DC=shoel,DC=local?sAMAccountName' 
     7        AuthLDAPBindDN tracauth@shoel.local 
     8        AuthLDAPBindPassword **funnyPassword** 
     9        AuthLDAPGroupAttribute member 
     10        AuthLDAPRemoteUserAttribute sAMAccountName 
     11        AuthLDAPRemoteUserIsDN on 
     12        AuthLDAPGroupAttributeIsDN on 
     13        AuthLDAPCompareDNOnServer on 
     14# all users are allowd to login  
     15        require valid-user 
     16# just this group 
     17#        require ldap-group CN=mitarbeiter,DC=shoel,DC=local 
     18</Location>                  
     19 
     20<Location /trac/testtrac> 
     21       PythonPath "sys.path + ['/usr/share/trac']" 
     22       SetHandler mod_python 
     23       PythonHandler trac.web.modpython_frontend 
     24       #PythonHandler tram.modpython_frontend 
     25       PythonOption TracEnv /trac/testtrac 
     26       PythonOption TracUriRoot /trac/testtrac 
     27       SetEnv PYTHON_EGG_CACHE /tmp 
     28</Location> 
     29 
  • 0.10/example_conf/trac.ini

    old new  
     1# -*- coding: utf-8 -*- 
     2 
     3[account-manager] 
     4authentication_url = http://localhost/testcase/ 
     5password_store = HttpAuthStore 
     6 
     7[attachment] 
     8max_size = 262144 
     9render_unsafe_content = false 
     10 
     11[blog] 
     12date_format = %x %X 
     13default_tag = news 
     14first_week_day = SUNDAY 
     15footer =  
     16history_days = 30 
     17macro_blacklist =  
     18mark_updated = true 
     19nav_bar = false 
     20new_blog_link = New News 
     21num_posts = 5 
     22page_format = %Y/%m/%d/%H.%M 
     23post_size = 1024 
     24 
     25[browser] 
     26downloadable_paths = /trunk, /branches/*, /tags/* 
     27hide_properties = svk:merge 
     28render_unsafe_content = false 
     29 
     30[changeset] 
     31max_diff_bytes = 10000000 
     32max_diff_files = 0 
     33wiki_format_messages = true 
     34 
     35[components] 
     36acct_mgr.admin.accountmanageradminpage = enabled 
     37acct_mgr.api.accountmanager = enabled 
     38acct_mgr.db.sessionstore = enabled 
     39acct_mgr.htfile.abstractpasswordfilestore = enabled 
     40acct_mgr.htfile.htdigeststore = enabled 
     41acct_mgr.htfile.htpasswdstore = enabled 
     42acct_mgr.http.httpauthstore = enabled 
     43acct_mgr.pwhash.htdigesthashmethod = enabled 
     44acct_mgr.pwhash.htpasswdhashmethod = enabled 
     45acct_mgr.web_ui.loginmodule = enabled 
     46trac.web.auth.LoginModule = disabled 
     47ldapplugin.api.* = enabled 
     48tblog.* = enabled 
     49trac.ticket.report.* = disabled 
     50trac2latex.trac2latex.* = enabled 
     51tractags.* = enabled 
     52tractoc.macro.* = enabled 
     53tramplugin.* = enabled 
     54webadmin.* = enabled 
     55webadmin.basics.* = enabled 
     56webadmin.logging.* = enabled 
     57webadmin.perm.* = enabled 
     58webadmin.plugin.* = enabled 
     59webadmin.ticket.* = enabled 
     60webadmin.web_ui.* = enabled 
     61 
     62[header_logo] 
     63alt = the logo 
     64height = 70 
     65link =  
     66src =  
     67width = 209 
     68 
     69[ldap] 
     70basedn = dc=shoel,dc=local 
     71bind_passwd = nNuwQi1 
     72bind_user =  CN=trac accountauth,DC=shoel,DC=local 
     73enable = true 
     74group_bind = true 
     75group_rdn =  
     76groupattr = cn 
     77groupmember = member 
     78groupmemberisdn = true 
     79groupname =  
     80ldapstyle = AD 
     81mapobjectclassgroup = TracGroup 
     82mapobjectclassuser = TracUser 
     83objectclassuservalue = TRUE 
     84objectclassgroupvalue = TRUE 
     85mapanonymoususer = anonymous 
     86mapauthenticateduser = authenticated 
     87mapuiduser = sAMAccountName 
     88mapgidgroup = sAMAccountName 
     89mapuserperm = TracPerm 
     90mapgroupperm = TracPerm 
     91manage_groups = true 
     92host = 192.168.0.2 
     93port = 389 
     94permattr = tracperm 
     95permfilter = objectclass=* 
     96store_bind = true 
     97uidattr = uid 
     98use_tls = false 
     99user_rdn =  
     100cache_ttl = 300 
     101cache_size = 100 
     102 
     103[logging] 
     104log_file = /trac/testtrac/log/trac.log 
     105log_level = DEBUG 
     106log_type = file 
     107 
     108[mimeviewer] 
     109enscript_modes = text/x-dylan:dylan:4 
     110enscript_path = enscript 
     111max_preview_size = 262144 
     112mime_map = text/x-dylan:dylan,text/x-idl:ice,text/x-ada:ads:adb 
     113php_path = php 
     114silvercity_modes =  
     115tab_width = 8 
     116 
     117[notification] 
     118always_notify_owner = false 
     119always_notify_reporter = false 
     120always_notify_updater = false 
     121mime_encoding = base64 
     122smtp_always_bcc =  
     123smtp_always_cc =  
     124smtp_default_domain =  
     125smtp_enabled = false 
     126smtp_from =  
     127smtp_password =  
     128smtp_port = 25 
     129smtp_replyto =  
     130smtp_server =  
     131smtp_subject_prefix =  
     132smtp_user =  
     133use_public_cc = true 
     134use_short_addr = false 
     135use_tls = false 
     136 
     137[project] 
     138descr = This is the knowledge database  
     139footer = Visit the Trac open source project at<br /><a href="http://trac.edgewall.org/">http://trac.edgewall.org/</a> 
     140icon = site/icon.gif 
     141name = My Project 
     142url = http://funny.an.url 
     143 
     144[search] 
     145min_query_length = 3 
     146 
     147[ticket] 
     148default_component =  
     149default_milestone =  
     150default_priority = major 
     151default_type = defect 
     152default_version =  
     153restrict_owner = false 
     154 
     155[timeline] 
     156changeset_long_messages = false 
     157changeset_show_files = 0 
     158default_daysback = 30 
     159ticket_show_details = false 
     160 
     161[trac] 
     162authz_file =  
     163authz_module_name =  
     164base_url =  
     165check_auth_ip = true 
     166database = sqlite:db/trac.db 
     167default_charset = iso-8859-15 
     168default_handler = WikiModule 
     169htdocs_location =  
     170ignore_auth_case = false 
     171mainnav = wiki,timeline,roadmap,browser,tickets,newticket,search 
     172metanav = login,logout,settings,help,about 
     173permission_store = LdapPermissionStore  
     174;permission_store = DefaultPermissionStore 
     175repository_dir =  
     176repository_type = svn 
     177timeout = 20 
     178 
     179[wiki] 
     180ignore_missing_pages = false 
     181split_page_names = false 
     182 
  • 0.10/ldapplugin/api.py

    old new  
    44#  
    55# Copyright (C) 2003-2006 Edgewall Software 
    66# Copyright (C) 2005-2006 Emmanuel Blot <emmanuel.blot@free.fr> 
     7# Copyright (C) 2007-2008 Sirrix AG <www.sirrix.com> (Active Directory) 
    78# All rights reserved. 
    89# 
    910# This software is licensed as described in the file COPYING, which 
     
    1920# a concern. 
    2021# Requires Python-LDAP, available from http://python-ldap.sourceforge.net 
    2122# 
     23# Extended for Active Directory (read only) by Alexander Kasper <alex@mediadrugs.de> 
     24 
     25# new Options are 
     26#ldapstyle = AD | openldap (enable gerneral AD-Support) 
     27#mapobjectclassgroup = objectClass | TracGroup (from supplied schema) 
     28#mapobjectclassuser = objectClass | TracUser 
     29#objectclassuservalue = user | TRUE 
     30#objectclassgroupvalue = group | TRUE 
     31#mapanonymoususer = anonymous (currently unused) 
     32#mapauthenticateduser = authenticated (currently unused) 
     33#mapuiduser = uid | sAMAccountName 
     34#mapgidgroup = gid | sAMAccountName 
     35#mapuserperm = TracPerm 
     36#mapgroupperm = TracPerm 
     37 
     38# schema import for AD needed 
    2239 
    2340import re 
    2441import time 
     
    3754LDAP_DIRECTORY_PARAMS = [ 'host', 'port', 'use_tls', 'basedn', 
    3855                          'bind_user', 'bind_passwd', 
    3956                          'groupname', 'groupmember', 'groupmemberisdn', 
    40                           'groupattr', 'uidattr', 'permattr'] 
     57                          'groupattr', 'uidattr', 'permattr', 
     58                          'ldapstyle', 'mapobjectclassgroup', 
     59                          'mapobjectclassuser', 'objectclassuservalue', 
     60                          'objectclassgroupvalue','mapanonymoususer', 
     61                          'mapauthenticateduser','mapuiduser', 
     62                          'mapgidgroup','mapuserperm','mapgroupperm' ] 
     63                           
    4164                           
    4265GROUP_PREFIX = '@' 
    4366 
     
    6386        for name,value in self.config.options('ldap'): 
    6487            if name in LDAP_DIRECTORY_PARAMS: 
    6588                self._ldapcfg[name] = value 
     89 
    6690        # user entry local cache 
    6791        self._cache = {} 
    6892        # max time to live for a cache entry 
    6993        self._cache_ttl = int(self.config.get('ldap', 'cache_ttl', str(15*60))) 
    7094        # max cache entries 
    7195        self._cache_size = min(25, int(self.config.get('ldap', 'cache_size', '100'))) 
     96        self.ldapstyle = self.config.get('ldap', 'ldapstyle', 'openldap') 
    7297 
    7398    # IPermissionProvider interface 
    7499 
     
    146171     
    147172    def _get_user_groups(self, username): 
    148173        """Returns a list of all groups a user belongs to""" 
    149         ldap_groups = self._ldap.get_groups() 
    150174        groups = [] 
    151         for group in ldap_groups: 
    152             if self._ldap.is_in_group(self.util.user_attrdn(username), group): 
    153                 m = DN_RE.search(group) 
    154                 if m: 
    155                     groupname = GROUP_PREFIX + m.group('rdn') 
    156                     if groupname not in groups: 
     175        if self.ldapstyle == "openldap": 
     176            ldap_groups = self._ldap.get_groups() 
     177            for group in ldap_groups: 
     178                if self._ldap.is_in_group(self.util.user_attrdn(username), group): 
     179                    m = DN_RE.search(group) 
     180                    if m: 
     181                        groupname = GROUP_PREFIX + m.group('rdn') 
     182                        if groupname not in groups: 
     183                            groups.append(groupname) 
     184            return groups 
     185        if self.ldapstyle == "AD": 
     186            self._openldap() 
     187            # we do not allow a group to be in a group (also it is possible) 
     188            if not self._ldap.is_group_by_shortname(username): 
     189                ldap_groups = self._ldap.get_groups_ad() 
     190                for group in ldap_groups: 
     191                    userdn = self._ldap.get_user_DN_by_shortname(username) 
     192                    if self._ldap.is_in_group_ad(userdn,group): 
     193                        groupname = GROUP_PREFIX + self._ldap.get_group_shortname_by_DN(group) 
    157194                        groups.append(groupname) 
    158195        return groups 
     196     
     197    def _openldap(self): 
     198        # new LDAP connection 
     199        bind = self.config.getbool('ldap', 'group_bind') 
     200        self._ldap = LdapConnection(self.env.log, bind, **self._ldapcfg) 
     201 
    159202 
    160203class LdapPermissionStore(Component): 
    161204    """ 
     
    178221        for name,value in self.config.options('ldap'): 
    179222            if name in LDAP_DIRECTORY_PARAMS: 
    180223                self._ldapcfg[name] = value 
     224        self.ldapstyle=self.config.get('ldap','ldapstyle','openldap') 
    181225        # user entry local cache 
    182226        self._cache = {} 
    183227        # max time to live for a cache entry 
     
    192236        self.global_perms = self.config.getbool('ldap', 'global_perms') 
    193237        self.manage_groups = self.config.getbool('ldap', 'manage_groups') 
    194238 
     239 
    195240    # IPermissionStore interface 
    196241 
    197242    def get_user_permissions(self, username): 
     
    204249            for provider in self.group_providers: 
    205250                users += list(provider.get_permission_groups(username)) 
    206251            for user in users: 
    207                 uid = self.util.create_dn(user) 
    208                 for action in self._get_permissions(uid): 
    209                     if action not in actions: 
    210                         actions.append(action) 
    211  
     252                if self.ldapstyle == 'openldap': 
     253                    uid = self.util.create_dn(user) 
     254                    for action in self._get_permissions(uid): 
     255                        if action not in actions: 
     256                            actions.append(action) 
     257                if self.ldapstyle == 'AD': 
     258                    self._openldap() 
     259                    uid = self._ldap.create_dn_AD(user) 
     260                    if not uid or uid is None or uid is "": continue 
     261                    for action in self._get_permissions(uid): 
     262                        if action not in actions: 
     263                            actions.append(action) 
    212264            self.env.log.debug('new: %s' % actions) 
    213265            self._update_cache_actions(username, actions) 
    214266        perms = {} 
     
    223275        if not self.enabled: 
    224276            raise TracError("LdapPermissionStore is not enabled") 
    225277        perms = [] 
    226         filterstr = self.config.get('ldap', 'permfilter', 'objectclass=*') 
    227         basedn = self.config.get('ldap','basedn','').encode('ascii') 
    228         self._openldap() 
    229         dns = self._ldap.get_dn(basedn, filterstr.encode('ascii')) 
    230         permusers = [] 
    231         for dn in dns: 
    232             user = self.util.extract_user_from_dn(dn) 
    233             if not user or user in permusers: continue 
    234             permusers.append(user) 
    235             self.log.debug("permission for %s (%s)" % (user, dn)) 
    236             actions = self._ldap.get_attribute(dn, self._ldap.permattr) 
    237             for action in actions: 
    238                 xaction = self._extract_action(action) 
    239                 if not xaction: 
    240                     continue 
    241                 perms.append((user, xaction)) 
    242             if self.manage_groups: 
    243                 for provider in self.group_providers: 
    244                     if isinstance(provider, LdapPermissionGroupProvider): 
    245                         for group in provider.get_permission_groups(user): 
    246                             perms.append((user, group)) 
     278        if self.ldapstyle == 'openldap': 
     279            filterstr = self.config.get('ldap', 'permfilter', 'objectclass=*') 
     280            basedn = self.config.get('ldap','basedn','').encode('ascii') 
     281            self._openldap() 
     282            dns = self._ldap.get_dn(basedn, filterstr.encode('ascii')) 
     283            permusers = [] 
     284            for dn in dns: 
     285                user = self.util.extract_user_from_dn(dn) 
     286                if not user or user in permusers: continue 
     287                permusers.append(user) 
     288                self.log.debug("permission for %s (%s)" % (user, dn)) 
     289                actions = self._ldap.get_attribute(dn, self._ldap.permattr) 
     290                for action in actions: 
     291                    xaction = self._extract_action(action) 
     292                    if not xaction: 
     293                        continue 
     294                    perms.append((user, xaction)) 
     295                if self.manage_groups: 
     296                    for provider in self.group_providers: 
     297                        if isinstance(provider, LdapPermissionGroupProvider): 
     298                            for group in provider.get_permission_groups(user): 
     299                                perms.append((user, group)) 
     300        if self.ldapstyle == 'AD': 
     301            # connect to ldap 
     302            self._openldap() 
     303            # get all dns from user and groups 
     304            dnList = [] 
     305            self._openldap() 
     306            dnList = self._ldap.get_groups_ad() 
     307            dnList.extend(self._ldap.get_users_ad()) 
     308            permusers = [] 
     309            for dn in dnList: 
     310                # that's bad, first ask for all DNs and then query again for shortnames - datacontainer would be nice 
     311                if self._ldap.is_group_by_dn(dn): 
     312                    # mark it as a group 
     313                    user = self._ldap.get_group_shortname_by_DN(dn) 
     314                    if not user or user in permusers: 
     315                        continue 
     316                    user = GROUP_PREFIX + user 
     317                    permusers.append(user) 
     318                    actions = self._ldap.get_attribute(dn,self._ldap.mapgroupperm) 
     319                else: 
     320                    user = self._ldap.get_user_shortname_by_DN(dn) 
     321                    if not user or user in permusers: 
     322                        continue 
     323                    permusers.append(user) 
     324                    actions = self._ldap.get_attribute(dn,self._ldap.mapuserperm) 
     325                for action in actions: 
     326                    xaction = self._extract_action(action) 
     327                    if not xaction: 
     328                        continue 
     329                    perms.append((user, xaction)) 
     330                if self.manage_groups: 
     331                    for provider in self.group_providers: 
     332                        if isinstance(provider, LdapPermissionGroupProvider): 
     333                            for group in provider.get_permission_groups(user): 
     334                                perms.append((user, group)) 
    247335        return perms 
    248336 
     337 
    249338    def grant_permission(self, username, action): 
    250339        """Store the new permission for the user in the LDAP directory""" 
    251         if not self.enabled: 
    252             raise TracError("LdapPermissionStore is not enabled") 
    253         if self.manage_groups and self.util.is_group(action): 
    254             self._flush_group_cache(username) 
    255             self._add_user_to_group(username.encode('ascii'), action) 
    256             return 
    257         uid = self.util.create_dn(username.encode('ascii')) 
    258         try: 
    259             permlist = self._get_permissions(uid) 
    260             action = action.encode('ascii') 
    261             if action not in permlist: 
    262                 xaction = self._build_action(action) 
    263                 self._ldap.add_attribute(uid, self._ldap.permattr, xaction) 
    264             if self.util.is_group(username): 
    265                 # flush the cache as group dependencies are not known  
    266                 self.flush_cache() 
    267             else: 
    268                 self.flush_cache(username) 
    269                 self._add_cache_actions(username, [action]) 
    270         except ldap.LDAPError, e: 
    271             raise TracError, "Unable to grant permission %s to %s: %s" \ 
    272                              % (action, username, e[0]['desc']) 
    273  
     340        if self.ldapstyle == 'openldap': 
     341            if not self.enabled: 
     342                raise TracError("LdapPermissionStore is not enabled") 
     343            if self.manage_groups and self.util.is_group(action): 
     344                self._flush_group_cache(username) 
     345                self._add_user_to_group(username.encode('ascii'), action) 
     346                return 
     347            uid = self.util.create_dn(username.encode('ascii')) 
     348            try: 
     349                permlist = self._get_permissions(uid) 
     350                action = action.encode('ascii') 
     351                if action not in permlist: 
     352                    xaction = self._build_action(action) 
     353                    self._ldap.add_attribute(uid, self._ldap.permattr, xaction) 
     354                    if self.util.is_group(username): 
     355                        # flush the cache as group dependencies are not known  
     356                        self.flush_cache() 
     357                    else: 
     358                        self.flush_cache(username) 
     359                        self._add_cache_actions(username, [action]) 
     360            except ldap.LDAPError, e: 
     361                raise TracError, "Unable to grant permission %s to %s: %s" \ 
     362                      % (action, username, e[0]['desc']) 
     363        else: 
     364            raise TracError, "Unable to grant permission %s to %s: current style is %s " % (action, username, self.ldapstyle) 
     365                           
    274366    def revoke_permission(self, username, action): 
    275367        """Remove the permission for the user from the LDAP directory""" 
    276         if not self.enabled: 
    277             raise TracError("LdapPermissionStore is not enabled") 
    278         if self.manage_groups and self.util.is_group(action): 
    279             self._flush_group_cache(username) 
    280             self._remove_user_from_group(username.encode('ascii'), action) 
    281             return 
    282         uid = self.util.create_dn(username.encode('ascii')) 
    283         try: 
    284             permlist = self._get_permissions(uid) 
    285             if action in permlist: 
    286                 action = action.encode('ascii') 
    287                 xaction = self._build_action(action) 
    288                 self._ldap.delete_attribute(uid, self._ldap.permattr, xaction) 
    289                 if self.util.is_group(username): 
    290                     # flush the cache as group dependencies are not known  
    291                     self.flush_cache() 
    292                 else: 
    293                     self.flush_cache(username) 
    294                     self._del_cache_actions(username, [action]) 
    295         except ldap.LDAPError, e: 
    296             kind = self.global_perms and 'global' or 'project' 
    297             raise TracError, "Unable to revoke %s permission %s from %s: %s" \ 
    298                              % (kind, action, username, e[0]['desc']) 
     368        if self.ldapstyle == 'openldap': 
     369            if not self.enabled: 
     370                raise TracError("LdapPermissionStore is not enabled") 
     371            if self.manage_groups and self.util.is_group(action): 
     372                self._flush_group_cache(username) 
     373                self._remove_user_from_group(username.encode('ascii'), action) 
     374                return 
     375            uid = self.util.create_dn(username.encode('ascii')) 
     376            try: 
     377                permlist = self._get_permissions(uid) 
     378                if action in permlist: 
     379                    action = action.encode('ascii') 
     380                    xaction = self._build_action(action) 
     381                    self._ldap.delete_attribute(uid, self._ldap.permattr, xaction) 
     382                    if self.util.is_group(username): 
     383                        # flush the cache as group dependencies are not known  
     384                        self.flush_cache() 
     385                    else: 
     386                        self.flush_cache(username) 
     387                        self._del_cache_actions(username, [action]) 
     388            except ldap.LDAPError, e: 
     389                kind = self.global_perms and 'global' or 'project' 
     390                raise TracError, "Unable to revoke %s permission %s from %s: %s" \ 
     391                      % (kind, action, username, e[0]['desc']) 
     392        else: 
     393            raise TracError, "Unable to revoke permission %s from %s: current style is %s " % (action, username, self.ldapstyle) 
    299394 
    300395    # Private implementation 
    301396 
     
    308403    def _get_permissions(self, uid): 
    309404        """Retrieves the permissions from the LDAP directory""" 
    310405        self._openldap() 
    311         actions = self._ldap.get_attribute(uid, self._ldap.permattr)  
     406        if self.ldapstyle == 'openldap': 
     407            actions = self._ldap.get_attribute(uid, self._ldap.permattr) 
     408        if self.ldapstyle == 'AD': 
     409            self._openldap() 
     410            if self._ldap.is_group_by_dn(uid): 
     411                actions = self._ldap.get_attribute(uid, self._ldap.mapgroupperm) 
     412            else: 
     413                actions = self._ldap.get_attribute(uid, self._ldap.mapuserperm) 
    312414        perms = [] 
    313415        for action in actions: 
    314416            if action not in perms: 
     
    336438        return "%s:%s" % (self.env_name, action) 
    337439 
    338440    def _add_user_to_group(self, user, group): 
    339         groupdn = self.util.create_dn(group) 
    340         userdn = self.util.create_dn(user) 
    341         self._openldap() 
    342         try: 
    343             self._ldap.add_attribute(groupdn, self._ldap.groupmember, userdn) 
    344             self.log.info("user %s added to group %s" % (user, group)) 
    345         except ldap.TYPE_OR_VALUE_EXISTS, e: 
    346             # already in group, can safely ignore 
    347             self.log.debug("user %s already member of %s" % (user, group)) 
    348             return 
    349         except ldap.LDAPError, e: 
    350             raise TracError, e[0]['desc'] 
     441        if self.ldapstyle == 'openldap': 
     442            groupdn = self.util.create_dn(group) 
     443            userdn = self.util.create_dn(user) 
     444            self._openldap() 
     445            try: 
     446                self._ldap.add_attribute(groupdn, self._ldap.groupmember, userdn) 
     447                self.log.info("user %s added to group %s" % (user, group)) 
     448            except ldap.TYPE_OR_VALUE_EXISTS, e: 
     449                # already in group, can safely ignore 
     450                self.log.debug("user %s already member of %s" % (user, group)) 
     451                return 
     452            except ldap.LDAPError, e: 
     453                raise TracError, e[0]['desc'] 
     454        else: 
     455            raise TracError, "current style is %s", self.ldapstyle 
    351456         
    352457    def _remove_user_from_group(self, user, group): 
    353         groupdn = self.util.create_dn(group) 
    354         userdn = self.util.create_dn(user) 
    355         self._openldap() 
    356         try: 
    357             self._ldap.delete_attribute(groupdn, self._ldap.groupmember,  
    358                                         userdn) 
    359             self.log.info("user %s removed from group %s" % (user, group)) 
    360         except ldap.OBJECT_CLASS_VIOLATION, e: 
    361             # probable cause is an empty group 
    362             raise TracError, "Ldap error (group %s would be emptied?)" % group 
    363         except ldap.LDAPError, e: 
    364             raise TracError, e[0]['desc'] 
     458        if self.ldapstyle == 'openldap': 
     459            groupdn = self.util.create_dn(group) 
     460            userdn = self.util.create_dn(user) 
     461            self._openldap() 
     462            try: 
     463                self._ldap.delete_attribute(groupdn, self._ldap.groupmember,  
     464                                            userdn) 
     465                self.log.info("user %s removed from group %s" % (user, group)) 
     466            except ldap.OBJECT_CLASS_VIOLATION, e: 
     467                # probable cause is an empty group 
     468                raise TracError, "Ldap error (group %s would be emptied?)" % group 
     469            except ldap.LDAPError, e: 
     470                raise TracError, e[0]['desc'] 
     471        else: 
     472            raise TracError, "current style is %s", self.ldapstyle 
    365473         
    366474    def _get_cache_actions(self, username): 
    367475        """Retrieves the user permissions from the cache, if any""" 
     
    446554                           ('uidattr', 'uid'), 
    447555                           ('basedn', None), 
    448556                           ('user_rdn', None), 
    449                            ('group_rdn', None)]: 
     557                           ('group_rdn', None), 
     558                           ('ldapstyle','openldap')]: 
    450559            v = config.get('ldap', k, default) 
    451560            if v: v = v.encode('ascii').lower() 
    452561            self.__setattr__(k, v) 
     
    500609    """ 
    501610     
    502611    _BOOL_VAL = ['groupmemberisdn', 'use_tls'] 
    503     _INT_VAL  = ['port']   
     612    _INT_VAL  = ['port'] 
     613 
    504614         
    505615    def __init__(self, log, bind=False, **ldap): 
    506616        self.log = log 
     
    517627        self.basedn = None 
    518628        self.groupmemberisdn = True 
    519629        self.use_tls = False 
     630         
     631        self.ldapstyle = 'openldap' 
     632        self.mapobjectclassgroup = 'objectClass' 
     633        self.mapobjectclassuser = 'objectClass' 
     634        self.objectclassuservalue = 'user' 
     635        self.objectclassgroupvalue = 'group' 
     636        self.mapanonymoususer = 'anonymous' 
     637        self.mapauthenticateduser = 'authenticated' 
     638        self.mapuiduser = 'sAMAccount' 
     639        self.mapgidgroup = 'sAMAccount' 
     640        self.mapuserperm = 'tracperm' 
     641        self.mapgroupperm = 'tracperm' 
     642 
     643         
     644        # ugly but cannot find the problem 
     645 
    520646        for k, v in ldap.items(): 
    521647            if k in LdapConnection._BOOL_VAL: 
    522648                self.__setattr__(k, v.lower() in _TRUE_VALUES) 
     
    536662        self._ds.unbind_s() 
    537663        self._ds = None 
    538664 
     665    def get_groups_ad(self): 
     666        """Return a list of available group DNs""" 
     667        groups = self.get_dn(self.basedn, self.mapobjectclassgroup + '=' + self.objectclassgroupvalue) 
     668        return groups 
     669 
     670    def get_users_ad(self): 
     671        """Return a list of available user DNs""" 
     672        users = self.get_dn(self.basedn, self.mapobjectclassuser + '=' + self.objectclassuservalue) 
     673        return users 
     674 
     675    def create_dn_AD(self,username): 
     676        """returns the full DN for user or group""" 
     677        if username.startswith(GROUP_PREFIX): 
     678            return self.get_group_DN_by_shortname(username[len(GROUP_PREFIX):]) 
     679        else: 
     680            return self.get_user_DN_by_shortname(username) 
     681 
     682 
     683    def is_group_by_shortname(self,shortname): 
     684        """returns true if the shortname is markt as a group otherwise false""" 
     685        checkgroup = None 
     686        checkgroup = self.get_group_DN_by_shortname(shortname) 
     687        if not checkgroup or checkgroup is None: 
     688            return False 
     689        else: 
     690            return True 
     691     
     692    def is_group_by_dn(self,dn): 
     693        """returns true if the DN is markt as a group otherwise false""" 
     694        checkgroup = None 
     695        checkgroup = self.fetch_attribute(dn,self.mapobjectclassgroup) 
     696        if len(checkgroup)!=1 or not checkgroup or checkgroup is None: 
     697            return False 
     698        else: 
     699            if checkgroup[0] != self.objectclassgroupvalue: 
     700                return False 
     701            return True 
     702 
     703    def get_group_DN_by_shortname(self,shortname): 
     704        """returns the full DN for a shortname of a group""" 
     705        dn = None 
     706        dn = self.get_dn(self.basedn, 
     707                         '(&(' + self.mapobjectclassgroup + '=' + self.objectclassgroupvalue + 
     708                         ')(' + self.mapgidgroup + '=' + shortname + '))' ) 
     709        if len(dn) == 1 : 
     710            return dn[0] 
     711        return None 
     712     
     713    def get_group_shortname_by_DN(self,dn): 
     714        """returns the shortname for a group """ 
     715        # get_attribute allows filter via dn ... filter,dn 
     716        shortname = None 
     717        shortname = self.fetch_attribute(dn,self.mapgidgroup) 
     718        if not shortname or shortname is None or len(shortname)!=1: 
     719            return None 
     720        return shortname[0] 
     721             
     722    def get_user_DN_by_shortname(self,shortname): 
     723        """returns the full DN for a shortname of an user""" 
     724        dn = self.get_dn(self.basedn,self.mapuiduser + '=' + shortname) 
     725        if len(dn) == 1 : 
     726            return dn[0] 
     727        else: 
     728            return "" 
     729        return "" 
     730 
     731    def get_user_shortname_by_DN(self,dn): 
     732        """returns the shortname for an user """ 
     733        # get_attribute allows filter via dn ... filter,dn 
     734        shortname = None 
     735        shortname = self.fetch_attribute(dn, self.mapuiduser) 
     736        if not shortname or shortname is None or len(shortname)!=1: 
     737            return None 
     738        return shortname[0] 
     739     
     740    def is_in_group_ad(self,userdn,groupdn): 
     741        """returns true if a userdn is in a groupdn""" 
     742        checkgroup = False 
     743        if self.groupmemberisdn: 
     744            checkgroup = self.check_presence(groupdn,self.groupmember + "=" + userdn) 
     745        else: 
     746            checkgroup = self.check_presence(groupdn,self.groupmember + "=" + self.get_user_shortname_by_DN(userdn)) 
     747        if not checkgroup or checkgroup is None: 
     748            return False 
     749        else: 
     750            return True 
     751         
     752 
    539753    def get_groups(self): 
    540754        """Return a list of available group dns""" 
    541755        groups = self.get_dn(self.basedn, 'objectclass=' + self.groupname) 
     
    570784                break 
    571785        return dns 
    572786 
     787    def check_presence(self,dn,value): 
     788        """ 
     789        returns true if a specific dn has a specific attribut with a specific value. 
     790        value is in the form attribute=value 
     791        """ 
     792        try: 
     793            if not self.__dict__.has_key('_ds') or not self.__dict__['_ds']: 
     794