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