From: helge Date: Sun, 20 Feb 2005 22:53:09 +0000 (+0000) Subject: refactoring in the LDAP code of AgenorUserManager X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d8d399e67f3512578cc32704d4c0960a7c1ab482;p=scalable-opengroupware.org refactoring in the LDAP code of AgenorUserManager git-svn-id: http://svn.opengroupware.org/SOGo/trunk@591 d1b88da0-ebda-0310-925b-ed51d893ca5b --- diff --git a/OGoContentStore/NSURL+OCS.h b/OGoContentStore/NSURL+OCS.h index 1d0c204b..ca7319c7 100644 --- a/OGoContentStore/NSURL+OCS.h +++ b/OGoContentStore/NSURL+OCS.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2004 SKYRIX Software AG + Copyright (C) 2004-2005 SKYRIX Software AG This file is part of OpenGroupware.org. @@ -18,7 +18,6 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -// $Id$ #ifndef __OGoContentStore_NSURL_OCS_H__ #define __OGoContentStore_NSURL_OCS_H__ diff --git a/SOGo/SoObjects/Mailer/SOGoMailManager.m b/SOGo/SoObjects/Mailer/SOGoMailManager.m index cf7ddb58..03d44a7b 100644 --- a/SOGo/SoObjects/Mailer/SOGoMailManager.m +++ b/SOGo/SoObjects/Mailer/SOGoMailManager.m @@ -191,9 +191,13 @@ static NSString *imap4Separator = nil; result = [client login:[_url user] password:_pwd]; if (![[result valueForKey:@"result"] boolValue]) { [self errorWithFormat: - @"IMAP4 login failed (host=%@,user=%@,pwd=%s,url=%@/%@/%@): %@", + @"IMAP4 login failed:\n" + @" host=%@, user=%@, pwd=%s\n" + @" url=%@\n base=%@\n base-class=%@)\n" + " = %@", [_url host], [_url user], [_pwd length] > 0 ? "yes" : "no", - [_url absoluteString], [_url baseURL], + [_url absoluteString], + [_url baseURL], NSStringFromClass([[_url baseURL] class]), client]; return nil; diff --git a/SOGo/SoObjects/SOGo/AgenorUserManager.m b/SOGo/SoObjects/SOGo/AgenorUserManager.m index f44dfdea..7702a9d2 100644 --- a/SOGo/SoObjects/SOGo/AgenorUserManager.m +++ b/SOGo/SoObjects/SOGo/AgenorUserManager.m @@ -1,7 +1,7 @@ /* - Copyright (C) 2000-2004 SKYRIX Software AG + Copyright (C) 2004-2005 SKYRIX Software AG - This file is part of OGo + This file is part of OpenGroupware.org. OGo is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the @@ -18,8 +18,6 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -// $Id$ - #include "AgenorUserManager.h" #include @@ -47,28 +45,39 @@ static BOOL debugOn = NO; static BOOL useLDAP = NO; static NSString *ldapHost = nil; static NSString *ldapBaseDN = nil; +static NSString *fallbackIMAP4Server = nil; +static NSString *defaultMailDomain = @"equipement.gouv.fr"; + (void)initialize { static BOOL didInit = NO; NSUserDefaults *ud; - if(didInit) + if (didInit) return; didInit = YES; - ud = [NSUserDefaults standardUserDefaults]; + ud = [NSUserDefaults standardUserDefaults]; debugOn = [ud boolForKey:@"SOGoUserManagerDebugEnabled"]; + useLDAP = [ud boolForKey:@"SOGoUserManagerUsesLDAP"]; - if(useLDAP) { - ldapHost = [[ud stringForKey:@"SOGoLDAPHost"] retain]; - ldapBaseDN = [[ud stringForKey:@"SOGoLDAPBaseDN"] retain]; + if (useLDAP) { + ldapHost = [[ud stringForKey:@"SOGoLDAPHost"] copy]; + ldapBaseDN = [[ud stringForKey:@"SOGoLDAPBaseDN"] copy]; + NSLog(@"Note: using LDAP host to manage accounts: %@", ldapHost); } + else + NSLog(@"Note: LDAP access is disabled."); + + fallbackIMAP4Server = [[ud stringForKey:@"SOGoFallbackIMAP4Server"] copy]; + if ([fallbackIMAP4Server length] > 0) + NSLog(@"Note: using fallback IMAP4 server: '%@'", fallbackIMAP4Server); + else + fallbackIMAP4Server = nil; } + (id)sharedUserManager { - static id mgr = nil; - if(mgr == nil) { + static AgenorUserManager *mgr = nil; + if (mgr == nil) mgr = [[self alloc] init]; - } return mgr; } @@ -104,35 +113,36 @@ static NSString *ldapBaseDN = nil; /* private cache helpers */ +// TODO: this is really unnecessary, no? - (void)_cacheCN:(NSString *)_cn forUID:(NSString *)_uid { + if (_cn == nil) return; [self->cnCache addObject:_cn forKey:_uid]; } - - (NSString *)_cachedCNForUID:(NSString *)_uid { return [self->cnCache objectForKey:_uid]; } - (void)_cacheServer:(NSString *)_server forUID:(NSString *)_uid { + if (_server == nil) return; [self->serverCache addObject:_server forKey:_uid]; } - - (NSString *)_cachedServerForUID:(NSString *)_uid { return [self->serverCache objectForKey:_uid]; } - (void)_cacheEmail:(NSString *)_email forUID:(NSString *)_uid { + if (_email == nil) return; [self->emailCache addObject:_email forKey:_uid]; } - - (NSString *)_cachedEmailForUID:(NSString *)_uid { return [self->emailCache objectForKey:_uid]; } - (void)_cacheUID:(NSString *)_uid forEmail:(NSString *)_email { + if (_uid == nil) return; [self->uidCache addObject:_uid forKey:_email]; } - - (NSString *)_cachedUIDForEmail:(NSString *)_email { return [self->uidCache objectForKey:_email]; } @@ -167,8 +177,7 @@ static NSString *ldapBaseDN = nil; Only LDAP fetches would guarantee correctness in both cases. */ -- (NSString *)getUIDForEmail:(NSString *)_email { - if(useLDAP) { +- (NSString *)primaryGetAgenorUIDForEmail:(NSString *)_email { static NSArray *uidAttrs = nil; NGLdapConnection *conn; EOQualifier *q; @@ -181,9 +190,6 @@ static NSString *ldapBaseDN = nil; uidAttrs = [[NSArray alloc] initWithObjects:@"uid", nil]; } - if((uid = [self _cachedUIDForEmail:_email])) - return uid; - q = [EOQualifier qualifierWithQualifierFormat:@"mail = %@", _email]; conn = [self ldapConnection]; @@ -191,7 +197,7 @@ static NSString *ldapBaseDN = nil; qualifier:q attributes:uidAttrs]; entry = [resultEnum nextObject]; - if(!entry) { + if (entry == nil) { if(debugOn) { [self logWithFormat:@"%s Didn't find LDAP entry for email '%@'!", __PRETTY_FUNCTION__, @@ -203,8 +209,17 @@ static NSString *ldapBaseDN = nil; if (!uidAttr) return nil; /* can happen, not unlikely */ uid = [uidAttr stringValueAtIndex:0]; - [self _cacheUID:uid forEmail:_email]; return uid; +} + +- (NSString *)getUIDForEmail:(NSString *)_email { + NSString *uid; + + if ((uid = [self _cachedUIDForEmail:_email]) != nil) + return uid; + + if (useLDAP) { + uid = [self primaryGetAgenorUIDForEmail:_email]; } else { NSRange r; @@ -214,58 +229,56 @@ static NSString *ldapBaseDN = nil; return nil; r = [_email rangeOfString:@"@"]; - if(r.length == 0) + if (r.length == 0) return nil; + domain = [_email substringFromIndex:NSMaxRange(r)]; - if(![domain isEqualToString:@"equipement.gouv.fr"]) - return _email; - return [_email substringToIndex:r.location]; + if (![domain isEqualToString:defaultMailDomain]) + uid = _email; + else + uid = [_email substringToIndex:r.location]; } + + [self _cacheUID:uid forEmail:_email]; + return uid; } -- (NSString *)getEmailForUID:(NSString *)_uid { - if(useLDAP) { - static NSArray *emailAttrs = nil; - NGLdapConnection *conn; - EOQualifier *q; - NSEnumerator *resultEnum; - NGLdapEntry *entry; - NGLdapAttribute *emailAttr; - NSString *email; - - if(!emailAttrs) { - emailAttrs = [[NSArray alloc] initWithObjects:@"mineqMelmailEmission", nil]; - } +- (NSString *)primaryGetEmailForAgenorUID:(NSString *)_uid { + static NSArray *emailAttrs = nil; + NGLdapConnection *conn; + EOQualifier *q; + NSEnumerator *resultEnum; + NGLdapEntry *entry; + NGLdapAttribute *emailAttr; + NSString *email; + unsigned count; - if((email = [self _cachedEmailForUID:_uid])) - return email; + if (emailAttrs == nil) + emailAttrs = [[NSArray alloc] initWithObjects:@"mineqMelmailEmission",nil]; - q = [EOQualifier qualifierWithQualifierFormat:@"uid = %@", _uid]; + q = [EOQualifier qualifierWithQualifierFormat:@"uid = %@", _uid]; - conn = [self ldapConnection]; - resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN - qualifier:q - attributes:emailAttrs]; - entry = [resultEnum nextObject]; - if(!entry) { + conn = [self ldapConnection]; + resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN + qualifier:q + attributes:emailAttrs]; + entry = [resultEnum nextObject]; + if (entry == nil) { if(debugOn) { [self logWithFormat:@"%s Didn't find LDAP entry for uid '%@'!", __PRETTY_FUNCTION__, _uid]; } return nil; - } - emailAttr = [entry attributeWithName:@"mineqMelmailEmission"]; - if (!emailAttr) { - return nil; /* shit happens */ - } - else { - unsigned count; - - email = nil; - count = [emailAttr count]; + } + emailAttr = [entry attributeWithName:@"mineqMelmailEmission"]; + if (emailAttr == nil) + return nil; /* shit happens */ + + email = nil; + count = [emailAttr count]; #if 0 - if (count > 1) { + if (count > 1) { unsigned i; /* in case there are multiple email addresses, select the first @@ -274,77 +287,94 @@ static NSString *ldapBaseDN = nil; NSString *candidate; candidate = [emailAttr stringValueAtIndex:i]; - if (![candidate hasSuffix:@"@equipement.gouv.fr"]) { + if (![candidate hasSuffix:defaultMailDomain]) { + // TODO: also check for '@' email = candidate; break; } } - } + } #endif - if (email == nil && count > 0) { - email = [emailAttr stringValueAtIndex:0]; - } - [self _cacheEmail:email forUID:_uid]; - return email; - } + if (email == nil && count > 0) + email = [emailAttr stringValueAtIndex:0]; + + return email; +} + +- (NSString *)getEmailForUID:(NSString *)_uid { + NSString *email; + + if (![_uid isNotNull] || [_uid length] == 0) + return nil; + if ((email = [self _cachedEmailForUID:_uid]) != nil) + return email; + + if (useLDAP) { + email = [self primaryGetEmailForAgenorUID:_uid]; } else { NSRange r; - if(!_uid || [_uid length] == 0) - return nil; r = [_uid rangeOfString:@"@"]; - if(r.length > 0) - return _uid; - return [NSString stringWithFormat:@"%@@equipement.gouv.fr", _uid]; + email = (r.length > 0) + ? _uid + : [[_uid stringByAppendingString:@"@"] + stringByAppendingString:defaultMailDomain]; } + + [self _cacheEmail:email forUID:_uid]; + return email; } /* CN */ -- (NSString *)getCNForUID:(NSString *)_uid { - if(useLDAP) { - static NSArray *cnAttrs = nil; - NGLdapConnection *conn; - EOQualifier *q; - NSEnumerator *resultEnum; - NGLdapEntry *entry; - NGLdapAttribute *cnAttr; - NSString *cn; - - if(!cnAttrs) { - cnAttrs = [[NSArray alloc] initWithObjects:@"cn", nil]; - } - - if((cn = [self _cachedCNForUID:_uid])) - return cn; - - q = [EOQualifier qualifierWithQualifierFormat:@"uid = %@", _uid]; +- (NSString *)primaryGetCNForAgenorUID:(NSString *)_uid { + static NSArray *cnAttrs = nil; + NGLdapConnection *conn; + EOQualifier *q; + NSEnumerator *resultEnum; + NGLdapEntry *entry; + NGLdapAttribute *cnAttr; + NSString *cn; + + if (cnAttrs == nil) + cnAttrs = [[NSArray alloc] initWithObjects:@"cn", nil]; + + q = [EOQualifier qualifierWithQualifierFormat:@"uid = %@", _uid]; - conn = [self ldapConnection]; - resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN - qualifier:q - attributes:cnAttrs]; - entry = [resultEnum nextObject]; - if(!entry) { + conn = [self ldapConnection]; + resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN + qualifier:q + attributes:cnAttrs]; + entry = [resultEnum nextObject]; + if (entry == nil) { if(debugOn) { [self logWithFormat:@"%s Didn't find LDAP entry for uid '%@'!", __PRETTY_FUNCTION__, _uid]; } return nil; - } - cnAttr = [entry attributeWithName:@"cn"]; - if(!cnAttr && debugOn) { + } + cnAttr = [entry attributeWithName:@"cn"]; + if(cnAttr == nil && debugOn) { [self logWithFormat:@"%s LDAP entry for uid '%@' has no common name?", __PRETTY_FUNCTION__, _uid]; return nil; /* nothing we can do about it */ - } - cn = [cnAttr stringValueAtIndex:0]; - [self _cacheCN:cn forUID:_uid]; + } + cn = [cnAttr stringValueAtIndex:0]; + return cn; +} + +- (NSString *)getCNForUID:(NSString *)_uid { + NSString *cn; + + if ((cn = [self _cachedCNForUID:_uid]) != nil) return cn; + + if (useLDAP) { + cn = [self primaryGetCNForAgenorUID:_uid]; } else { NSString *s; @@ -357,10 +387,13 @@ static NSString *ldapBaseDN = nil; // TODO: algorithm might be inappropriate, depends on the actual UID r = [s rangeOfString:@"."]; if (r.length == 0) - return s; - - return [s substringToIndex:r.location]; + cn = s; + else + cn = [s substringToIndex:r.location]; } + + [self _cacheCN:cn forUID:_uid]; + return cn; } @@ -370,70 +403,47 @@ static NSString *ldapBaseDN = nil; NSString *server; server = [self getServerForUID:_uid]; - if(!server) + if (server == nil) return nil; return [NSString stringWithFormat:@"%@@%@", _uid, server]; } -- (NSString *)getServerForUID:(NSString *)_uid { - /* - First of all : for a particular user IMAP and SMTP are served on the same - host. - - The name of the machine is determined by applying a regex on every values of - the mineqMelRoutage LDAP attribute. - The regex is : .*%.*@(.*\.melanie2\.i2$) - It extracts the substring that follows '@', ends with 'melanie2', on - adresses which have a '%' before the '@' - - Example: helge.hesse%opengroupware.org@servername1.melanie2.i2 - -> servername1.melanie2.i2 - - If only one server name is found by applying the regex on every value of the - attribute, then this name is the IMAP/SMTP server for that user. - Note that this is the case when we got a unique (well formed) value for the - attribute. - If the regex finds more than one servername when applied to the differents - values, then the IMAP/SMTP server name is to be found in the - mineqMelServeurPrincipal attribute of the user. - */ - if(useLDAP) { - static NSArray *attrs = nil; - NGLdapConnection *conn; - EOQualifier *q; - NSEnumerator *resultEnum; - NGLdapEntry *entry; - NGLdapAttribute *attr; - NSMutableArray *serverCandidates; - NSString *server; - - if(!attrs) { - attrs = [[NSArray alloc] initWithObjects:@"mineqMelRoutage", - @"mineqMelServeurPrincipal", - nil]; - } - - if((server = [self _cachedServerForUID:_uid])) - return server; - - q = [EOQualifier qualifierWithQualifierFormat:@"uid = %@", _uid]; - - conn = [self ldapConnection]; - resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN - qualifier:q - attributes:attrs]; - /* we just expect one entry, thus drop the rest */ - entry = [resultEnum nextObject]; - if(!entry) { +- (NGLdapEntry *)_fetchEntryForAgenorUID:(NSString *)_uid { + static NSArray *attrs = nil; + NGLdapConnection *conn; + EOQualifier *q; + NSEnumerator *resultEnum; + NGLdapEntry *entry; + + if (attrs == nil) { + attrs = [[NSArray alloc] initWithObjects: + @"mineqMelRoutage", + @"mineqMelServeurPrincipal", + nil]; + } + + q = [EOQualifier qualifierWithQualifierFormat:@"uid = %@", _uid]; + + conn = [self ldapConnection]; + resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN + qualifier:q + attributes:attrs]; + /* we just expect one entry, thus drop the rest */ + entry = [resultEnum nextObject]; + if (entry == nil) { if(debugOn) { NSLog(@"%s Didn't find LDAP entry for uid '%@'!", __PRETTY_FUNCTION__, _uid); } return nil; - } - attr = [entry attributeWithName:@"mineqMelRoutage"]; - if(attr) { + } + return entry; +} + +- (NSArray *)_serverCandidatesForMineqMelRoutage:(NGLdapAttribute *)attr { + NSMutableArray *serverCandidates; + unsigned i, count; count = [attr count]; @@ -468,42 +478,101 @@ static NSString *ldapBaseDN = nil; } } } - } - else { - if(debugOn) { - NSLog(@"%s LDAP entry for uid '%@' has no mineqMelRoutage entry?", - __PRETTY_FUNCTION__, - _uid); - } - serverCandidates = nil; - } - if([serverCandidates count] == 1) { - server = [serverCandidates objectAtIndex:0]; - } + return serverCandidates; +} - /* last resort */ - if(!server) { +- (NSString *)primaryGetServerForAgenorUID:(NSString *)_uid { + /* + First of all : for a particular user IMAP and SMTP are served on the same + host. + + The name of the machine is determined by applying a regex on every values of + the mineqMelRoutage LDAP attribute. + The regex is : .*%.*@(.*\.melanie2\.i2$) + It extracts the substring that follows '@', ends with 'melanie2', on + adresses which have a '%' before the '@' + + Example: helge.hesse%opengroupware.org@servername1.melanie2.i2 + -> servername1.melanie2.i2 + + If only one server name is found by applying the regex on every value of the + attribute, then this name is the IMAP/SMTP server for that user. + Note that this is the case when we got a unique (well formed) value for the + attribute. + If the regex finds more than one servername when applied to the differents + values, then the IMAP/SMTP server name is to be found in the + mineqMelServeurPrincipal attribute of the user. + */ + NSString *server; + NGLdapEntry *entry; + NGLdapAttribute *attr; + + if ((entry = [self _fetchEntryForAgenorUID:_uid]) == nil) + return nil; + + attr = [entry attributeWithName:@"mineqMelRoutage"]; + if (attr != nil) { + NSArray *serverCandidates; + + serverCandidates = [self _serverCandidatesForMineqMelRoutage:attr]; + + if ([serverCandidates count] > 0) + server = [serverCandidates objectAtIndex:0]; + } + else { + [self debugWithFormat: + @"%s LDAP entry for uid '%@' has no mineqMelRoutage entry?", + __PRETTY_FUNCTION__, + _uid]; + } + + /* last resort */ + if (server == nil) { attr = [entry attributeWithName:@"mineqMelServeurPrincipal"]; - if([attr count] > 0) + if ([attr count] > 0) server = [attr stringValueAtIndex:0]; - } - - if(!server) { - if(debugOn) { - NSLog(@"%s no chance of getting at server info for user '%@', " + } + + if (server == nil) { + [self debugWithFormat: + @"%s no chance of getting at server info for user '%@', " @"tried everything. Sorry.", __PRETTY_FUNCTION__, - _uid); - } - return nil; - } + _uid]; + return nil; + } + return server; +} + +- (NSString *)getServerForUID:(NSString *)_uid { + NSString *server; - [self _cacheServer:server forUID:_uid]; + if (_uid == nil || [_uid length] == 0) + return nil; + + if ((server = [self _cachedServerForUID:_uid]) != nil) return server; - } + + if (useLDAP) + server = [self primaryGetServerForAgenorUID:_uid]; + else if (fallbackIMAP4Server) + server = fallbackIMAP4Server; else { - return @"mail.opengroupware.org"; + [self logWithFormat:@"ERROR: could not get server for uid '%@', " + @"neither LDAP (SOGoUserManagerUsesLDAP) nor " + @"a fallback (SOGoFallbackIMAP4Server) is configured.", + _uid]; + server = nil; } + + [self _cacheServer:server forUID:_uid]; + return server; } -@end +/* debugging */ + +- (BOOL)isDebuggingEnabled { + return debugOn; +} + +@end /* AgenorUserManager */ diff --git a/SOGo/SoObjects/SOGo/ChangeLog b/SOGo/SoObjects/SOGo/ChangeLog index ef68cad0..91b1668f 100644 --- a/SOGo/SoObjects/SOGo/ChangeLog +++ b/SOGo/SoObjects/SOGo/ChangeLog @@ -1,3 +1,9 @@ +2005-02-20 Helge Hess + + * AgenorUserManager.m: refactoring of the LDAP fetch code, added the + 'SOGoFallbackIMAP4Server' default to configure the IMAP4 server when + LDAP is disabled (v0.9.31) + 2005-02-17 Helge Hess * moved in code from libSOGoLogic (unnecessarily a separate library) diff --git a/SOGo/SoObjects/SOGo/Version b/SOGo/SoObjects/SOGo/Version index ddd701e9..b259838b 100644 --- a/SOGo/SoObjects/SOGo/Version +++ b/SOGo/SoObjects/SOGo/Version @@ -1,5 +1,5 @@ # version file -SUBMINOR_VERSION:=30 +SUBMINOR_VERSION:=31 # v0.9.26 requires libOGoContentStore v0.9.13