Ticket #2293: ldappluginAD.2.patch
| File ldappluginAD.2.patch, 40.8 kB (added by asklepios, 1 year ago) |
|---|
-
0.10/COPYING
old new 1 1 Copyright (C) 2005-2006 Emmanuel Blot <emmanuel.blot@free.fr> 2 2 All rights reserved. 3 3 4 Copyright (C) 2007-2008 Sirrix AG <www.sirrix.com> 5 (Alexander Kasper wrote Active Directory Extension) 6 All rights reserved 7 4 8 Redistribution and use in source and binary forms, with or without 5 9 modification, are permitted provided that the following conditions 6 10 are met: -
0.10/ad-schema/README
old new 1 Warning: please use a testenvironment since schemadefinitions for AD are complex, at multible places redundant and extrem ugly :) 2 3 00 importcommand is ldifde -i -f <filename> 4 01 command to get 'dn' is (replace DC=shoel,DC=local and shoel.local with your domain) 5 01.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 6 01.1.group for linux: ldapsearch -D loginname@shoel.local -h <hostip> -x -w **password** -LLL -b "DC=shoel,DC=local" 'objectclass=group' sAMAccountName dn 7 01.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** 8 01.2.group for windows: ldifde -f output.txt -l dn,sAMAccountName -r "(objectclass=group)" -d "DC=shoel,DC=local" -b loginname shoel.local **password** 9 02 modfiy *.ldf to fir yout needs minimal replace shoel.local resp DC=shoel,DC=local with your domain 10 03 Import TracADExtension.ldf 11 04.1 to mark a User/Group as a TracGroup use make_User_TracUser.ldf or make_Group_TracGroup.ldf 12 04.2 to give a attribute to a user / Group use add_TracPerm_to_User.ldf or add_TracPerm_to_Group.ldf 13 05 the structure is TracPerm,TracGroup and TracUser are Attributes and TracExt is the coresponding class 14 06 TracExt is an auxiliaryclass of the Buildin Classes User and Group 15 -
0.10/ad-schema/TracADextension.ldf
old new 1 dn: CN=TracPerm,CN=Schema,CN=Configuration,DC=shoel,DC=local 2 changetype: add 3 objectClass: top 4 objectClass: attributeSchema 5 cn: TracPerm 6 distinguishedName: CN=TracPerm,CN=Schema,CN=Configuration,DC=shoel,DC=local 7 instanceType: 4 8 attributeID: 1.3.6.1.4.1.2342.2.1 9 attributeSyntax: 2.5.5.3 10 isSingleValued: FALSE 11 showInAdvancedViewOnly: TRUE 12 adminDisplayName: TracPerm 13 adminDescription: Trac Permission Store 14 oMSyntax: 27 15 lDAPDisplayName: TracPerm 16 name: TracPerm 17 objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=shoel,DC=local 18 19 dn: CN=TracGroup,CN=Schema,CN=Configuration,DC=shoel,DC=local 20 changetype: add 21 objectClass: top 22 objectClass: attributeSchema 23 cn: TracGroup 24 distinguishedName: CN=TracGroup,CN=Schema,CN=Configuration,DC=shoel,DC=local 25 instanceType: 4 26 attributeID: 1.3.6.1.4.1.2342.2.2 27 attributeSyntax: 2.5.5.3 28 isSingleValued: FALSE 29 showInAdvancedViewOnly: TRUE 30 adminDisplayName: TracGroup 31 adminDescription: Trac flag for a Group 32 oMSyntax: 27 33 lDAPDisplayName: TracGroup 34 name: TracGroup 35 objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=shoel,DC=local 36 37 dn: CN=TracUser,CN=Schema,CN=Configuration,DC=shoel,DC=local 38 changetype: add 39 objectClass: top 40 objectClass: attributeSchema 41 cn: TracUser 42 distinguishedName: CN=TracUser,CN=Schema,CN=Configuration,DC=shoel,DC=local 43 instanceType: 4 44 attributeID: 1.3.6.1.4.1.2342.2.3 45 attributeSyntax: 2.5.5.3 46 isSingleValued: FALSE 47 showInAdvancedViewOnly: TRUE 48 adminDisplayName: TracUser 49 adminDescription: Trac flag for a User 50 oMSyntax: 27 51 lDAPDisplayName: TracUser 52 name: TracUser 53 objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=shoel,DC=local 54 55 dn: 56 changetype: modify 57 add: schemaupdatenow 58 schemaupdatenow: 1 59 - 60 61 dn: CN=TracExt,CN=Schema,CN=Configuration,DC=shoel,DC=local 62 changetype: add 63 objectClass: top 64 objectClass: classSchema 65 cn: TracExt 66 distinguishedName: CN=TracExt,CN=Schema,CN=Configuration,DC=shoel,DC=local 67 instanceType: 4 68 governsID: 1.3.6.1.4.1.2342.1.3 69 mayContain: TracPerm 70 mayContain: TracGroup 71 mayContain: TracUser 72 showInAdvancedViewOnly: TRUE 73 adminDisplayName: TracExt 74 adminDescription: Extension for Trac 75 objectClassCategory: 3 76 lDAPDisplayName: TracExt 77 name: Trac 78 systemOnly: FALSE 79 defaultObjectCategory: CN=TracExt,CN=Schema,CN=Configuration,DC=shoel,DC=local 80 81 dn: 82 changetype: modify 83 add: schemaupdatenow 84 schemaupdatenow: 1 85 - 86 87 dn: CN=User,CN=Schema,CN=Configuration,DC=shoel,DC=local 88 changetype: modify 89 add: auxiliaryClass 90 auxiliaryClass: TracExt 91 - 92 93 dn: CN=Group,CN=Schema,CN=Configuration,DC=shoel,DC=local 94 changetype: modify 95 add: auxiliaryClass 96 auxiliaryClass: TracExt 97 - 98 99 dn: 100 changetype: modify 101 add: schemaupdatenow 102 schemaupdatenow: 1 103 - 104 -
0.10/ad-schema/add_TracPerm_to_Group.ldf
old new 1 dn: CN=devel,ou=groups,OU=shoel,DC=shoel,DC=local 2 changetype: modify 3 add: TracPerm 4 TracPerm: project:WIKI_VIEW 5 - 6 7 dn: 8 changetype: modify 9 add: schemaupdatenow 10 schemaupdatenow: 1 11 - 12 -
0.10/ad-schema/add_TracPerm_to_User.ldf
old new 1 dn: CN=asklepios as. shoel,ou=users,OU=shoel,DC=shoel,DC=local 2 changetype: modify 3 add: TracPerm 4 TracPerm: project:WIKI_ADMIN 5 - 6 7 dn: 8 changetype: modify 9 add: schemaupdatenow 10 schemaupdatenow: 1 11 - -
0.10/ad-schema/del_TracPerm_from_Group.ldf
old new 1 dn: CN=devel,ou=groups,OU=shoel,DC=shoel,DC=local 2 changetype: modify 3 delete: TracPerm 4 TracPerm: project:WIKI_VIEW 5 - 6 7 dn: 8 changetype: modify 9 add: schemaupdatenow 10 schemaupdatenow: 1 11 - 12 -
0.10/ad-schema/del_TracPerm_from_User.ldf
old new 1 dn: CN=asklepios as. shoel,ou=users,OU=shoel,DC=shoel,DC=local 2 changetype: modify 3 delete: TracPerm 4 TracPerm: project:WIKI_ADMIN 5 - 6 7 dn: 8 changetype: modify 9 add: schemaupdatenow 10 schemaupdatenow: 1 11 - -
0.10/ad-schema/make_Group_TracGroup.ldf
old new 1 dn: CN=mitarbeiter,ou=groups,OU=shoel,DC=shoel,DC=local 2 changetype: modify 3 add: TracGroup 4 TracGroup: TRUE 5 - 6 7 dn: 8 changetype: modify 9 add: schemaupdatenow 10 schemaupdatenow: 1 11 - 12 -
0.10/ad-schema/make_User_TracUser.ldf
old new 1 dn: CN=asklepios as. shoel,ou=users,OU=shoel,DC=shoel,DC=local 2 changetype: modify 3 add: TracUser 4 TracUser: TRUE 5 - 6 7 dn: 8 changetype: modify 9 add: schemaupdatenow 10 schemaupdatenow: 1 11 - -
0.10/ad-schema/unmake_Group_TracGroup.ldf
old new 1 dn: CN=mitarbeiter,ou=groups,OU=shoel,DC=shoel,DC=local 2 changetype: modify 3 delete: TracGroup 4 TracGroup: TRUE 5 - 6 7 dn: 8 changetype: modify 9 add: schemaupdatenow 10 schemaupdatenow: 1 11 - 12 -
0.10/ad-schema/unmake_User_TracUser.ldf
old new 1 dn: CN=asklepios as. shoel,ou=users,OU=shoel,DC=shoel,DC=local 2 changetype: modify 3 delete: TracUser 4 TracUser: TRUE 5 - 6 7 dn: 8 changetype: modify 9 add: schemaupdatenow 10 schemaupdatenow: 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] 4 authentication_url = http://localhost/testcase/ 5 password_store = HttpAuthStore 6 7 [attachment] 8 max_size = 262144 9 render_unsafe_content = false 10 11 [blog] 12 date_format = %x %X 13 default_tag = news 14 first_week_day = SUNDAY 15 footer = 16 history_days = 30 17 macro_blacklist = 18 mark_updated = true 19 nav_bar = false 20 new_blog_link = New News 21 num_posts = 5 22 page_format = %Y/%m/%d/%H.%M 23 post_size = 1024 24 25 [browser] 26 downloadable_paths = /trunk, /branches/*, /tags/* 27 hide_properties = svk:merge 28 render_unsafe_content = false 29 30 [changeset] 31 max_diff_bytes = 10000000 32 max_diff_files = 0 33 wiki_format_messages = true 34 35 [components] 36 acct_mgr.admin.accountmanageradminpage = enabled 37 acct_mgr.api.accountmanager = enabled 38 acct_mgr.db.sessionstore = enabled 39 acct_mgr.htfile.abstractpasswordfilestore = enabled 40 acct_mgr.htfile.htdigeststore = enabled 41 acct_mgr.htfile.htpasswdstore = enabled 42 acct_mgr.http.httpauthstore = enabled 43 acct_mgr.pwhash.htdigesthashmethod = enabled 44 acct_mgr.pwhash.htpasswdhashmethod = enabled 45 acct_mgr.web_ui.loginmodule = enabled 46 trac.web.auth.LoginModule = disabled 47 ldapplugin.api.* = enabled 48 tblog.* = enabled 49 trac.ticket.report.* = disabled 50 trac2latex.trac2latex.* = enabled 51 tractags.* = enabled 52 tractoc.macro.* = enabled 53 tramplugin.* = enabled 54 webadmin.* = enabled 55 webadmin.basics.* = enabled 56 webadmin.logging.* = enabled 57 webadmin.perm.* = enabled 58 webadmin.plugin.* = enabled 59 webadmin.ticket.* = enabled 60 webadmin.web_ui.* = enabled 61 62 [header_logo] 63 alt = the logo 64 height = 70 65 link = 66 src = 67 width = 209 68 69 [ldap] 70 basedn = dc=shoel,dc=local 71 bind_passwd = nNuwQi1 72 bind_user = CN=trac accountauth,DC=shoel,DC=local 73 enable = true 74 group_bind = true 75 group_rdn = 76 groupattr = cn 77 groupmember = member 78 groupmemberisdn = true 79 groupname = 80 ldapstyle = AD 81 mapobjectclassgroup = TracGroup 82 mapobjectclassuser = TracUser 83 objectclassuservalue = TRUE 84 objectclassgroupvalue = TRUE 85 mapanonymoususer = anonymous 86 mapauthenticateduser = authenticated 87 mapuiduser = sAMAccountName 88 mapgidgroup = sAMAccountName 89 mapuserperm = TracPerm 90 mapgroupperm = TracPerm 91 manage_groups = true 92 host = 192.168.0.2 93 port = 389 94 permattr = tracperm 95 permfilter = objectclass=* 96 store_bind = true 97 uidattr = uid 98 use_tls = false 99 user_rdn = 100 cache_ttl = 300 101 cache_size = 100 102 103 [logging] 104 log_file = /trac/testtrac/log/trac.log 105 log_level = DEBUG 106 log_type = file 107 108 [mimeviewer] 109 enscript_modes = text/x-dylan:dylan:4 110 enscript_path = enscript 111 max_preview_size = 262144 112 mime_map = text/x-dylan:dylan,text/x-idl:ice,text/x-ada:ads:adb 113 php_path = php 114 silvercity_modes = 115 tab_width = 8 116 117 [notification] 118 always_notify_owner = false 119 always_notify_reporter = false 120 always_notify_updater = false 121 mime_encoding = base64 122 smtp_always_bcc = 123 smtp_always_cc = 124 smtp_default_domain = 125 smtp_enabled = false 126 smtp_from = 127 smtp_password = 128 smtp_port = 25 129 smtp_replyto = 130 smtp_server = 131 smtp_subject_prefix = 132 smtp_user = 133 use_public_cc = true 134 use_short_addr = false 135 use_tls = false 136 137 [project] 138 descr = This is the knowledge database 139 footer = Visit the Trac open source project at<br /><a href="http://trac.edgewall.org/">http://trac.edgewall.org/</a> 140 icon = site/icon.gif 141 name = My Project 142 url = http://funny.an.url 143 144 [search] 145 min_query_length = 3 146 147 [ticket] 148 default_component = 149 default_milestone = 150 default_priority = major 151 default_type = defect 152 default_version = 153 restrict_owner = false 154 155 [timeline] 156 changeset_long_messages = false 157 changeset_show_files = 0 158 default_daysback = 30 159 ticket_show_details = false 160 161 [trac] 162 authz_file = 163 authz_module_name = 164 base_url = 165 check_auth_ip = true 166 database = sqlite:db/trac.db 167 default_charset = iso-8859-15 168 default_handler = WikiModule 169 htdocs_location = 170 ignore_auth_case = false 171 mainnav = wiki,timeline,roadmap,browser,tickets,newticket,search 172 metanav = login,logout,settings,help,about 173 permission_store = LdapPermissionStore 174 ;permission_store = DefaultPermissionStore 175 repository_dir = 176 repository_type = svn 177 timeout = 20 178 179 [wiki] 180 ignore_missing_pages = false 181 split_page_names = false 182 -
0.10/ldapplugin/api.py
old new 4 4 # 5 5 # Copyright (C) 2003-2006 Edgewall Software 6 6 # Copyright (C) 2005-2006 Emmanuel Blot <emmanuel.blot@free.fr> 7 # Copyright (C) 2007-2008 Sirrix AG <www.sirrix.com> (Active Directory) 7 8 # All rights reserved. 8 9 # 9 10 # This software is licensed as described in the file COPYING, which … … 19 20 # a concern. 20 21 # Requires Python-LDAP, available from http://python-ldap.sourceforge.net 21 22 # 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 22 39 23 40 import re 24 41 import time … … 37 54 LDAP_DIRECTORY_PARAMS = [ 'host', 'port', 'use_tls', 'basedn', 38 55 'bind_user', 'bind_passwd', 39 56 '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 41 64 42 65 GROUP_PREFIX = '@' 43 66 … … 63 86 for name,value in self.config.options('ldap'): 64 87 if name in LDAP_DIRECTORY_PARAMS: 65 88 self._ldapcfg[name] = value 89 66 90 # user entry local cache 67 91 self._cache = {} 68 92 # max time to live for a cache entry 69 93 self._cache_ttl = int(self.config.get('ldap', 'cache_ttl', str(15*60))) 70 94 # max cache entries 71 95 self._cache_size = min(25, int(self.config.get('ldap', 'cache_size', '100'))) 96 self.ldapstyle = self.config.get('ldap', 'ldapstyle', 'openldap') 72 97 73 98 # IPermissionProvider interface 74 99 … … 146 171 147 172 def _get_user_groups(self, username): 148 173 """Returns a list of all groups a user belongs to""" 149 ldap_groups = self._ldap.get_groups()150 174 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) 157 194 groups.append(groupname) 158 195 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 159 202 160 203 class LdapPermissionStore(Component): 161 204 """ … … 178 221 for name,value in self.config.options('ldap'): 179 222 if name in LDAP_DIRECTORY_PARAMS: 180 223 self._ldapcfg[name] = value 224 self.ldapstyle=self.config.get('ldap','ldapstyle','openldap') 181 225 # user entry local cache 182 226 self._cache = {} 183 227 # max time to live for a cache entry … … 192 236 self.global_perms = self.config.getbool('ldap', 'global_perms') 193 237 self.manage_groups = self.config.getbool('ldap', 'manage_groups') 194 238 239 195 240 # IPermissionStore interface 196 241 197 242 def get_user_permissions(self, username): … … 204 249 for provider in self.group_providers: 205 250 users += list(provider.get_permission_groups(username)) 206 251 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) 212 264 self.env.log.debug('new: %s' % actions) 213 265 self._update_cache_actions(username, actions) 214 266 perms = {} … … 223 275 if not self.enabled: 224 276 raise TracError("LdapPermissionStore is not enabled") 225 277 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)) 247 335 return perms 248 336 337 249 338 def grant_permission(self, username, action): 250 339 """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 274 366 def revoke_permission(self, username, action): 275 367 """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) 299 394 300 395 # Private implementation 301 396 … … 308 403 def _get_permissions(self, uid): 309 404 """Retrieves the permissions from the LDAP directory""" 310 405 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) 312 414 perms = [] 313 415 for action in actions: 314 416 if action not in perms: … … 336 438 return "%s:%s" % (self.env_name, action) 337 439 338 440 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 351 456 352 457 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 365 473 366 474 def _get_cache_actions(self, username): 367 475 """Retrieves the user permissions from the cache, if any""" … … 446 554 ('uidattr', 'uid'), 447 555 ('basedn', None), 448 556 ('user_rdn', None), 449 ('group_rdn', None)]: 557 ('group_rdn', None), 558 ('ldapstyle','openldap')]: 450 559 v = config.get('ldap', k, default) 451 560 if v: v = v.encode('ascii').lower() 452 561 self.__setattr__(k, v) … … 500 609 """ 501 610 502 611 _BOOL_VAL = ['groupmemberisdn', 'use_tls'] 503 _INT_VAL = ['port'] 612 _INT_VAL = ['port'] 613 504 614 505 615 def __init__(self, log, bind=False, **ldap): 506 616 self.log = log … … 517 627 self.basedn = None 518 628 self.groupmemberisdn = True 519 629 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 520 646 for k, v in ldap.items(): 521 647 if k in LdapConnection._BOOL_VAL: 522 648 self.__setattr__(k, v.lower() in _TRUE_VALUES) … … 536 662 self._ds.unbind_s() 537 663 self._ds = None 538 664 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 539 753 def get_groups(self): 540 754 """Return a list of available group dns""" 541 755 groups = self.get_dn(self.basedn, 'objectclass=' + self.groupname) … … 570 784 break 571 785 return dns 572 786 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
