1 /* LDAPSource.m - this file is part of SOGo
3 * Copyright (C) 2007 Inverse groupe conseil
5 * Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
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)
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.
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.
23 #import <Foundation/NSArray.h>
24 #import <Foundation/NSDictionary.h>
25 #import <Foundation/NSString.h>
27 #import <EOControl/EOControl.h>
28 #import <NGLdap/NGLdapConnection.h>
29 #import <NGLdap/NGLdapAttribute.h>
30 #import <NGLdap/NGLdapEntry.h>
32 #import "LDAPSource.h"
33 #import "LDAPUserManager.h"
35 static NSArray *commonSearchFields;
39 @implementation LDAPSource
45 if (!commonSearchFields)
47 ud = [NSUserDefaults standardUserDefaults];
48 sizeLimit = [ud integerForKey: @"SOGoLDAPQueryLimit"];
49 timeLimit = [ud integerForKey: @"SOGoLDAPQueryTimeout"];
51 commonSearchFields = [NSArray arrayWithObjects:
64 @"mozillaHomeCountryName",
81 @"facsimileTelephoneNumber",
84 @"mozillaSecondEmail",
85 @"xmozillasecondemail",
97 @"mozillaHomePostalCode",
98 @"mozillaHomeLocalityName",
99 @"mozillaWorkStreet2",
100 @"mozillaUseHtmlMail",
101 @"xmozillausehtmlmail",
102 @"mozillaHomeStreet2",
118 @"calFBURL", @"proxyAddresses",
121 [commonSearchFields retain];
125 + (id) sourceFromUDSource: (NSDictionary *) udSource
129 newSource = [[self alloc] initFromUDSource: udSource];
130 [newSource autorelease];
137 if ((self = [super init]))
146 IDField = @"cn"; /* the first part of a user DN */
149 mailFields = [NSArray arrayWithObject: @"mail"];
153 ldapConnection = nil;
154 searchAttributes = nil;
169 [mailFields release];
170 [bindFields release];
171 [ldapConnection release];
173 [modulesConstraints release];
177 - (id) initFromUDSource: (NSDictionary *) udSource
181 ASSIGN(sourceID, [udSource objectForKey: @"id"]);
183 [self setBindDN: [udSource objectForKey: @"bindDN"]
184 hostname: [udSource objectForKey: @"hostname"]
185 port: [udSource objectForKey: @"port"]
186 andPassword: [udSource objectForKey: @"bindPassword"]];
187 [self setBaseDN: [udSource objectForKey: @"baseDN"]
188 IDField: [udSource objectForKey: @"IDFieldName"]
189 CNField: [udSource objectForKey: @"CNFieldName"]
190 UIDField: [udSource objectForKey: @"UIDFieldName"]
191 mailFields: [udSource objectForKey: @"MailFieldNames"]
192 andBindFields: [udSource objectForKey: @"bindFields"]];
193 ASSIGN (modulesConstraints, [udSource objectForKey: @"ModulesConstraints"]);
198 - (void) setBindDN: (NSString *) newBindDN
199 hostname: (NSString *) newBindHostname
200 port: (NSString *) newBindPort
201 andPassword: (NSString *) newBindPassword
203 ASSIGN (bindDN, newBindDN);
204 ASSIGN (hostname, newBindHostname);
206 port = [newBindPort intValue];
207 ASSIGN (password, newBindPassword);
210 - (void) setBaseDN: (NSString *) newBaseDN
211 IDField: (NSString *) newIDField
212 CNField: (NSString *) newCNField
213 UIDField: (NSString *) newUIDField
214 mailFields: (NSArray *) newMailFields
215 andBindFields: (NSString *) newBindFields
217 ASSIGN (baseDN, newBaseDN);
219 ASSIGN (IDField, newIDField);
221 ASSIGN (CNField, newCNField);
223 ASSIGN (UIDField, newUIDField);
225 ASSIGN (mailFields, newMailFields);
227 ASSIGN (bindFields, newBindFields);
230 - (void) _initLDAPConnection
232 ldapConnection = [[NGLdapConnection alloc] initWithHostName: hostname
234 [ldapConnection bindWithMethod: @"simple"
236 credentials: password];
238 [ldapConnection setQuerySizeLimit: sizeLimit];
240 [ldapConnection setQueryTimeLimit: timeLimit];
243 /* user management */
244 - (EOQualifier *) _qualifierForBindFilter: (NSString *) uid
247 NSEnumerator *fields;
248 NSString *currentField;
250 qs = [NSMutableString string];
251 fields = [[bindFields componentsSeparatedByString: @","] objectEnumerator];
252 currentField = [fields nextObject];
255 [qs appendFormat: @"OR (%@='%@')", currentField, uid];
256 currentField = [fields nextObject];
258 [qs deleteCharactersInRange: NSMakeRange (0, 3)];
260 return [EOQualifier qualifierWithQualifierFormat: qs];
263 - (NSString *) _fetchUserDNForLogin: (NSString *) loginToCheck
266 NSEnumerator *entries;
267 NGLdapEntry *userEntry;
269 [self _initLDAPConnection];
270 entries = [ldapConnection deepSearchAtBaseDN: baseDN
271 qualifier: [self _qualifierForBindFilter: loginToCheck]
272 attributes: [NSArray arrayWithObject: @"dn"]];
273 userEntry = [entries nextObject];
275 userDN = [userEntry dn];
278 [ldapConnection release];
283 - (BOOL) checkLogin: (NSString *) loginToCheck
284 andPassword: (NSString *) passwordToCheck
288 NGLdapConnection *bindConnection;
292 if ([loginToCheck length] > 0)
294 bindConnection = [[NGLdapConnection alloc] initWithHostName: hostname
297 [ldapConnection setQueryTimeLimit: timeLimit];
299 userDN = [self _fetchUserDNForLogin: loginToCheck];
301 userDN = [NSString stringWithFormat: @"%@=%@,%@",
302 IDField, loginToCheck, baseDN];
306 didBind = [bindConnection bindWithMethod: @"simple"
308 credentials: passwordToCheck];
312 [bindConnection release];
318 /* contact management */
319 - (EOQualifier *) _qualifierForFilter: (NSString *) filter
322 EOQualifier *qualifier;
324 if ([filter length] > 0)
326 if ([filter isEqualToString: @"."])
329 qs = [NSString stringWithFormat:
332 @"OR (displayName='%@*')"
334 @"OR (telephoneNumber='*%@*')",
335 filter, filter, filter, filter, filter];
336 qualifier = [EOQualifier qualifierWithQualifierFormat: qs];
344 - (EOQualifier *) _qualifierForUIDFilter: (NSString *) uid
348 qs = [NSString stringWithFormat: (@"(%@='%@') OR (mail='%@')"
349 @" OR (mozillaSecondEmail='%@')"
350 @" OR (xmozillasecondemail='%@')"),
351 UIDField, uid, uid, uid, uid];
353 return [EOQualifier qualifierWithQualifierFormat: qs];
356 - (NSArray *) _contraintsFields
358 NSMutableArray *fields;
359 NSEnumerator *values;
360 NSDictionary *currentConstraint;
362 fields = [NSMutableArray array];
363 values = [[modulesConstraints allValues] objectEnumerator];
364 while ((currentConstraint = [values nextObject]))
365 [fields addObjectsFromArray: [currentConstraint allKeys]];
370 - (NSArray *) _searchAttributes
372 if (!searchAttributes)
374 searchAttributes = [NSMutableArray new];
376 [searchAttributes addObject: CNField];
378 [searchAttributes addObject: UIDField];
379 [searchAttributes addObjectsFromArray: mailFields];
380 [searchAttributes addObjectsFromArray: [self _contraintsFields]];
381 [searchAttributes addObjectsFromArray: commonSearchFields];
384 return searchAttributes;
387 - (NSArray *) allEntryIDs
390 NSEnumerator *entries;
391 NGLdapEntry *currentEntry;
394 ids = [NSMutableArray array];
396 [self _initLDAPConnection];
397 entries = [ldapConnection deepSearchAtBaseDN: baseDN
399 attributes: [NSArray arrayWithObject: IDField]];
402 currentEntry = [entries nextObject];
405 value = [[currentEntry attributeWithName: IDField]
406 stringValueAtIndex: 0];
407 if ([value length] > 0)
408 [ids addObject: value];
409 currentEntry = [entries nextObject];
412 [ldapConnection release];
417 - (void) _fillEmailsOfEntry: (NGLdapEntry *) ldapEntry
418 intoContactEntry: (NSMutableDictionary *) contactEntry
420 NSEnumerator *emailFields;
421 NSString *currentFieldName, *value;
422 NSMutableArray *emails;
424 emails = [NSMutableArray new];
425 emailFields = [mailFields objectEnumerator];
426 while ((currentFieldName = [emailFields nextObject]))
428 value = [[ldapEntry attributeWithName: currentFieldName]
429 stringValueAtIndex: 0];
431 [emails addObject: value];
433 [emails autorelease];
434 [contactEntry setObject: emails forKey: @"c_emails"];
437 - (void) _fillConstraints: (NGLdapEntry *) ldapEntry
438 forModule: (NSString *) module
439 intoContactEntry: (NSMutableDictionary *) contactEntry
441 NSDictionary *constraints;
442 NSEnumerator *matches;
443 NSString *currentMatch, *currentValue, *ldapValue;
448 constraints = [modulesConstraints objectForKey: module];
451 matches = [[constraints allKeys] objectEnumerator];
452 currentMatch = [matches nextObject];
453 while (result && currentMatch)
455 ldapValue = [[ldapEntry attributeWithName: currentMatch]
456 stringValueAtIndex: 0];
457 currentValue = [constraints objectForKey: currentMatch];
458 if ([ldapValue isEqualToString: currentValue])
459 currentMatch = [matches nextObject];
465 [contactEntry setObject: [NSNumber numberWithBool: result]
466 forKey: [NSString stringWithFormat: @"%@Access", module]];
469 - (NSDictionary *) _convertLDAPEntryToContact: (NGLdapEntry *) ldapEntry
471 NSMutableDictionary *contactEntry;
472 NSEnumerator *attributes;
473 NSString *currentAttribute, *value;
475 contactEntry = [NSMutableDictionary dictionary];
476 attributes = [[self _searchAttributes] objectEnumerator];
477 currentAttribute = [attributes nextObject];
478 while (currentAttribute)
480 value = [[ldapEntry attributeWithName: currentAttribute]
481 stringValueAtIndex: 0];
483 [contactEntry setObject: value forKey: currentAttribute];
484 currentAttribute = [attributes nextObject];
486 value = [[ldapEntry attributeWithName: IDField] stringValueAtIndex: 0];
489 [contactEntry setObject: value forKey: @"c_name"];
490 value = [[ldapEntry attributeWithName: UIDField] stringValueAtIndex: 0];
493 [contactEntry setObject: value forKey: @"c_uid"];
494 value = [[ldapEntry attributeWithName: CNField] stringValueAtIndex: 0];
497 [contactEntry setObject: value forKey: @"c_cn"];
498 [self _fillEmailsOfEntry: ldapEntry intoContactEntry: contactEntry];
499 [self _fillConstraints: ldapEntry forModule: @"Calendar"
500 intoContactEntry: (NSMutableDictionary *) contactEntry];
501 [self _fillConstraints: ldapEntry forModule: @"Mail"
502 intoContactEntry: (NSMutableDictionary *) contactEntry];
507 - (NSArray *) fetchContactsMatching: (NSString *) match
509 NSMutableArray *contacts;
510 NGLdapEntry *currentEntry;
511 NSEnumerator *entries;
513 contacts = [NSMutableArray array];
515 if ([match length] > 0)
517 [self _initLDAPConnection];
518 entries = [ldapConnection deepSearchAtBaseDN: baseDN
519 qualifier: [self _qualifierForFilter: match]
520 attributes: [self _searchAttributes]];
523 currentEntry = [entries nextObject];
527 [self _convertLDAPEntryToContact: currentEntry]];
528 currentEntry = [entries nextObject];
531 [ldapConnection release];
537 - (NSDictionary *) lookupContactEntry: (NSString *) entryID;
539 NSDictionary *contactEntry;
540 NGLdapEntry *ldapEntry;
544 if ([entryID length] > 0)
546 [self _initLDAPConnection];
548 = [ldapConnection entryAtDN: [NSString stringWithFormat: @"%@=%@,%@",
549 IDField, entryID, baseDN]
550 attributes: [self _searchAttributes]];
552 contactEntry = [self _convertLDAPEntryToContact: ldapEntry];
553 [ldapConnection release];
559 - (NSDictionary *) lookupContactEntryWithUIDorEmail: (NSString *) uid;
561 NSDictionary *contactEntry;
562 NGLdapEntry *ldapEntry;
563 NSEnumerator *entries;
564 EOQualifier *qualifier;
568 if ([uid length] > 0)
570 [self _initLDAPConnection];
571 qualifier = [self _qualifierForUIDFilter: uid];
572 entries = [ldapConnection deepSearchAtBaseDN: baseDN
574 attributes: [self _searchAttributes]];
575 ldapEntry = [entries nextObject];
577 contactEntry = [self _convertLDAPEntryToContact: ldapEntry];
578 [ldapConnection release];
584 - (NSString *) sourceID