]> err.no Git - scalable-opengroupware.org/blob - SoObjects/SOGo/LDAPSource.m
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1168 d1b88da0-ebda-0310...
[scalable-opengroupware.org] / SoObjects / SOGo / LDAPSource.m
1 /* LDAPSource.m - this file is part of SOGo
2  *
3  * Copyright (C) 2007 Inverse groupe conseil
4  *
5  * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
6  *
7  * This file is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * This file is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #import <Foundation/NSArray.h>
24 #import <Foundation/NSDictionary.h>
25 #import <Foundation/NSString.h>
26
27 #import <EOControl/EOControl.h>
28 #import <NGLdap/NGLdapConnection.h>
29 #import <NGLdap/NGLdapAttribute.h>
30 #import <NGLdap/NGLdapEntry.h>
31
32 #import "LDAPSource.h"
33
34 static NSArray *commonSearchFields;
35 static int timeLimit;
36 static int sizeLimit;
37
38 @implementation LDAPSource
39
40 + (void) initialize
41 {
42   NSUserDefaults *ud;
43
44   if (!commonSearchFields)
45     {
46       ud = [NSUserDefaults standardUserDefaults];
47       sizeLimit = [ud integerForKey: @"SOGoLDAPQueryLimit"];
48       timeLimit = [ud integerForKey: @"SOGoLDAPQueryTimeout"];
49
50       commonSearchFields = [NSArray arrayWithObjects:
51                                       @"title",
52                                     @"company",
53                                     @"o",
54                                     @"displayName",
55                                     @"modifytimestamp",
56                                     @"mozillaHomeState",
57                                     @"mozillaHomeUrl",
58                                     @"homeurl",
59                                     @"st",
60                                     @"region",
61                                     @"mozillaCustom2",
62                                     @"custom2",
63                                     @"mozillaHomeCountryName",
64                                     @"description",
65                                     @"notes",
66                                     @"department",
67                                     @"departmentnumber",
68                                     @"ou",
69                                     @"orgunit",
70                                     @"mobile",
71                                     @"cellphone",
72                                     @"carphone",
73                                     @"mozillaCustom1",
74                                     @"custom1",
75                                     @"mozillaNickname",
76                                     @"xmozillanickname",
77                                     @"mozillaWorkUrl",
78                                     @"workurl",
79                                     @"fax",
80                                     @"facsimileTelephoneNumber",
81                                     @"telephoneNumber",
82                                     @"mozillaHomeStreet",
83                                     @"mozillaSecondEmail",
84                                     @"xmozillasecondemail",
85                                     @"mozillaCustom4",
86                                     @"custom4",
87                                     @"nsAIMid",
88                                     @"nscpaimscreenname",
89                                     @"street",
90                                     @"streetAddress",
91                                     @"postOfficeBox",
92                                     @"homePhone",
93                                     @"cn",
94                                     @"commonname",
95                                     @"givenName",
96                                     @"mozillaHomePostalCode",
97                                     @"mozillaHomeLocalityName",
98                                     @"mozillaWorkStreet2",
99                                     @"mozillaUseHtmlMail",
100                                     @"xmozillausehtmlmail",
101                                     @"mozillaHomeStreet2",
102                                     @"postalCode",
103                                     @"zip",
104                                     @"c",
105                                     @"countryname",
106                                     @"pager",
107                                     @"pagerphone",
108                                     @"mail",
109                                     @"sn",
110                                     @"surname",
111                                     @"mozillaCustom3",
112                                     @"custom3",
113                                     @"l",
114                                     @"locality",
115                                     @"birthyear",
116                                     @"serialNumber",
117                                     @"calFBURL",
118                                     nil];
119       [commonSearchFields retain];
120     }
121 }
122
123 + (id) sourceFromUDSource: (NSDictionary *) udSource
124 {
125   id newSource;
126
127   newSource = [[self alloc] initFromUDSource: udSource];
128   [newSource autorelease];
129
130   return newSource;
131 }
132
133 - (id) init
134 {
135   if ((self = [super init]))
136     {
137       bindDN = nil;
138       hostname = nil;
139       port = 389;
140       password = nil;
141
142       baseDN = nil;
143       IDField = @"cn"; /* the first part of a user DN */
144       CNField = @"cn";
145       UIDField = @"uid";
146       bindFields = nil;
147
148       ldapConnection = nil;
149       searchAttributes = nil;
150     }
151
152   return self;
153 }
154
155 - (void) dealloc
156 {
157   [bindDN release];
158   [hostname release];
159   [password release];
160   [baseDN release];
161   [IDField release];
162   [CNField release];
163   [UIDField release];
164   [bindFields release];
165   [ldapConnection release];
166   [super dealloc];
167 }
168
169 - (id) initFromUDSource: (NSDictionary *) udSource
170 {
171   self = [self init];
172
173   [self setBindDN: [udSource objectForKey: @"bindDN"]
174         hostname: [udSource objectForKey: @"hostname"]
175         port: [udSource objectForKey: @"port"]
176         andPassword: [udSource objectForKey: @"bindPassword"]];
177   [self setBaseDN: [udSource objectForKey: @"baseDN"]
178         IDField: [udSource objectForKey: @"IDFieldName"]
179         CNField: [udSource objectForKey: @"CNFieldName"]
180         UIDField:  [udSource objectForKey: @"UIDFieldName"]
181         andBindFields: [udSource objectForKey: @"bindFields"]];
182
183   return self;
184 }
185
186 - (void) setBindDN: (NSString *) newBindDN
187           hostname: (NSString *) newBindHostname
188               port: (NSString *) newBindPort
189        andPassword: (NSString *) newBindPassword
190 {
191   ASSIGN (bindDN, newBindDN);
192   ASSIGN (hostname, newBindHostname);
193   if (newBindPort)
194     port = [newBindPort intValue];
195   ASSIGN (password, newBindPassword);
196 }
197
198 - (void) setBaseDN: (NSString *) newBaseDN
199            IDField: (NSString *) newIDField
200            CNField: (NSString *) newCNField
201           UIDField: (NSString *) newUIDField
202      andBindFields: (NSString *) newBindFields
203 {
204   ASSIGN (baseDN, newBaseDN);
205   if (newIDField)
206     ASSIGN (IDField, newIDField);
207   if (CNField)
208     ASSIGN (CNField, newCNField);
209   if (UIDField)
210     ASSIGN (UIDField, newUIDField);
211   if (newBindFields)
212     ASSIGN (bindFields, newBindFields);
213 }
214
215 - (void) _initLDAPConnection
216 {
217   ldapConnection = [[NGLdapConnection alloc] initWithHostName: hostname
218                                              port: port];
219   [ldapConnection bindWithMethod: @"simple"
220                   binddn: bindDN
221                   credentials: password];
222   if (sizeLimit > 0)
223     [ldapConnection setQuerySizeLimit: sizeLimit];
224   if (timeLimit > 0)
225     [ldapConnection setQueryTimeLimit: timeLimit];
226 }
227
228 /* user management */
229 - (EOQualifier *) _qualifierForBindFilter: (NSString *) uid
230 {
231   NSMutableString *qs;
232   NSEnumerator *fields;
233   NSString *currentField;
234
235   qs = [NSMutableString string];
236   fields = [[bindFields componentsSeparatedByString: @","] objectEnumerator];
237   currentField = [fields nextObject];
238   while (currentField)
239     {
240       [qs appendFormat: @"OR (%@='%@')", currentField, uid];
241       currentField = [fields nextObject];
242     }
243   [qs deleteCharactersInRange: NSMakeRange (0, 3)];
244
245   return [EOQualifier qualifierWithQualifierFormat: qs];
246 }
247
248 - (NSString *) _fetchUserDNForLogin: (NSString *) loginToCheck
249 {
250   NSString *userDN;
251   NSEnumerator *entries;
252   NGLdapEntry *userEntry;
253
254   [self _initLDAPConnection];
255   entries = [ldapConnection deepSearchAtBaseDN: baseDN
256                             qualifier: [self _qualifierForBindFilter: loginToCheck]
257                             attributes: [NSArray arrayWithObject: @"dn"]];
258   userEntry = [entries nextObject];
259   if (userEntry)
260     userDN = [userEntry dn];
261   else
262     userDN = nil;
263   [ldapConnection release];
264
265   return userDN;
266 }
267
268 - (BOOL) checkLogin: (NSString *) loginToCheck
269         andPassword: (NSString *) passwordToCheck
270 {
271   BOOL didBind;
272   NSString *userDN;
273   NGLdapConnection *bindConnection;
274
275   didBind = NO;
276
277   if ([loginToCheck length] > 0)
278     {
279       bindConnection = [[NGLdapConnection alloc] initWithHostName: hostname
280                                                  port: port];
281       if (timeLimit > 0)
282         [ldapConnection setQueryTimeLimit: timeLimit];
283       if (bindFields)
284         userDN = [self _fetchUserDNForLogin: loginToCheck];
285       else
286         userDN = [NSString stringWithFormat: @"%@=%@,%@",
287                            IDField, loginToCheck, baseDN];
288       if (userDN)
289         {
290           NS_DURING
291             didBind = [bindConnection bindWithMethod: @"simple"
292                                       binddn: userDN
293                                       credentials: passwordToCheck];
294           NS_HANDLER
295           NS_ENDHANDLER
296         }
297       [bindConnection release];
298     }
299
300   return didBind;
301 }
302
303 /* contact management */
304 - (EOQualifier *) _qualifierForFilter: (NSString *) filter
305 {
306   NSString *qs;
307   EOQualifier *qualifier;
308
309   if ([filter length] > 0)
310     {
311       if ([filter isEqualToString: @"."])
312         qs = @"(cn='*')";
313       else
314         qs = [NSString stringWithFormat:
315                          @"(cn='%@*')"
316                        @"OR (sn='%@*')"
317                        @"OR (displayName='%@*')"
318                        @"OR (mail='%@*')"
319                        @"OR (telephoneNumber='*%@*')",
320                        filter, filter, filter, filter, filter];
321       qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
322     }
323   else
324     qualifier = nil;
325
326   return qualifier;
327 }
328
329 - (EOQualifier *) _qualifierForUIDFilter: (NSString *) uid
330 {
331   NSString *qs;
332
333   qs = [NSString stringWithFormat: (@"(%@='%@') OR (mail='%@')"
334                                     @" OR (mozillaSecondEmail='%@')"
335                                     @" OR (xmozillasecondemail='%@')"),
336                  UIDField, uid, uid, uid, uid];
337
338   return [EOQualifier qualifierWithQualifierFormat: qs];
339 }
340
341 - (NSArray *) _searchAttributes
342 {
343   if (!searchAttributes)
344     {
345       searchAttributes = [NSMutableArray new];
346       if (CNField)
347         [searchAttributes addObject: CNField];
348       if (UIDField)
349         [searchAttributes addObject: UIDField];
350       [searchAttributes addObjectsFromArray: commonSearchFields];
351     }
352
353   return searchAttributes;
354 }
355
356 - (NSArray *) allEntryIDs
357 {
358   NSMutableArray *ids;
359   NSEnumerator *entries;
360   NGLdapEntry *currentEntry;
361   NSString *value;
362
363   ids = [NSMutableArray array];
364
365   [self _initLDAPConnection];
366   entries = [ldapConnection deepSearchAtBaseDN: baseDN
367                             qualifier: nil
368                             attributes: [NSArray arrayWithObject: IDField]];
369   if (entries)
370     {
371       currentEntry = [entries nextObject];
372       while (currentEntry)
373         {
374           value = [[currentEntry attributeWithName: IDField]
375                     stringValueAtIndex: 0];
376           if ([value length] > 0)
377             [ids addObject: value];
378           currentEntry = [entries nextObject];
379         }
380     }
381   [ldapConnection release];
382
383   return ids;
384 }
385
386 - (NSDictionary *) _convertLDAPEntryToContact: (NGLdapEntry *) ldapEntry
387 {
388   NSMutableDictionary *contactEntry;
389   NSEnumerator *attributes;
390   NSString *currentAttribute, *value;
391
392   contactEntry = [NSMutableDictionary dictionary];
393   attributes = [[self _searchAttributes] objectEnumerator];
394   currentAttribute = [attributes nextObject];
395   while (currentAttribute)
396     {
397       value = [[ldapEntry attributeWithName: currentAttribute]
398                 stringValueAtIndex: 0];
399       if (value)
400         [contactEntry setObject: value forKey: currentAttribute];
401       currentAttribute = [attributes nextObject];
402     }
403   value = [[ldapEntry attributeWithName: IDField] stringValueAtIndex: 0];
404   if (!value)
405     value = @"";
406   [contactEntry setObject: value forKey: @"c_name"];
407   value = [[ldapEntry attributeWithName: UIDField] stringValueAtIndex: 0];
408   if (!value)
409     value = @"";
410   [contactEntry setObject: value forKey: @"c_uid"];
411   value = [[ldapEntry attributeWithName: CNField] stringValueAtIndex: 0];
412   if (!value)
413     value = @"";
414   [contactEntry setObject: value forKey: @"c_cn"];
415
416   return contactEntry;
417 }
418
419 - (NSArray *) fetchContactsMatching: (NSString *) match
420 {
421   NSMutableArray *contacts;
422   NGLdapEntry *currentEntry;
423   NSEnumerator *entries;
424
425   contacts = [NSMutableArray array];
426
427   if ([match length] > 0)
428     {
429       [self _initLDAPConnection];
430       entries = [ldapConnection deepSearchAtBaseDN: baseDN
431                                 qualifier: [self _qualifierForFilter: match]
432                                 attributes: [self _searchAttributes]];
433       if (entries)
434         {
435           currentEntry = [entries nextObject];
436           while (currentEntry)
437             {
438               [contacts addObject:
439                           [self _convertLDAPEntryToContact: currentEntry]];
440               currentEntry = [entries nextObject];
441             }
442         }
443       [ldapConnection release];
444     }
445
446   return contacts;
447 }
448
449 - (NSDictionary *) lookupContactEntry: (NSString *) entryID;
450 {
451   NSDictionary *contactEntry;
452   NGLdapEntry *ldapEntry;
453
454   contactEntry = nil;
455
456   if ([entryID length] > 0)
457     {
458       [self _initLDAPConnection];
459       ldapEntry
460         = [ldapConnection entryAtDN: [NSString stringWithFormat: @"%@=%@,%@",
461                                                IDField, entryID, baseDN]
462                           attributes: [self _searchAttributes]];
463       if (ldapEntry)
464         contactEntry = [self _convertLDAPEntryToContact: ldapEntry];
465       [ldapConnection release];
466     }
467
468   return contactEntry;
469 }
470
471 - (NSDictionary *) lookupContactEntryWithUIDorEmail: (NSString *) uid;
472 {
473   NSDictionary *contactEntry;
474   NGLdapEntry *ldapEntry;
475   NSEnumerator *entries;
476   EOQualifier *qualifier;
477
478   contactEntry = nil;
479
480   if ([uid length] > 0)
481     {
482       [self _initLDAPConnection];
483       qualifier = [self _qualifierForUIDFilter: uid];
484       entries = [ldapConnection deepSearchAtBaseDN: baseDN
485                                 qualifier: qualifier
486                                 attributes: [self _searchAttributes]];
487       ldapEntry = [entries nextObject];
488       if (ldapEntry)
489         contactEntry = [self _convertLDAPEntryToContact: ldapEntry];
490       [ldapConnection release];
491     }
492
493   return contactEntry;
494 }
495
496 @end