]> err.no Git - scalable-opengroupware.org/blob - SoObjects/SOGo/LDAPSource.m
eeb0a14afb043414fc6b07c217fa138df5b8d54c
[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   if ([loginToCheck length] > 0)
276     {
277       bindConnection = [[NGLdapConnection alloc] initWithHostName: hostname
278                                                  port: port];
279       if (timeLimit > 0)
280         [ldapConnection setQueryTimeLimit: timeLimit];
281       if (bindFields)
282         userDN = [self _fetchUserDNForLogin: loginToCheck];
283       else
284         userDN = [NSString stringWithFormat: @"%@=%@,%@",
285                            IDField, loginToCheck, baseDN];
286       if (userDN)
287         {
288           NS_DURING
289             didBind = [bindConnection bindWithMethod: @"simple"
290                                       binddn: userDN
291                                       credentials: passwordToCheck];
292           NS_HANDLER
293             didBind = NO;
294           NS_ENDHANDLER
295         }
296       [bindConnection release];
297     }
298   else
299     didBind = NO;
300
301   return didBind;
302 }
303
304 /* contact management */
305 - (EOQualifier *) _qualifierForFilter: (NSString *) filter
306 {
307   NSString *qs;
308   EOQualifier *qualifier;
309
310   if ([filter length] > 0)
311     {
312       if ([filter isEqualToString: @"."])
313         qs = @"(cn='*')";
314       else
315         qs = [NSString stringWithFormat:
316                          @"(cn='%@*')"
317                        @"OR (sn='%@*')"
318                        @"OR (displayName='%@*')"
319                        @"OR (mail='%@*')"
320                        @"OR (telephoneNumber='*%@*')",
321                        filter, filter, filter, filter, filter];
322       qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
323     }
324   else
325     qualifier = nil;
326
327   return qualifier;
328 }
329
330 - (EOQualifier *) _qualifierForUIDFilter: (NSString *) uid
331 {
332   NSString *qs;
333
334   qs = [NSString stringWithFormat: (@"(%@='%@') OR (mail='%@')"
335                                     @" OR (mozillaSecondEmail='%@')"
336                                     @" OR (xmozillasecondemail='%@')"),
337                  UIDField, uid, uid, uid, uid];
338
339   return [EOQualifier qualifierWithQualifierFormat: qs];
340 }
341
342 - (NSArray *) _searchAttributes
343 {
344   if (!searchAttributes)
345     {
346       searchAttributes = [NSMutableArray new];
347       if (CNField)
348         [searchAttributes addObject: CNField];
349       if (UIDField)
350         [searchAttributes addObject: UIDField];
351       [searchAttributes addObjectsFromArray: commonSearchFields];
352     }
353
354   return searchAttributes;
355 }
356
357 - (NSArray *) allEntryIDs
358 {
359   NSMutableArray *ids;
360   NSEnumerator *entries;
361   NGLdapEntry *currentEntry;
362   NSString *value;
363
364   ids = [NSMutableArray array];
365
366   [self _initLDAPConnection];
367   entries = [ldapConnection deepSearchAtBaseDN: baseDN
368                             qualifier: nil
369                             attributes: [NSArray arrayWithObject: IDField]];
370   if (entries)
371     {
372       currentEntry = [entries nextObject];
373       while (currentEntry)
374         {
375           value = [[currentEntry attributeWithName: IDField]
376                     stringValueAtIndex: 0];
377           if ([value length] > 0)
378             [ids addObject: value];
379           currentEntry = [entries nextObject];
380         }
381     }
382   [ldapConnection release];
383
384   return ids;
385 }
386
387 - (NSDictionary *) _convertLDAPEntryToContact: (NGLdapEntry *) ldapEntry
388 {
389   NSMutableDictionary *contactEntry;
390   NSEnumerator *attributes;
391   NSString *currentAttribute, *value;
392
393   contactEntry = [NSMutableDictionary dictionary];
394   attributes = [[self _searchAttributes] objectEnumerator];
395   currentAttribute = [attributes nextObject];
396   while (currentAttribute)
397     {
398       value = [[ldapEntry attributeWithName: currentAttribute]
399                 stringValueAtIndex: 0];
400       if (value)
401         [contactEntry setObject: value forKey: currentAttribute];
402       currentAttribute = [attributes nextObject];
403     }
404   value = [[ldapEntry attributeWithName: IDField] stringValueAtIndex: 0];
405   if (!value)
406     value = @"";
407   [contactEntry setObject: value forKey: @"c_name"];
408   value = [[ldapEntry attributeWithName: UIDField] stringValueAtIndex: 0];
409   if (!value)
410     value = @"";
411   [contactEntry setObject: value forKey: @"c_uid"];
412   value = [[ldapEntry attributeWithName: CNField] stringValueAtIndex: 0];
413   if (!value)
414     value = @"";
415   [contactEntry setObject: value forKey: @"c_cn"];
416
417   return contactEntry;
418 }
419
420 - (NSArray *) fetchContactsMatching: (NSString *) match
421 {
422   NSMutableArray *contacts;
423   NGLdapEntry *currentEntry;
424   NSEnumerator *entries;
425
426   contacts = [NSMutableArray array];
427
428   if ([match length] > 0)
429     {
430       [self _initLDAPConnection];
431       entries = [ldapConnection deepSearchAtBaseDN: baseDN
432                                 qualifier: [self _qualifierForFilter: match]
433                                 attributes: [self _searchAttributes]];
434       if (entries)
435         {
436           currentEntry = [entries nextObject];
437           while (currentEntry)
438             {
439               [contacts addObject:
440                           [self _convertLDAPEntryToContact: currentEntry]];
441               currentEntry = [entries nextObject];
442             }
443         }
444       [ldapConnection release];
445     }
446
447   return contacts;
448 }
449
450 - (NSDictionary *) lookupContactEntry: (NSString *) entryID;
451 {
452   NSDictionary *contactEntry;
453   NGLdapEntry *ldapEntry;
454
455   contactEntry = nil;
456
457   if ([entryID length] > 0)
458     {
459       [self _initLDAPConnection];
460       ldapEntry
461         = [ldapConnection entryAtDN: [NSString stringWithFormat: @"%@=%@,%@",
462                                                IDField, entryID, baseDN]
463                           attributes: [self _searchAttributes]];
464       if (ldapEntry)
465         contactEntry = [self _convertLDAPEntryToContact: ldapEntry];
466       [ldapConnection release];
467     }
468
469   return contactEntry;
470 }
471
472 - (NSDictionary *) lookupContactEntryWithUIDorEmail: (NSString *) uid;
473 {
474   NSDictionary *contactEntry;
475   NGLdapEntry *ldapEntry;
476   NSEnumerator *entries;
477   EOQualifier *qualifier;
478
479   contactEntry = nil;
480
481   if ([uid length] > 0)
482     {
483       [self _initLDAPConnection];
484       qualifier = [self _qualifierForUIDFilter: uid];
485       entries = [ldapConnection deepSearchAtBaseDN: baseDN
486                                 qualifier: qualifier
487                                 attributes: [self _searchAttributes]];
488       ldapEntry = [entries nextObject];
489       if (ldapEntry)
490         contactEntry = [self _convertLDAPEntryToContact: ldapEntry];
491       [ldapConnection release];
492     }
493
494   return contactEntry;
495 }
496
497 @end