2009-09-25 16:42:33 +02:00
|
|
|
/* SOGoUserManager.m - this file is part of SOGo
|
2007-05-09 21:07:35 +02:00
|
|
|
*
|
2015-01-05 19:49:28 +01:00
|
|
|
* Copyright (C) 2007-2015 Inverse inc.
|
2007-05-09 21:07:35 +02:00
|
|
|
*
|
|
|
|
* This file is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This file is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; see the file COPYING. If not, write to
|
|
|
|
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
* Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
#import <Foundation/NSArray.h>
|
2015-03-04 02:59:32 +01:00
|
|
|
#import <Foundation/NSCalendarDate.h>
|
2007-05-09 21:07:35 +02:00
|
|
|
#import <Foundation/NSDictionary.h>
|
2008-07-04 18:06:09 +02:00
|
|
|
#import <Foundation/NSEnumerator.h>
|
2009-12-02 21:53:52 +01:00
|
|
|
#import <Foundation/NSException.h>
|
2008-12-12 19:55:12 +01:00
|
|
|
#import <Foundation/NSLock.h>
|
2012-10-06 20:51:26 +02:00
|
|
|
#import <Foundation/NSNull.h>
|
2007-05-09 21:07:35 +02:00
|
|
|
#import <Foundation/NSString.h>
|
|
|
|
#import <Foundation/NSTimer.h>
|
|
|
|
#import <Foundation/NSValue.h>
|
2011-06-24 21:19:50 +02:00
|
|
|
#import <NGExtensions/NSNull+misc.h>
|
2008-02-07 17:53:19 +01:00
|
|
|
#import <NGExtensions/NSObject+Logs.h>
|
2007-05-09 21:07:35 +02:00
|
|
|
|
2009-11-19 18:08:47 +01:00
|
|
|
#import "NSArray+Utilities.h"
|
2010-10-26 20:20:46 +02:00
|
|
|
#import "NSString+Utilities.h"
|
2012-05-31 15:24:32 +02:00
|
|
|
#import "NSString+Crypto.h"
|
2010-11-02 14:16:05 +01:00
|
|
|
#import "NSObject+Utilities.h"
|
2009-11-29 05:19:32 +01:00
|
|
|
#import "SOGoDomainDefaults.h"
|
2009-11-19 18:08:47 +01:00
|
|
|
#import "SOGoSource.h"
|
2009-11-29 05:19:32 +01:00
|
|
|
#import "SOGoSystemDefaults.h"
|
2009-11-19 18:08:47 +01:00
|
|
|
#import "SOGoUserManager.h"
|
|
|
|
#import "SOGoCache.h"
|
2010-03-08 16:18:05 +01:00
|
|
|
#import "SOGoConstants.h"
|
2009-11-19 18:08:47 +01:00
|
|
|
#import "SOGoSource.h"
|
2009-09-25 16:42:33 +02:00
|
|
|
|
2012-10-06 20:51:26 +02:00
|
|
|
static Class NSNullK;
|
|
|
|
|
2009-12-02 21:53:52 +01:00
|
|
|
@implementation SOGoUserManagerRegistry
|
|
|
|
|
2012-10-06 20:51:26 +02:00
|
|
|
+ (void) initialize
|
|
|
|
{
|
|
|
|
NSNullK = [NSNull class];
|
|
|
|
}
|
|
|
|
|
2009-12-02 21:53:52 +01:00
|
|
|
+ (id) sharedRegistry
|
|
|
|
{
|
|
|
|
static id sharedRegistry = nil;
|
|
|
|
|
|
|
|
if (!sharedRegistry)
|
|
|
|
sharedRegistry = [self new];
|
|
|
|
|
|
|
|
return sharedRegistry;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) sourceClassForType: (NSString *) type
|
|
|
|
{
|
|
|
|
NSString *sourceClass;
|
|
|
|
|
|
|
|
if (type)
|
|
|
|
{
|
2015-11-10 17:38:35 +01:00
|
|
|
if ([type caseInsensitiveCompare: @"ldap"] == NSOrderedSame)
|
2009-12-02 21:53:52 +01:00
|
|
|
sourceClass = @"LDAPSource";
|
2015-11-10 17:38:35 +01:00
|
|
|
else if ([type caseInsensitiveCompare: @"sql"] == NSOrderedSame)
|
2009-12-02 21:53:52 +01:00
|
|
|
sourceClass = @"SQLSource";
|
2015-11-10 17:38:35 +01:00
|
|
|
else if (NSClassFromString(type))
|
|
|
|
sourceClass = type;
|
2009-12-02 21:53:52 +01:00
|
|
|
else
|
2011-04-05 17:13:43 +02:00
|
|
|
{
|
|
|
|
[NSException raise: @"SOGoUserManagerRegistryException"
|
|
|
|
format: @"No class known for type '%@'", type];
|
|
|
|
sourceClass = nil;
|
|
|
|
}
|
2009-12-02 21:53:52 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
sourceClass = @"LDAPSource";
|
|
|
|
|
|
|
|
return sourceClass;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
2007-05-09 21:07:35 +02:00
|
|
|
|
2009-09-25 16:42:33 +02:00
|
|
|
@implementation SOGoUserManager
|
2007-05-09 21:07:35 +02:00
|
|
|
|
|
|
|
+ (id) sharedUserManager
|
|
|
|
{
|
|
|
|
static id sharedUserManager = nil;
|
|
|
|
|
|
|
|
if (!sharedUserManager)
|
|
|
|
sharedUserManager = [self new];
|
|
|
|
|
|
|
|
return sharedUserManager;
|
|
|
|
}
|
|
|
|
|
2012-01-12 21:01:34 +01:00
|
|
|
- (BOOL) _registerSource: (NSDictionary *) udSource
|
2009-11-29 05:19:32 +01:00
|
|
|
inDomain: (NSString *) domain
|
2007-05-09 21:07:35 +02:00
|
|
|
{
|
2009-09-25 16:42:33 +02:00
|
|
|
NSString *sourceID, *value, *type;
|
2007-05-09 21:07:35 +02:00
|
|
|
NSMutableDictionary *metadata;
|
2010-03-08 16:18:05 +01:00
|
|
|
NSObject <SOGoSource> *sogoSource;
|
2015-09-23 15:48:21 +02:00
|
|
|
BOOL isAddressBook;
|
2009-09-25 16:42:33 +02:00
|
|
|
Class c;
|
2009-11-29 05:19:32 +01:00
|
|
|
|
2007-05-09 21:07:35 +02:00
|
|
|
sourceID = [udSource objectForKey: @"id"];
|
2015-09-23 15:48:21 +02:00
|
|
|
if (!sourceID || [sourceID length] == 0)
|
2009-10-23 23:04:02 +02:00
|
|
|
{
|
2015-09-23 15:48:21 +02:00
|
|
|
[self errorWithFormat: @"attempted to register a contact/user source "
|
|
|
|
@"without id (skipped)"];
|
|
|
|
return NO;
|
2009-10-23 23:04:02 +02:00
|
|
|
}
|
2015-09-23 15:48:21 +02:00
|
|
|
if ([_sourcesMetadata objectForKey: sourceID])
|
|
|
|
{
|
|
|
|
[self errorWithFormat: @"attempted to register a contact/user source "
|
|
|
|
@"with duplicated id (%@)", sourceID];
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
2015-11-10 17:38:35 +01:00
|
|
|
type = [udSource objectForKey: @"type"];
|
2015-09-23 15:48:21 +02:00
|
|
|
c = NSClassFromString([_registry sourceClassForType: type]);
|
|
|
|
sogoSource = [c sourceFromUDSource: udSource inDomain: domain];
|
|
|
|
[_sources setObject: sogoSource forKey: sourceID];
|
2012-01-12 21:01:34 +01:00
|
|
|
|
2015-09-23 15:48:21 +02:00
|
|
|
metadata = [NSMutableDictionary dictionary];
|
|
|
|
if (domain)
|
|
|
|
[metadata setObject: domain forKey: @"domain"];
|
|
|
|
value = [udSource objectForKey: @"canAuthenticate"];
|
|
|
|
if (value)
|
|
|
|
[metadata setObject: value forKey: @"canAuthenticate"];
|
|
|
|
value = [udSource objectForKey: @"isAddressBook"];
|
|
|
|
if (value)
|
|
|
|
{
|
|
|
|
[metadata setObject: value forKey: @"isAddressBook"];
|
|
|
|
isAddressBook = [value boolValue];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
isAddressBook = NO;
|
|
|
|
value = [udSource objectForKey: @"displayName"];
|
|
|
|
if (value)
|
|
|
|
[metadata setObject: value forKey: @"displayName"];
|
|
|
|
else if (isAddressBook)
|
|
|
|
[self errorWithFormat: @"addressbook source '%@' has no displayname", sourceID];
|
|
|
|
|
|
|
|
value = [udSource objectForKey: @"MailFieldNames"];
|
|
|
|
if (value)
|
|
|
|
[metadata setObject: value forKey: @"MailFieldNames"];
|
|
|
|
value = [udSource objectForKey: @"SearchFieldNames"];
|
|
|
|
if (value)
|
|
|
|
[metadata setObject: value forKey: @"SearchFieldNames"];
|
|
|
|
|
|
|
|
[_sourcesMetadata setObject: metadata forKey: sourceID];
|
|
|
|
|
|
|
|
return YES;
|
2007-05-09 21:07:35 +02:00
|
|
|
}
|
|
|
|
|
2009-11-29 05:19:32 +01:00
|
|
|
- (int) _registerSourcesInDomain: (NSString *) domain
|
2007-05-09 21:07:35 +02:00
|
|
|
{
|
2009-11-29 05:19:32 +01:00
|
|
|
NSArray *userSources;
|
2012-01-12 21:01:34 +01:00
|
|
|
unsigned int count, max, total;
|
2009-11-29 05:19:32 +01:00
|
|
|
SOGoDomainDefaults *dd;
|
2007-05-09 21:07:35 +02:00
|
|
|
|
2015-09-23 15:48:21 +02:00
|
|
|
dd = [SOGoDomainDefaults defaultsForDomain: domain];
|
2009-11-29 05:19:32 +01:00
|
|
|
userSources = [dd userSources];
|
|
|
|
max = [userSources count];
|
2012-01-12 21:01:34 +01:00
|
|
|
total = 0;
|
2009-11-29 05:19:32 +01:00
|
|
|
for (count = 0; count < max; count++)
|
2012-01-12 21:01:34 +01:00
|
|
|
if ([self _registerSource: [userSources objectAtIndex: count]
|
|
|
|
inDomain: domain])
|
|
|
|
total++;
|
2009-09-25 16:42:33 +02:00
|
|
|
|
2012-01-12 21:01:34 +01:00
|
|
|
return total;
|
2009-11-29 05:19:32 +01:00
|
|
|
}
|
2007-05-09 21:07:35 +02:00
|
|
|
|
2009-11-29 05:19:32 +01:00
|
|
|
- (void) _prepareSources
|
|
|
|
{
|
|
|
|
NSArray *domains;
|
|
|
|
unsigned int count, max, total;
|
2009-09-25 16:42:33 +02:00
|
|
|
|
2009-11-29 05:19:32 +01:00
|
|
|
_sources = [[NSMutableDictionary alloc] init];
|
|
|
|
_sourcesMetadata = [[NSMutableDictionary alloc] init];
|
2009-09-25 16:42:33 +02:00
|
|
|
|
2009-11-29 05:19:32 +01:00
|
|
|
total = [self _registerSourcesInDomain: nil];
|
|
|
|
domains = [[SOGoSystemDefaults sharedSystemDefaults] domainIds];
|
|
|
|
max = [domains count];
|
|
|
|
for (count = 0; count < max; count++)
|
|
|
|
total += [self _registerSourcesInDomain: [domains objectAtIndex: count]];
|
|
|
|
|
|
|
|
if (!total)
|
|
|
|
[self errorWithFormat: @"No authentication sources defined - nobody will be able to login. Check your defaults."];
|
2007-05-09 21:07:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
- (id) init
|
|
|
|
{
|
|
|
|
if ((self = [super init]))
|
|
|
|
{
|
2009-09-25 16:42:33 +02:00
|
|
|
_sources = nil;
|
|
|
|
_sourcesMetadata = nil;
|
2009-12-02 21:53:52 +01:00
|
|
|
_registry = [NSClassFromString ([self registryClass]) sharedRegistry];
|
2009-11-29 05:19:32 +01:00
|
|
|
[self _prepareSources];
|
2007-05-09 21:07:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
{
|
2009-09-25 16:42:33 +02:00
|
|
|
[_sources release];
|
|
|
|
[_sourcesMetadata release];
|
2007-05-09 21:07:35 +02:00
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
2009-12-02 21:53:52 +01:00
|
|
|
- (NSString *) registryClass
|
|
|
|
{
|
|
|
|
return @"SOGoUserManagerRegistry";
|
|
|
|
}
|
|
|
|
|
2009-11-29 05:19:32 +01:00
|
|
|
- (NSArray *) sourceIDsInDomain: (NSString *) domain
|
2007-05-09 21:07:35 +02:00
|
|
|
{
|
2009-11-29 05:19:32 +01:00
|
|
|
NSMutableArray *sourceIDs;
|
|
|
|
NSArray *keys;
|
|
|
|
int count, max;
|
|
|
|
NSString *currentID, *sourceDomain;
|
|
|
|
NSObject <SOGoSource> *currentSource;
|
|
|
|
|
|
|
|
keys = [_sources allKeys];
|
|
|
|
max = [keys count];
|
|
|
|
sourceIDs = [NSMutableArray arrayWithCapacity: max];
|
|
|
|
for (count = 0; count < max; count++)
|
|
|
|
{
|
|
|
|
currentID = [keys objectAtIndex: count];
|
|
|
|
currentSource = [_sources objectForKey: currentID];
|
|
|
|
sourceDomain = [currentSource domain];
|
2009-11-29 22:48:00 +01:00
|
|
|
if (![sourceDomain length] || [sourceDomain isEqualToString: domain])
|
2009-11-29 05:19:32 +01:00
|
|
|
[sourceIDs addObject: currentID];
|
|
|
|
}
|
|
|
|
|
|
|
|
return sourceIDs;
|
2007-05-09 21:07:35 +02:00
|
|
|
}
|
|
|
|
|
2009-11-29 22:48:00 +01:00
|
|
|
- (NSObject <SOGoSource> *) sourceWithID: (NSString *) sourceID
|
|
|
|
{
|
|
|
|
return [_sources objectForKey: sourceID];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSDictionary *) metadataForSourceID: (NSString *) sourceID
|
|
|
|
{
|
|
|
|
return [_sourcesMetadata objectForKey: sourceID];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray *) authenticationSourceIDsInDomain: (NSString *) domain
|
2007-05-09 21:07:35 +02:00
|
|
|
{
|
|
|
|
NSMutableArray *sourceIDs;
|
|
|
|
NSEnumerator *allIDs;
|
2009-11-29 22:48:00 +01:00
|
|
|
NSString *currentID, *sourceDomain;
|
2009-11-29 05:19:32 +01:00
|
|
|
NSDictionary *metadata;
|
2007-05-09 21:07:35 +02:00
|
|
|
|
|
|
|
sourceIDs = [NSMutableArray array];
|
2009-09-25 16:42:33 +02:00
|
|
|
allIDs = [[_sources allKeys] objectEnumerator];
|
2009-11-29 05:19:32 +01:00
|
|
|
while ((currentID = [allIDs nextObject]))
|
2007-05-09 21:07:35 +02:00
|
|
|
{
|
2009-11-29 22:48:00 +01:00
|
|
|
sourceDomain = [[_sources objectForKey: currentID] domain];
|
2012-02-11 08:08:02 +01:00
|
|
|
if (![domain length] || ![sourceDomain length] || [domain isEqualToString: sourceDomain])
|
2009-11-29 05:19:32 +01:00
|
|
|
{
|
2009-11-29 22:48:00 +01:00
|
|
|
metadata = [_sourcesMetadata objectForKey: currentID];
|
|
|
|
if ([[metadata objectForKey: @"canAuthenticate"] boolValue])
|
2009-11-29 05:19:32 +01:00
|
|
|
[sourceIDs addObject: currentID];
|
|
|
|
}
|
2007-05-09 21:07:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return sourceIDs;
|
|
|
|
}
|
|
|
|
|
2009-11-29 22:48:00 +01:00
|
|
|
- (NSArray *) addressBookSourceIDsInDomain: (NSString *) domain
|
2007-05-09 21:07:35 +02:00
|
|
|
{
|
2009-11-29 22:48:00 +01:00
|
|
|
NSMutableArray *sourceIDs;
|
|
|
|
NSEnumerator *allIDs;
|
|
|
|
NSString *currentID;
|
|
|
|
NSDictionary *metadata;
|
2007-05-09 21:07:35 +02:00
|
|
|
|
2009-11-29 22:48:00 +01:00
|
|
|
sourceIDs = [NSMutableArray array];
|
|
|
|
allIDs = [[self sourceIDsInDomain: domain] objectEnumerator];
|
|
|
|
while ((currentID = [allIDs nextObject]))
|
|
|
|
{
|
|
|
|
metadata = [_sourcesMetadata objectForKey: currentID];
|
|
|
|
if ([[metadata objectForKey: @"isAddressBook"] boolValue])
|
|
|
|
[sourceIDs addObject: currentID];
|
|
|
|
}
|
2007-05-09 21:07:35 +02:00
|
|
|
|
2009-11-29 22:48:00 +01:00
|
|
|
return sourceIDs;
|
2007-05-09 21:07:35 +02:00
|
|
|
}
|
|
|
|
|
2015-09-23 15:36:39 +02:00
|
|
|
- (BOOL) isDomainDefined: (NSString *) domain
|
|
|
|
{
|
|
|
|
NSEnumerator *allIDs;
|
|
|
|
NSArray *ids;
|
|
|
|
NSString *currentID, *sourceDomain;
|
|
|
|
SOGoSystemDefaults *sd;
|
|
|
|
|
|
|
|
if (!domain) return NO;
|
|
|
|
|
|
|
|
ids = [_sources allKeys];
|
|
|
|
if ([ids containsObject: domain])
|
|
|
|
// FIXME check SOGoMailDomain?
|
|
|
|
// Now source id is being considered as the domain
|
|
|
|
return YES;
|
|
|
|
|
|
|
|
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
|
|
|
if ([sd enableDomainBasedUID])
|
|
|
|
{
|
|
|
|
allIDs = [ids objectEnumerator];
|
|
|
|
while ((currentID = [allIDs nextObject]))
|
|
|
|
{
|
|
|
|
sourceDomain = [[_sources objectForKey: currentID] domain];
|
|
|
|
if (!sourceDomain) // source that can identify any domain
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NO;
|
|
|
|
}
|
2007-05-09 21:07:35 +02:00
|
|
|
- (NSString *) displayNameForSourceWithID: (NSString *) sourceID
|
|
|
|
{
|
|
|
|
NSDictionary *metadata;
|
|
|
|
|
2009-09-25 16:42:33 +02:00
|
|
|
metadata = [_sourcesMetadata objectForKey: sourceID];
|
2007-05-09 21:07:35 +02:00
|
|
|
|
|
|
|
return [metadata objectForKey: @"displayName"];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) getCNForUID: (NSString *) uid
|
|
|
|
{
|
|
|
|
NSDictionary *contactInfos;
|
|
|
|
|
2007-05-10 16:59:13 +02:00
|
|
|
// NSLog (@"getCNForUID: %@", uid);
|
2007-05-09 21:07:35 +02:00
|
|
|
contactInfos = [self contactInfosForUserWithUIDorEmail: uid];
|
|
|
|
|
|
|
|
return [contactInfos objectForKey: @"cn"];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) getEmailForUID: (NSString *) uid
|
|
|
|
{
|
|
|
|
NSDictionary *contactInfos;
|
|
|
|
|
|
|
|
contactInfos = [self contactInfosForUserWithUIDorEmail: uid];
|
|
|
|
|
|
|
|
return [contactInfos objectForKey: @"c_email"];
|
|
|
|
}
|
|
|
|
|
2007-05-30 22:11:19 +02:00
|
|
|
- (NSString *) getFullEmailForUID: (NSString *) uid
|
|
|
|
{
|
|
|
|
NSDictionary *contactInfos;
|
2010-06-07 23:30:36 +02:00
|
|
|
NSString *cn, *email, *fullEmail;
|
2007-05-30 22:11:19 +02:00
|
|
|
|
|
|
|
contactInfos = [self contactInfosForUserWithUIDorEmail: uid];
|
2010-06-07 23:30:36 +02:00
|
|
|
email = [contactInfos objectForKey: @"c_email"];
|
|
|
|
cn = [contactInfos objectForKey: @"cn"];
|
|
|
|
if ([cn length] > 0)
|
|
|
|
{
|
|
|
|
if ([email length] > 0)
|
2015-09-23 15:48:21 +02:00
|
|
|
fullEmail = [NSString stringWithFormat: @"%@ <%@>", cn, email];
|
2010-06-07 23:30:36 +02:00
|
|
|
else
|
|
|
|
fullEmail = cn;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
fullEmail = email;
|
2007-05-30 22:11:19 +02:00
|
|
|
|
2010-06-07 23:30:36 +02:00
|
|
|
return fullEmail;
|
2007-05-30 22:11:19 +02:00
|
|
|
}
|
|
|
|
|
2013-01-11 15:55:10 +01:00
|
|
|
- (NSString *) getExternalLoginForUID: (NSString *) uid
|
|
|
|
inDomain: (NSString *) domain
|
2008-05-22 17:52:25 +02:00
|
|
|
{
|
2009-11-29 05:19:32 +01:00
|
|
|
NSDictionary *contactInfos;
|
2011-06-24 21:19:50 +02:00
|
|
|
NSString *login;
|
2009-11-29 05:19:32 +01:00
|
|
|
SOGoDomainDefaults *dd;
|
2015-05-20 12:30:05 +02:00
|
|
|
SOGoSystemDefaults *sd;
|
2009-11-29 05:19:32 +01:00
|
|
|
|
2011-06-24 21:19:50 +02:00
|
|
|
contactInfos = [self contactInfosForUserWithUIDorEmail: uid
|
|
|
|
inDomain: domain];
|
2011-04-14 20:41:10 +02:00
|
|
|
login = [contactInfos objectForKey: @"c_imaplogin"];
|
|
|
|
if (login == nil)
|
|
|
|
{
|
2015-09-23 15:48:21 +02:00
|
|
|
dd = [SOGoDomainDefaults defaultsForDomain: domain];
|
2015-05-20 12:30:05 +02:00
|
|
|
if ([dd forceExternalLoginWithEmail])
|
|
|
|
{
|
|
|
|
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
2016-05-06 19:47:35 +02:00
|
|
|
if ([sd enableDomainBasedUID] &&
|
2016-05-09 21:09:48 +02:00
|
|
|
[uid rangeOfString: @"@"].location == NSNotFound)
|
2016-05-06 19:47:35 +02:00
|
|
|
{
|
|
|
|
// On multidomain environment we must use uid@domain
|
|
|
|
// for getEmailForUID method
|
|
|
|
login = [NSString stringWithFormat: @"%@@%@", uid, domain];
|
|
|
|
}
|
2015-05-20 12:30:05 +02:00
|
|
|
else
|
|
|
|
login = uid;
|
2016-05-06 19:47:35 +02:00
|
|
|
|
2015-05-20 12:30:05 +02:00
|
|
|
login = [self getEmailForUID: login];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
login = uid;
|
2011-04-14 20:41:10 +02:00
|
|
|
}
|
2015-05-20 12:30:05 +02:00
|
|
|
|
2011-04-14 20:41:10 +02:00
|
|
|
return login;
|
2008-05-22 17:52:25 +02:00
|
|
|
}
|
|
|
|
|
2007-05-09 21:07:35 +02:00
|
|
|
- (NSString *) getUIDForEmail: (NSString *) email
|
|
|
|
{
|
2015-07-29 16:35:20 +02:00
|
|
|
NSDictionary *info;
|
|
|
|
SOGoSystemDefaults *sd;
|
2016-04-12 19:17:04 +02:00
|
|
|
NSString *uid, *domain, *suffix;
|
2015-07-29 16:35:20 +02:00
|
|
|
|
|
|
|
info = [self contactInfosForUserWithUIDorEmail: email];
|
|
|
|
uid = [info objectForKey: @"c_uid"];
|
2007-05-09 21:07:35 +02:00
|
|
|
|
2015-07-29 16:35:20 +02:00
|
|
|
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
|
|
|
if ([sd enableDomainBasedUID]
|
|
|
|
&& ![[info objectForKey: @"DomainLessLogin"] boolValue])
|
|
|
|
{
|
|
|
|
domain = [info objectForKey: @"c_domain"];
|
2016-04-12 19:17:04 +02:00
|
|
|
suffix = [NSString stringWithFormat: @"@%@", domain];
|
|
|
|
|
|
|
|
// Don't add @domain suffix if it's already there
|
|
|
|
if (![uid hasSuffix: suffix])
|
|
|
|
uid = [NSString stringWithFormat: @"%@%@", uid, suffix];
|
2015-07-29 16:35:20 +02:00
|
|
|
}
|
2007-05-09 21:07:35 +02:00
|
|
|
|
2015-07-29 16:35:20 +02:00
|
|
|
return uid;
|
2007-05-09 21:07:35 +02:00
|
|
|
}
|
|
|
|
|
2010-03-08 16:18:05 +01:00
|
|
|
- (BOOL) _sourceChangePasswordForLogin: (NSString *) login
|
2011-06-24 21:19:50 +02:00
|
|
|
inDomain: (NSString *) domain
|
2010-03-08 16:18:05 +01:00
|
|
|
oldPassword: (NSString *) oldPassword
|
2015-09-23 15:48:21 +02:00
|
|
|
newPassword: (NSString *) newPassword
|
|
|
|
perr: (SOGoPasswordPolicyError *) perr
|
2010-03-08 16:18:05 +01:00
|
|
|
{
|
|
|
|
NSObject <SOGoSource> *sogoSource;
|
|
|
|
NSEnumerator *authIDs;
|
|
|
|
NSString *currentID;
|
|
|
|
BOOL didChange;
|
2015-09-23 15:48:21 +02:00
|
|
|
|
2010-03-08 16:18:05 +01:00
|
|
|
didChange = NO;
|
2015-09-23 15:48:21 +02:00
|
|
|
|
2011-06-24 21:19:50 +02:00
|
|
|
authIDs = [[self authenticationSourceIDsInDomain: domain] objectEnumerator];
|
2010-03-08 16:18:05 +01:00
|
|
|
while (!didChange && (currentID = [authIDs nextObject]))
|
|
|
|
{
|
|
|
|
sogoSource = [_sources objectForKey: currentID];
|
|
|
|
didChange = [sogoSource changePasswordForLogin: login
|
2011-06-24 21:19:50 +02:00
|
|
|
oldPassword: oldPassword
|
|
|
|
newPassword: newPassword
|
|
|
|
perr: perr];
|
2010-03-08 16:18:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return didChange;
|
|
|
|
}
|
|
|
|
|
2009-09-25 16:42:33 +02:00
|
|
|
- (BOOL) _sourceCheckLogin: (NSString *) login
|
|
|
|
andPassword: (NSString *) password
|
2011-07-16 00:22:11 +02:00
|
|
|
domain: (NSString **) domain
|
2011-06-24 21:19:50 +02:00
|
|
|
perr: (SOGoPasswordPolicyError *) perr
|
|
|
|
expire: (int *) expire
|
|
|
|
grace: (int *) grace
|
2010-03-08 16:18:05 +01:00
|
|
|
{
|
|
|
|
NSObject <SOGoSource> *sogoSource;
|
2007-05-09 21:07:35 +02:00
|
|
|
NSEnumerator *authIDs;
|
|
|
|
NSString *currentID;
|
2009-09-25 16:42:33 +02:00
|
|
|
BOOL checkOK;
|
2015-05-20 18:32:44 +02:00
|
|
|
|
2007-05-09 21:07:35 +02:00
|
|
|
checkOK = NO;
|
2015-05-20 18:32:44 +02:00
|
|
|
|
2011-07-16 00:22:11 +02:00
|
|
|
authIDs = [[self authenticationSourceIDsInDomain: *domain] objectEnumerator];
|
2008-05-22 17:52:25 +02:00
|
|
|
while (!checkOK && (currentID = [authIDs nextObject]))
|
2007-05-09 21:07:35 +02:00
|
|
|
{
|
2010-03-08 16:18:05 +01:00
|
|
|
sogoSource = [_sources objectForKey: currentID];
|
2015-07-07 14:25:17 +02:00
|
|
|
|
2010-03-08 16:18:05 +01:00
|
|
|
checkOK = [sogoSource checkLogin: login
|
2011-07-16 00:22:11 +02:00
|
|
|
password: password
|
|
|
|
perr: perr
|
|
|
|
expire: expire
|
|
|
|
grace: grace];
|
2007-05-09 21:07:35 +02:00
|
|
|
}
|
|
|
|
|
2011-07-16 00:22:11 +02:00
|
|
|
if (checkOK && *domain == nil)
|
2015-09-23 15:49:53 +02:00
|
|
|
{
|
|
|
|
SOGoSystemDefaults *sd = [SOGoSystemDefaults sharedSystemDefaults];
|
|
|
|
BOOL multidomainSource = [sd enableDomainBasedUID] &&
|
|
|
|
[sogoSource domain] == nil;
|
|
|
|
if (multidomainSource)
|
|
|
|
{
|
|
|
|
NSArray *parts = [login componentsSeparatedByString: @"@"];
|
|
|
|
if ([parts count] != 2)
|
|
|
|
{
|
|
|
|
[self errorWithFormat: @"Authenticated with multidomain source "
|
|
|
|
@"but login is not an email (%@).", login];
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
*domain = [parts objectAtIndex: 1];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*domain = [sogoSource domain];
|
|
|
|
}
|
2011-07-16 00:22:11 +02:00
|
|
|
|
2007-05-09 21:07:35 +02:00
|
|
|
return checkOK;
|
|
|
|
}
|
|
|
|
|
2013-06-11 15:41:17 +02:00
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
2010-03-08 16:18:05 +01:00
|
|
|
- (BOOL) checkLogin: (NSString *) _login
|
2013-02-02 00:35:10 +01:00
|
|
|
password: (NSString *) _pwd
|
2011-07-16 00:22:11 +02:00
|
|
|
domain: (NSString **) _domain
|
2013-02-02 00:35:10 +01:00
|
|
|
perr: (SOGoPasswordPolicyError *) _perr
|
|
|
|
expire: (int *) _expire
|
|
|
|
grace: (int *) _grace
|
|
|
|
{
|
|
|
|
return [self checkLogin: _login
|
|
|
|
password: _pwd
|
|
|
|
domain: _domain
|
|
|
|
perr: _perr
|
|
|
|
expire: _expire
|
|
|
|
grace: _grace
|
|
|
|
useCache: YES];
|
|
|
|
}
|
|
|
|
|
2013-06-11 15:41:17 +02:00
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
2013-02-02 00:35:10 +01:00
|
|
|
- (BOOL) checkLogin: (NSString *) _login
|
|
|
|
password: (NSString *) _pwd
|
|
|
|
domain: (NSString **) _domain
|
|
|
|
perr: (SOGoPasswordPolicyError *) _perr
|
|
|
|
expire: (int *) _expire
|
|
|
|
grace: (int *) _grace
|
|
|
|
useCache: (BOOL) useCache
|
2007-05-09 21:07:35 +02:00
|
|
|
{
|
2015-05-20 15:24:00 +02:00
|
|
|
NSMutableDictionary *currentUser;
|
|
|
|
NSDictionary *failedCount;
|
2011-06-24 21:19:50 +02:00
|
|
|
NSString *dictPassword, *username, *jsonUser;
|
2015-08-03 09:48:06 +02:00
|
|
|
SOGoSystemDefaults *sd;
|
2009-02-24 02:54:59 +01:00
|
|
|
BOOL checkOK;
|
2015-05-20 12:31:25 +02:00
|
|
|
|
2016-04-11 16:18:09 +02:00
|
|
|
if (!_login)
|
|
|
|
return NO;
|
|
|
|
|
2015-08-03 09:48:06 +02:00
|
|
|
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
2015-05-06 22:03:33 +02:00
|
|
|
|
2015-05-22 19:47:48 +02:00
|
|
|
username = _login;
|
|
|
|
|
2015-05-20 12:31:25 +02:00
|
|
|
if (*_domain)
|
|
|
|
{
|
|
|
|
if ([_login rangeOfString: @"@"].location == NSNotFound)
|
|
|
|
username = [NSString stringWithFormat: @"%@@%@", _login, *_domain];
|
|
|
|
}
|
2011-06-24 21:19:50 +02:00
|
|
|
else
|
2015-05-06 22:03:33 +02:00
|
|
|
{
|
|
|
|
NSRange r;
|
|
|
|
|
|
|
|
// We try to extract the domain in use in order to avoid pounding all the authentication
|
|
|
|
// sources if SOGoLoginDomains isn't specified. This is also true if the user is
|
|
|
|
// using DAV or EAS.
|
|
|
|
r = [username rangeOfString: @"@"];
|
|
|
|
|
|
|
|
if (r.location != NSNotFound)
|
|
|
|
{
|
|
|
|
*_domain = [username substringFromIndex: r.location+1];
|
|
|
|
|
2015-08-03 09:48:06 +02:00
|
|
|
if (![[[SOGoSystemDefaults sharedSystemDefaults] domainIds] containsObject: *_domain])
|
2015-05-06 22:03:33 +02:00
|
|
|
*_domain = nil;
|
|
|
|
}
|
|
|
|
}
|
2013-06-11 15:41:17 +02:00
|
|
|
|
|
|
|
// We check the fail count per user in memcache (per server). If the
|
|
|
|
// fail count reaches X in Y minutes, we deny immediately the
|
|
|
|
// authentications for Z minutes
|
2015-05-20 12:31:25 +02:00
|
|
|
failedCount = [[SOGoCache sharedCache] failedCountForLogin: username];
|
2013-06-11 15:41:17 +02:00
|
|
|
if (failedCount)
|
|
|
|
{
|
|
|
|
unsigned int current_time, start_time, delta, block_time;
|
|
|
|
|
|
|
|
current_time = [[NSCalendarDate date] timeIntervalSince1970];
|
|
|
|
start_time = [[failedCount objectForKey: @"InitialDate"] unsignedIntValue];
|
|
|
|
delta = current_time - start_time;
|
|
|
|
|
2015-08-03 09:48:06 +02:00
|
|
|
block_time = [sd failedLoginBlockInterval];
|
2015-09-23 15:48:21 +02:00
|
|
|
|
2015-08-03 09:48:06 +02:00
|
|
|
if ([[failedCount objectForKey: @"FailedCount"] intValue] >= [sd maximumFailedLoginCount] &&
|
|
|
|
delta >= [sd maximumFailedLoginInterval] &&
|
2013-06-11 15:41:17 +02:00
|
|
|
delta <= block_time )
|
|
|
|
{
|
|
|
|
*_perr = PolicyAccountLocked;
|
|
|
|
return NO;
|
|
|
|
}
|
2015-09-23 15:48:21 +02:00
|
|
|
|
2013-06-11 15:41:17 +02:00
|
|
|
if (delta > block_time)
|
|
|
|
{
|
|
|
|
[[SOGoCache sharedCache] setFailedCount: 0
|
|
|
|
forLogin: username];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-20 12:31:25 +02:00
|
|
|
// We check for cached passwords. If the entry is cached, we
|
|
|
|
// check this immediately. If not, we'll go directly at the
|
|
|
|
// authentication source and try to validate there, then cache it.
|
2011-06-24 21:19:50 +02:00
|
|
|
jsonUser = [[SOGoCache sharedCache] userAttributesForLogin: username];
|
2010-10-26 20:20:46 +02:00
|
|
|
currentUser = [jsonUser objectFromJSONString];
|
2015-08-03 09:48:06 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// If we are using multidomain and the UIDFieldName is not part of the email address
|
|
|
|
// we must bind without the domain part since internally, SOGo will use
|
|
|
|
// UIDFieldName @ domain as its unique identifier if the UIDFieldName is used to
|
|
|
|
// authenticate. This can happen for example of one has in LDAP:
|
|
|
|
//
|
|
|
|
// dn: uid=foo,dc=example,dc=com
|
|
|
|
// uid: foo
|
|
|
|
// mail: broccoli@example.com
|
|
|
|
//
|
|
|
|
// and authenticates with "foo", using bindFields = (uid, mail) and SOGoEnableDomainBasedUID = YES;
|
|
|
|
// Otherwise, -_sourceCheckLogin:... would have failed because SOGo would try to bind using: foo@example.com
|
|
|
|
//
|
|
|
|
if ([[currentUser objectForKey: @"DomainLessLogin"] boolValue])
|
|
|
|
{
|
|
|
|
NSRange r;
|
|
|
|
|
|
|
|
r = [_login rangeOfString: [NSString stringWithFormat: @"@%@", *_domain]];
|
|
|
|
_login = [_login substringToIndex: r.location];
|
|
|
|
}
|
|
|
|
|
2007-05-09 21:07:35 +02:00
|
|
|
dictPassword = [currentUser objectForKey: @"password"];
|
2013-02-02 00:35:10 +01:00
|
|
|
if (useCache && currentUser && dictPassword)
|
2010-12-29 14:01:16 +01:00
|
|
|
{
|
|
|
|
checkOK = ([dictPassword isEqualToString: [_pwd asSHA1String]]);
|
|
|
|
//NSLog(@"Password cache hit for user %@", _login);
|
|
|
|
}
|
2010-03-08 16:18:05 +01:00
|
|
|
else if ([self _sourceCheckLogin: _login
|
2011-06-24 21:19:50 +02:00
|
|
|
andPassword: _pwd
|
|
|
|
domain: _domain
|
|
|
|
perr: _perr
|
|
|
|
expire: _expire
|
|
|
|
grace: _grace])
|
2007-05-09 21:07:35 +02:00
|
|
|
{
|
|
|
|
checkOK = YES;
|
|
|
|
if (!currentUser)
|
2013-02-02 00:35:10 +01:00
|
|
|
{
|
|
|
|
currentUser = [NSMutableDictionary dictionary];
|
|
|
|
}
|
2009-08-10 18:23:21 +02:00
|
|
|
|
2015-08-03 09:48:06 +02:00
|
|
|
// Before caching user attributes, we must check if SOGoEnableDomainBasedUID is enabled
|
|
|
|
// but we don't have a domain. That would happen for example if the user authenticates
|
|
|
|
// without the domain part. We must also cache that information, since SOGo will try
|
|
|
|
// afterward to bind with UIDFieldName@domain, and it could potentially not exist
|
|
|
|
// in the authentication source. See the rationale in _sourceCheckLogin: ...
|
|
|
|
if ([sd enableDomainBasedUID] &&
|
|
|
|
[username rangeOfString: @"@"].location == NSNotFound)
|
|
|
|
{
|
|
|
|
username = [NSString stringWithFormat: @"%@@%@", username, *_domain];
|
|
|
|
[currentUser setObject: [NSNumber numberWithBool: YES] forKey: @"DomainLessLogin"];
|
|
|
|
}
|
|
|
|
|
2009-11-19 18:08:47 +01:00
|
|
|
// It's important to cache the password here as we might have cached the
|
|
|
|
// user's entry in -contactInfosForUserWithUIDorEmail: and if we don't
|
|
|
|
// set the password and recache the entry, the password would never be
|
|
|
|
// cached for the user unless its entry expires from memcached's
|
|
|
|
// internal cache.
|
2010-12-29 14:01:16 +01:00
|
|
|
[currentUser setObject: [_pwd asSHA1String] forKey: @"password"];
|
2009-11-19 18:08:47 +01:00
|
|
|
[[SOGoCache sharedCache]
|
2010-11-02 14:16:05 +01:00
|
|
|
setUserAttributes: [currentUser jsonRepresentation]
|
2011-06-24 21:19:50 +02:00
|
|
|
forLogin: username];
|
2007-05-09 21:07:35 +02:00
|
|
|
}
|
2010-11-15 20:48:55 +01:00
|
|
|
else
|
2013-06-11 15:41:17 +02:00
|
|
|
{
|
|
|
|
// If failed login "rate-limiting" is enabled, we adjust the stats
|
2015-08-03 09:48:06 +02:00
|
|
|
if ([sd maximumFailedLoginCount])
|
2013-06-11 15:41:17 +02:00
|
|
|
{
|
|
|
|
[[SOGoCache sharedCache] setFailedCount: ([[failedCount objectForKey: @"FailedCount"] intValue] + 1)
|
|
|
|
forLogin: username];
|
|
|
|
}
|
2015-09-23 15:48:21 +02:00
|
|
|
|
2013-06-11 15:41:17 +02:00
|
|
|
checkOK = NO;
|
|
|
|
}
|
2007-05-09 21:07:35 +02:00
|
|
|
|
2010-12-14 19:08:36 +01:00
|
|
|
// We MUST, for all LDAP sources, update the bindDN and bindPassword
|
|
|
|
// to the user's value if bindAsCurrentUser is set to true in the
|
|
|
|
// LDAP source configuration
|
|
|
|
if (checkOK)
|
|
|
|
{
|
|
|
|
NSObject <SOGoDNSource> *currentSource;
|
|
|
|
NSEnumerator *sources;
|
2015-09-23 15:48:21 +02:00
|
|
|
|
2010-12-14 19:08:36 +01:00
|
|
|
sources = [[_sources allValues] objectEnumerator];
|
|
|
|
while ((currentSource = [sources nextObject]))
|
2011-06-24 21:19:50 +02:00
|
|
|
if ([currentSource conformsToProtocol: @protocol(SOGoDNSource)] &&
|
|
|
|
[currentSource bindAsCurrentUser] &&
|
|
|
|
[currentSource lookupDNByLogin: _login])
|
|
|
|
{
|
|
|
|
[currentSource setBindDN: [currentSource lookupDNByLogin: _login]];
|
|
|
|
[currentSource setBindPassword: _pwd];
|
|
|
|
}
|
2010-12-14 19:08:36 +01:00
|
|
|
}
|
2015-06-18 18:19:02 +02:00
|
|
|
|
2007-05-09 21:07:35 +02:00
|
|
|
return checkOK;
|
|
|
|
}
|
|
|
|
|
2013-06-11 15:41:17 +02:00
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
2010-03-08 16:18:05 +01:00
|
|
|
- (BOOL) changePasswordForLogin: (NSString *) login
|
2011-06-24 21:19:50 +02:00
|
|
|
inDomain: (NSString *) domain
|
2015-09-23 15:48:21 +02:00
|
|
|
oldPassword: (NSString *) oldPassword
|
|
|
|
newPassword: (NSString *) newPassword
|
|
|
|
perr: (SOGoPasswordPolicyError *) perr
|
2010-03-08 16:18:05 +01:00
|
|
|
{
|
2015-02-25 12:01:31 +01:00
|
|
|
NSString *jsonUser, *userLogin;
|
2010-03-08 16:18:05 +01:00
|
|
|
NSMutableDictionary *currentUser;
|
|
|
|
BOOL didChange;
|
2015-02-25 12:01:31 +01:00
|
|
|
SOGoSystemDefaults *sd;
|
|
|
|
|
2010-03-08 16:18:05 +01:00
|
|
|
jsonUser = [[SOGoCache sharedCache] userAttributesForLogin: login];
|
2010-10-26 20:20:46 +02:00
|
|
|
currentUser = [jsonUser objectFromJSONString];
|
2010-03-08 16:18:05 +01:00
|
|
|
|
|
|
|
if ([self _sourceChangePasswordForLogin: login
|
2011-06-24 21:19:50 +02:00
|
|
|
inDomain: domain
|
|
|
|
oldPassword: oldPassword
|
|
|
|
newPassword: newPassword
|
|
|
|
perr: perr])
|
2010-03-08 16:18:05 +01:00
|
|
|
{
|
|
|
|
didChange = YES;
|
|
|
|
|
|
|
|
if (!currentUser)
|
2015-02-25 12:01:31 +01:00
|
|
|
currentUser = [NSMutableDictionary dictionary];
|
2010-03-08 16:18:05 +01:00
|
|
|
|
|
|
|
// It's important to cache the password here as we might have cached the
|
|
|
|
// user's entry in -contactInfosForUserWithUIDorEmail: and if we don't
|
|
|
|
// set the password and recache the entry, the password would never be
|
|
|
|
// cached for the user unless its entry expires from memcached's
|
|
|
|
// internal cache.
|
2010-12-29 14:01:16 +01:00
|
|
|
[currentUser setObject: [newPassword asSHA1String] forKey: @"password"];
|
2015-02-25 12:01:31 +01:00
|
|
|
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
2015-05-19 19:48:59 +02:00
|
|
|
if ([sd enableDomainBasedUID] &&
|
|
|
|
[login rangeOfString: @"@"].location == NSNotFound)
|
2015-02-25 12:01:31 +01:00
|
|
|
userLogin = [NSString stringWithFormat: @"%@@%@", login, domain];
|
|
|
|
else
|
|
|
|
userLogin = login;
|
|
|
|
[[SOGoCache sharedCache] setUserAttributes: [currentUser jsonRepresentation]
|
|
|
|
forLogin: userLogin];
|
2010-03-08 16:18:05 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
didChange = NO;
|
|
|
|
|
|
|
|
return didChange;
|
|
|
|
}
|
|
|
|
|
2007-05-09 21:07:35 +02:00
|
|
|
- (void) _fillContactMailRecords: (NSMutableDictionary *) contact
|
|
|
|
{
|
2009-11-29 05:19:32 +01:00
|
|
|
NSString *uid, *domain, *systemEmail;
|
2009-09-25 16:42:33 +02:00
|
|
|
NSMutableArray *emails;
|
2009-11-29 05:19:32 +01:00
|
|
|
SOGoDomainDefaults *dd;
|
2007-05-09 21:07:35 +02:00
|
|
|
|
2009-11-29 05:19:32 +01:00
|
|
|
domain = [contact objectForKey: @"c_domain"];
|
2015-09-23 15:52:41 +02:00
|
|
|
dd = [SOGoDomainDefaults defaultsForDomain: domain];
|
2007-05-09 21:07:35 +02:00
|
|
|
emails = [contact objectForKey: @"emails"];
|
2015-09-23 15:52:41 +02:00
|
|
|
if ([emails count] == 0)
|
|
|
|
{
|
|
|
|
uid = [contact objectForKey: @"c_uid"];
|
|
|
|
if ([uid rangeOfString: @"@"].location == NSNotFound)
|
|
|
|
systemEmail = [NSString stringWithFormat: @"%@@%@", uid, [dd mailDomain]];
|
|
|
|
else
|
|
|
|
systemEmail = uid;
|
|
|
|
// We always add the system email, which will always be returned
|
|
|
|
// by SOGoUser -systemEmail.
|
|
|
|
[emails addObject: systemEmail];
|
|
|
|
}
|
2007-05-09 21:07:35 +02:00
|
|
|
[contact setObject: [emails objectAtIndex: 0] forKey: @"c_email"];
|
|
|
|
}
|
|
|
|
|
2011-04-25 12:31:08 +02:00
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
2015-08-03 09:48:06 +02:00
|
|
|
- (void) _fillContactInfosForUser: (NSMutableDictionary *) theCurrentUser
|
|
|
|
withUIDorEmail: (NSString *) theUID
|
|
|
|
inDomain: (NSString *) theDomain
|
2007-05-09 21:07:35 +02:00
|
|
|
{
|
2012-12-03 22:42:56 +01:00
|
|
|
NSString *sourceID, *cn, *c_domain, *c_uid, *c_imaphostname, *c_imaplogin, *c_sievehostname;
|
2012-04-18 19:39:11 +02:00
|
|
|
NSObject <SOGoSource> *currentSource;
|
|
|
|
NSEnumerator *sogoSources;
|
|
|
|
NSDictionary *userEntry;
|
|
|
|
NSMutableArray *emails;
|
|
|
|
NSNumber *isGroup;
|
2007-11-18 11:16:25 +01:00
|
|
|
NSArray *c_emails;
|
2007-11-26 21:41:59 +01:00
|
|
|
BOOL access;
|
2015-06-18 18:19:02 +02:00
|
|
|
NSEnumerator *enumerator;
|
|
|
|
NSString *access_type;
|
|
|
|
NSArray *access_types_list = [NSArray arrayWithObjects: @"CalendarAccess",
|
|
|
|
@"MailAccess",
|
|
|
|
@"ActiveSyncAccess",
|
|
|
|
nil];
|
2007-11-26 21:41:59 +01:00
|
|
|
|
2007-05-09 21:07:35 +02:00
|
|
|
emails = [NSMutableArray array];
|
|
|
|
cn = nil;
|
|
|
|
c_uid = nil;
|
2009-11-29 22:48:00 +01:00
|
|
|
c_domain = nil;
|
2009-05-12 21:56:39 +02:00
|
|
|
c_imaphostname = nil;
|
2011-04-14 20:41:10 +02:00
|
|
|
c_imaplogin = nil;
|
2012-12-03 22:42:56 +01:00
|
|
|
c_sievehostname = nil;
|
2007-05-09 21:07:35 +02:00
|
|
|
|
2015-06-18 18:19:02 +02:00
|
|
|
enumerator = [access_types_list objectEnumerator];
|
|
|
|
while ((access_type = [enumerator nextObject]) != nil)
|
2015-08-03 09:48:06 +02:00
|
|
|
[theCurrentUser setObject: [NSNumber numberWithBool: YES]
|
|
|
|
forKey: access_type];
|
|
|
|
|
2016-01-08 17:39:19 +01:00
|
|
|
// For DomainLessLogin, we MUST strip any trailing domain part before
|
|
|
|
// doing lookups in our source (LDAP for example) as the UIDFieldName
|
|
|
|
// or the BindFields/MailFieldNames don't necessarily contain the
|
|
|
|
// domain in the value pair.
|
2015-08-03 09:48:06 +02:00
|
|
|
if ([[theCurrentUser objectForKey: @"DomainLessLogin"] boolValue])
|
|
|
|
{
|
|
|
|
NSRange r;
|
2015-06-11 17:36:03 +02:00
|
|
|
|
2016-01-08 17:39:19 +01:00
|
|
|
r = [theUID rangeOfString: @"@"];
|
2015-08-21 16:30:47 +02:00
|
|
|
|
|
|
|
// We check if the range is ok here since we could be using DomainLessLogin
|
|
|
|
if (r.location != NSNotFound)
|
|
|
|
theUID = [theUID substringToIndex: r.location];
|
2015-08-03 09:48:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
sogoSources = [[self authenticationSourceIDsInDomain: theDomain] objectEnumerator];
|
2012-01-03 23:52:27 +01:00
|
|
|
userEntry = nil;
|
|
|
|
while (!userEntry && (sourceID = [sogoSources nextObject]))
|
2007-05-09 21:07:35 +02:00
|
|
|
{
|
2009-09-25 16:42:33 +02:00
|
|
|
currentSource = [_sources objectForKey: sourceID];
|
2015-09-23 15:48:21 +02:00
|
|
|
|
2015-08-03 09:48:06 +02:00
|
|
|
userEntry = [currentSource lookupContactEntryWithUIDorEmail: theUID
|
|
|
|
inDomain: theDomain];
|
2007-05-09 21:07:35 +02:00
|
|
|
if (userEntry)
|
2015-04-15 18:52:55 +02:00
|
|
|
{
|
2015-08-03 09:48:06 +02:00
|
|
|
[theCurrentUser setObject: sourceID forKey: @"SOGoSource"];
|
2015-04-15 18:52:55 +02:00
|
|
|
if (!cn)
|
|
|
|
cn = [userEntry objectForKey: @"c_cn"];
|
|
|
|
if (!c_uid)
|
|
|
|
c_uid = [userEntry objectForKey: @"c_uid"];
|
2009-11-29 22:48:00 +01:00
|
|
|
if (!c_domain)
|
|
|
|
c_domain = [userEntry objectForKey: @"c_domain"];
|
2015-04-15 18:52:55 +02:00
|
|
|
c_emails = [userEntry objectForKey: @"c_emails"];
|
|
|
|
if ([c_emails count])
|
|
|
|
[emails addObjectsFromArray: c_emails];
|
|
|
|
if (!c_imaphostname)
|
|
|
|
c_imaphostname = [userEntry objectForKey: @"c_imaphostname"];
|
2011-04-14 20:41:10 +02:00
|
|
|
if (!c_imaplogin)
|
|
|
|
c_imaplogin = [userEntry objectForKey: @"c_imaplogin"];
|
2012-12-03 22:42:56 +01:00
|
|
|
if (!c_sievehostname)
|
|
|
|
c_sievehostname = [userEntry objectForKey: @"c_sievehostname"];
|
2015-06-18 18:19:02 +02:00
|
|
|
|
|
|
|
enumerator = [access_types_list objectEnumerator];
|
|
|
|
while ((access_type = [enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
access = [[userEntry objectForKey: access_type] boolValue];
|
|
|
|
if (!access)
|
2015-08-03 09:48:06 +02:00
|
|
|
[theCurrentUser setObject: [NSNumber numberWithBool: NO]
|
|
|
|
forKey: access_type];
|
2015-06-18 18:19:02 +02:00
|
|
|
}
|
2015-04-15 18:52:55 +02:00
|
|
|
|
|
|
|
// We check if it's a group
|
2012-04-18 19:39:11 +02:00
|
|
|
isGroup = [userEntry objectForKey: @"isGroup"];
|
|
|
|
if (isGroup)
|
2015-08-03 09:48:06 +02:00
|
|
|
[theCurrentUser setObject: isGroup forKey: @"isGroup"];
|
2011-04-25 12:31:08 +02:00
|
|
|
|
2015-04-15 18:52:55 +02:00
|
|
|
// We also fill the resource attributes, if any
|
|
|
|
if ([userEntry objectForKey: @"isResource"])
|
2015-08-03 09:48:06 +02:00
|
|
|
[theCurrentUser setObject: [userEntry objectForKey: @"isResource"]
|
|
|
|
forKey: @"isResource"];
|
2015-04-15 18:52:55 +02:00
|
|
|
if ([userEntry objectForKey: @"numberOfSimultaneousBookings"])
|
2015-08-03 09:48:06 +02:00
|
|
|
[theCurrentUser setObject: [userEntry objectForKey: @"numberOfSimultaneousBookings"]
|
|
|
|
forKey: @"numberOfSimultaneousBookings"];
|
2015-04-15 18:52:55 +02:00
|
|
|
|
|
|
|
// This is Active Directory specific attribute (needed on OpenChange/* layer)
|
|
|
|
if ([userEntry objectForKey: @"samaccountname"])
|
2015-08-03 09:48:06 +02:00
|
|
|
[theCurrentUser setObject: [userEntry objectForKey: @"samaccountname"]
|
|
|
|
forKey: @"sAMAccountName"];
|
2012-01-12 21:01:34 +01:00
|
|
|
}
|
2007-05-09 21:07:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!cn)
|
|
|
|
cn = @"";
|
|
|
|
if (!c_uid)
|
|
|
|
c_uid = @"";
|
2009-11-29 22:48:00 +01:00
|
|
|
if (!c_domain)
|
|
|
|
c_domain = @"";
|
2015-04-15 18:52:55 +02:00
|
|
|
|
2009-05-12 21:56:39 +02:00
|
|
|
if (c_imaphostname)
|
2015-08-03 09:48:06 +02:00
|
|
|
[theCurrentUser setObject: c_imaphostname forKey: @"c_imaphostname"];
|
2011-04-14 20:41:10 +02:00
|
|
|
if (c_imaplogin)
|
2015-08-03 09:48:06 +02:00
|
|
|
[theCurrentUser setObject: c_imaplogin forKey: @"c_imaplogin"];
|
2012-12-03 22:42:56 +01:00
|
|
|
if (c_sievehostname)
|
2015-08-03 09:48:06 +02:00
|
|
|
[theCurrentUser setObject: c_sievehostname forKey: @"c_sievehostname"];
|
2011-04-25 12:31:08 +02:00
|
|
|
|
2015-08-03 09:48:06 +02:00
|
|
|
[theCurrentUser setObject: emails forKey: @"emails"];
|
|
|
|
[theCurrentUser setObject: cn forKey: @"cn"];
|
|
|
|
[theCurrentUser setObject: c_uid forKey: @"c_uid"];
|
|
|
|
[theCurrentUser setObject: c_domain forKey: @"c_domain"];
|
2007-10-10 20:44:26 +02:00
|
|
|
|
|
|
|
// If our LDAP queries gave us nothing, we add at least one default
|
|
|
|
// email address based on the default domain.
|
2015-08-03 09:48:06 +02:00
|
|
|
[self _fillContactMailRecords: theCurrentUser];
|
2007-05-09 21:07:35 +02:00
|
|
|
}
|
|
|
|
|
2009-02-24 02:54:59 +01:00
|
|
|
//
|
|
|
|
// We cache here all identities, including those
|
|
|
|
// associated with email addresses.
|
|
|
|
//
|
2007-05-09 21:07:35 +02:00
|
|
|
- (void) _retainUser: (NSDictionary *) newUser
|
2011-06-24 21:19:50 +02:00
|
|
|
withLogin: (NSString *) login
|
2007-05-09 21:07:35 +02:00
|
|
|
{
|
|
|
|
NSEnumerator *emails;
|
2015-05-20 11:44:06 +02:00
|
|
|
NSString *key, *user_json;
|
|
|
|
|
|
|
|
user_json = [newUser jsonRepresentation];
|
|
|
|
[[SOGoCache sharedCache] setUserAttributes: user_json
|
|
|
|
forLogin: login];
|
2012-10-06 20:51:26 +02:00
|
|
|
if (![newUser isKindOfClass: NSNullK])
|
|
|
|
{
|
|
|
|
emails = [[newUser objectForKey: @"emails"] objectEnumerator];
|
|
|
|
while ((key = [emails nextObject]))
|
2015-05-20 11:44:06 +02:00
|
|
|
{
|
|
|
|
if (![key isEqualToString: login])
|
|
|
|
[[SOGoCache sharedCache] setUserAttributes: user_json
|
|
|
|
forLogin: key];
|
|
|
|
}
|
2012-10-06 20:51:26 +02:00
|
|
|
}
|
2007-05-09 21:07:35 +02:00
|
|
|
}
|
|
|
|
|
2010-06-01 20:48:14 +02:00
|
|
|
- (NSMutableDictionary *) _contactInfosForAnonymous
|
|
|
|
{
|
|
|
|
static NSMutableDictionary *user = nil;
|
|
|
|
|
|
|
|
if (!user)
|
|
|
|
{
|
|
|
|
user = [[NSMutableDictionary alloc] initWithCapacity: 7];
|
|
|
|
[user setObject: [NSArray arrayWithObject: @"anonymous"]
|
|
|
|
forKey: @"emails"];
|
|
|
|
[user setObject: @"Public User" forKey: @"cn"];
|
|
|
|
[user setObject: @"anonymous" forKey: @"c_uid"];
|
|
|
|
[user setObject: @"" forKey: @"c_domain"];
|
|
|
|
[user setObject: [NSNumber numberWithBool: YES]
|
|
|
|
forKey: @"CalendarAccess"];
|
|
|
|
[user setObject: [NSNumber numberWithBool: NO]
|
2015-09-23 15:48:21 +02:00
|
|
|
forKey: @"MailAccess"];
|
2010-06-01 20:48:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return user;
|
|
|
|
}
|
|
|
|
|
2011-06-24 21:19:50 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @see [SOGoUser initWithLogin:roles:trust:]
|
|
|
|
*/
|
|
|
|
- (NSDictionary *) contactInfosForUserWithUIDorEmail: (NSString *) uid
|
|
|
|
{
|
|
|
|
NSRange r;
|
|
|
|
NSString *username, *domain;
|
|
|
|
NSDictionary *infos;
|
|
|
|
SOGoSystemDefaults *sd;
|
|
|
|
|
|
|
|
domain = nil;
|
|
|
|
infos = nil;
|
|
|
|
|
2011-07-16 00:22:11 +02:00
|
|
|
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
2011-07-19 18:25:11 +02:00
|
|
|
if ([sd enableDomainBasedUID])
|
2011-06-24 21:19:50 +02:00
|
|
|
{
|
2011-07-16 00:22:11 +02:00
|
|
|
r = [uid rangeOfString: @"@" options: NSBackwardsSearch];
|
|
|
|
if (r.location != NSNotFound)
|
|
|
|
{
|
|
|
|
// The domain is probably appended to the username;
|
|
|
|
// make sure it is a defined domain in the configuration.
|
|
|
|
domain = [uid substringFromIndex: (r.location + r.length)];
|
2015-09-23 15:36:39 +02:00
|
|
|
if ([self isDomainDefined: domain])
|
2011-07-16 00:22:11 +02:00
|
|
|
username = [uid substringToIndex: r.location];
|
|
|
|
else
|
|
|
|
domain = nil;
|
|
|
|
}
|
|
|
|
if (domain != nil)
|
|
|
|
infos = [self contactInfosForUserWithUIDorEmail: username
|
|
|
|
inDomain: domain];
|
2011-06-24 21:19:50 +02:00
|
|
|
}
|
2011-07-16 00:22:11 +02:00
|
|
|
|
2011-06-24 21:19:50 +02:00
|
|
|
if (infos == nil)
|
|
|
|
// If the user was not found using the domain or if no domain was detected,
|
|
|
|
// search using the original uid.
|
|
|
|
infos = [self contactInfosForUserWithUIDorEmail: uid
|
|
|
|
inDomain: nil];
|
2015-09-23 15:48:21 +02:00
|
|
|
|
2011-06-24 21:19:50 +02:00
|
|
|
return infos;
|
|
|
|
}
|
|
|
|
|
2007-05-09 21:07:35 +02:00
|
|
|
- (NSDictionary *) contactInfosForUserWithUIDorEmail: (NSString *) uid
|
2011-06-24 21:19:50 +02:00
|
|
|
inDomain: (NSString *) domain
|
2007-05-09 21:07:35 +02:00
|
|
|
{
|
2015-07-28 12:37:33 +02:00
|
|
|
NSString *aUID, *cacheUid, *jsonUser;
|
2015-08-03 09:48:06 +02:00
|
|
|
NSMutableDictionary *currentUser;
|
|
|
|
|
2007-05-09 21:07:35 +02:00
|
|
|
BOOL newUser;
|
|
|
|
|
2010-06-01 20:48:14 +02:00
|
|
|
if ([uid isEqualToString: @"anonymous"])
|
|
|
|
currentUser = [self _contactInfosForAnonymous];
|
2013-01-28 14:34:40 +01:00
|
|
|
else if ([uid length] > 0)
|
2007-05-09 21:07:35 +02:00
|
|
|
{
|
2009-05-03 19:50:57 +02:00
|
|
|
// Remove the "@" prefix used to identified groups in the ACL tables.
|
|
|
|
aUID = [uid hasPrefix: @"@"] ? [uid substringFromIndex: 1] : uid;
|
2015-08-03 09:48:06 +02:00
|
|
|
if (domain && [aUID rangeOfString: @"@"].location == NSNotFound)
|
2011-06-24 21:19:50 +02:00
|
|
|
cacheUid = [NSString stringWithFormat: @"%@@%@", aUID, domain];
|
|
|
|
else
|
|
|
|
cacheUid = aUID;
|
2015-08-03 09:48:06 +02:00
|
|
|
|
2011-06-24 21:19:50 +02:00
|
|
|
jsonUser = [[SOGoCache sharedCache] userAttributesForLogin: cacheUid];
|
2011-10-26 17:25:49 +02:00
|
|
|
currentUser = [jsonUser objectFromJSONString];
|
2015-08-03 09:48:06 +02:00
|
|
|
|
2012-10-06 20:51:26 +02:00
|
|
|
if ([currentUser isKindOfClass: NSNullK])
|
|
|
|
currentUser = nil;
|
|
|
|
else if (!([currentUser objectForKey: @"emails"]
|
2015-09-23 15:48:21 +02:00
|
|
|
&& [currentUser objectForKey: @"cn"]))
|
|
|
|
{
|
|
|
|
// We make sure that we either have no occurence of a cache entry or
|
|
|
|
// that we have an occurence with only a cached password. In the
|
|
|
|
// latter case, we update the entry with the remaining information
|
|
|
|
// and recache the value.
|
|
|
|
if (!currentUser ||
|
2015-08-03 09:48:06 +02:00
|
|
|
([currentUser count] == 1 && [currentUser objectForKey: @"password"]) ||
|
|
|
|
([currentUser count] == 2 && [currentUser objectForKey: @"password"] && [currentUser objectForKey: @"DomainLessLogin"]))
|
|
|
|
{
|
2015-09-23 15:48:21 +02:00
|
|
|
newUser = YES;
|
|
|
|
|
|
|
|
if (!currentUser)
|
|
|
|
currentUser = [NSMutableDictionary dictionary];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
newUser = NO;
|
|
|
|
[self _fillContactInfosForUser: currentUser
|
2011-06-24 21:19:50 +02:00
|
|
|
withUIDorEmail: aUID
|
|
|
|
inDomain: domain];
|
2015-09-23 15:48:21 +02:00
|
|
|
if (newUser)
|
|
|
|
{
|
|
|
|
if ([[currentUser objectForKey: @"c_uid"] length] == 0)
|
2012-10-06 20:51:26 +02:00
|
|
|
{
|
|
|
|
[self _retainUser: (NSDictionary *) [NSNull null]
|
|
|
|
withLogin: cacheUid];
|
|
|
|
currentUser = nil;
|
|
|
|
}
|
|
|
|
else
|
2015-08-03 09:48:06 +02:00
|
|
|
{
|
|
|
|
SOGoSystemDefaults *sd;
|
|
|
|
|
|
|
|
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
|
|
|
|
|
|
|
// SOGoEnableDomainBasedUID is set to YES but we don't have a domain part. This happens in
|
|
|
|
// multi-domain environments authenticating only with the UIDFieldName
|
|
|
|
if ([sd enableDomainBasedUID] && !domain)
|
|
|
|
{
|
2016-04-12 19:17:04 +02:00
|
|
|
NSString *suffix;
|
|
|
|
|
|
|
|
suffix = [NSString stringWithFormat: @"@%@", [currentUser objectForKey: @"c_domain"]];
|
|
|
|
|
|
|
|
if (![cacheUid hasSuffix: suffix])
|
|
|
|
{
|
|
|
|
cacheUid = [NSString stringWithFormat: @"%@%@", cacheUid, suffix];
|
|
|
|
[currentUser setObject: [NSNumber numberWithBool: YES] forKey: @"DomainLessLogin"];
|
|
|
|
}
|
2015-08-03 09:48:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
[self _retainUser: currentUser withLogin: cacheUid];
|
|
|
|
}
|
|
|
|
}
|
2015-09-23 15:48:21 +02:00
|
|
|
}
|
2007-05-09 21:07:35 +02:00
|
|
|
}
|
2007-05-10 16:59:13 +02:00
|
|
|
else
|
|
|
|
currentUser = nil;
|
2007-05-09 21:07:35 +02:00
|
|
|
|
|
|
|
return currentUser;
|
|
|
|
}
|
|
|
|
|
2015-03-04 03:18:46 +01:00
|
|
|
/**
|
|
|
|
* Fetch the contact information identified by the specified UID in the global addressbooks.
|
|
|
|
*/
|
|
|
|
- (NSDictionary *) fetchContactWithUID: (NSString *) uid
|
|
|
|
inDomain: (NSString *) domain
|
|
|
|
{
|
2015-03-04 16:05:12 +01:00
|
|
|
NSDictionary *contact;
|
2015-03-04 03:18:46 +01:00
|
|
|
NSMutableArray *contacts;
|
|
|
|
NSEnumerator *sources;
|
|
|
|
NSString *sourceID;
|
|
|
|
id currentSource;
|
|
|
|
|
|
|
|
contacts = [NSMutableArray array];
|
2015-03-04 16:05:12 +01:00
|
|
|
contact = nil;
|
2015-03-04 03:18:46 +01:00
|
|
|
sources = [[self addressBookSourceIDsInDomain: domain] objectEnumerator];
|
|
|
|
while ((sourceID = [sources nextObject]))
|
|
|
|
{
|
|
|
|
currentSource = [_sources objectForKey: sourceID];
|
2015-09-23 15:09:45 +02:00
|
|
|
contact = [currentSource lookupContactEntry: uid inDomain: domain];
|
2015-03-04 16:05:12 +01:00
|
|
|
if (contact)
|
|
|
|
[contacts addObject: contact];
|
2015-03-04 03:18:46 +01:00
|
|
|
}
|
|
|
|
|
2015-03-04 16:05:12 +01:00
|
|
|
if ([contacts count])
|
|
|
|
contact = [[self _compactAndCompleteContacts: [contacts objectEnumerator]] lastObject];
|
|
|
|
else
|
|
|
|
contact = nil;
|
|
|
|
|
|
|
|
return contact;
|
2015-03-04 03:18:46 +01:00
|
|
|
}
|
|
|
|
|
2007-05-09 21:07:35 +02:00
|
|
|
- (NSArray *) _compactAndCompleteContacts: (NSEnumerator *) contacts
|
|
|
|
{
|
|
|
|
NSMutableDictionary *compactContacts, *returnContact;
|
|
|
|
NSDictionary *userEntry;
|
2012-03-21 16:50:07 +01:00
|
|
|
NSArray *newContacts, *allEmails;
|
2007-05-09 21:07:35 +02:00
|
|
|
NSMutableArray *emails;
|
2009-11-29 05:19:32 +01:00
|
|
|
NSString *uid, *email, *info;
|
2011-10-21 22:12:38 +02:00
|
|
|
NSNumber *isGroup;
|
2012-02-14 22:23:31 +01:00
|
|
|
id <SOGoSource> source;
|
2012-03-21 16:50:07 +01:00
|
|
|
NSUInteger count, max;
|
2007-05-09 21:07:35 +02:00
|
|
|
|
|
|
|
compactContacts = [NSMutableDictionary dictionary];
|
2008-11-23 09:33:08 +01:00
|
|
|
while ((userEntry = [contacts nextObject]))
|
2007-05-09 21:07:35 +02:00
|
|
|
{
|
|
|
|
uid = [userEntry objectForKey: @"c_uid"];
|
2007-09-11 00:15:03 +02:00
|
|
|
if ([uid length])
|
2015-09-23 15:48:21 +02:00
|
|
|
{
|
|
|
|
returnContact = [compactContacts objectForKey: uid];
|
|
|
|
if (!returnContact)
|
|
|
|
{
|
|
|
|
returnContact = [NSMutableDictionary dictionary];
|
|
|
|
[returnContact setObject: uid forKey: @"c_uid"];
|
2012-02-14 22:23:31 +01:00
|
|
|
source = [userEntry objectForKey: @"source"];
|
|
|
|
if (source)
|
|
|
|
[returnContact setObject: source forKey: @"source"];
|
2012-01-12 21:01:34 +01:00
|
|
|
[compactContacts setObject: returnContact forKey: uid];
|
|
|
|
}
|
2015-09-23 15:48:21 +02:00
|
|
|
if (![[returnContact objectForKey: @"c_name"] length])
|
|
|
|
[returnContact setObject: [userEntry objectForKey: @"c_name"]
|
|
|
|
forKey: @"c_name"];
|
|
|
|
if (![[returnContact objectForKey: @"cn"] length])
|
|
|
|
[returnContact setObject: [userEntry objectForKey: @"c_cn"]
|
|
|
|
forKey: @"cn"];
|
|
|
|
emails = [returnContact objectForKey: @"emails"];
|
|
|
|
if (!emails)
|
|
|
|
{
|
|
|
|
emails = [NSMutableArray array];
|
|
|
|
[returnContact setObject: emails forKey: @"emails"];
|
|
|
|
}
|
|
|
|
email = [userEntry objectForKey: @"mail"];
|
2012-03-21 16:50:07 +01:00
|
|
|
if ([email isKindOfClass: [NSArray class]])
|
|
|
|
{
|
|
|
|
allEmails = (NSArray *) email;
|
|
|
|
max = [allEmails count];
|
|
|
|
for (count = 0; count < max; count++)
|
|
|
|
{
|
|
|
|
email = [allEmails objectAtIndex: count];
|
|
|
|
[emails addObjectUniquely: email];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (email && ![emails containsObject: email])
|
2015-09-23 15:48:21 +02:00
|
|
|
[emails addObject: email];
|
|
|
|
email = [userEntry objectForKey: @"mozillasecondemail"];
|
|
|
|
if (email && ![emails containsObject: email])
|
|
|
|
[emails addObject: email];
|
|
|
|
email = [userEntry objectForKey: @"xmozillasecondemail"];
|
|
|
|
if (email && ![emails containsObject: email])
|
|
|
|
[emails addObject: email];
|
2009-11-29 05:19:32 +01:00
|
|
|
info = [userEntry objectForKey: @"c_info"];
|
|
|
|
if ([info length] > 0
|
|
|
|
&& ![[returnContact objectForKey: @"c_info"] length])
|
|
|
|
[returnContact setObject: info forKey: @"c_info"];
|
2015-09-23 15:48:21 +02:00
|
|
|
[self _fillContactMailRecords: returnContact];
|
2011-10-21 22:12:38 +02:00
|
|
|
isGroup = [userEntry objectForKey: @"isGroup"];
|
|
|
|
if (isGroup)
|
|
|
|
[returnContact setObject: isGroup forKey: @"isGroup"];
|
2015-09-23 15:48:21 +02:00
|
|
|
}
|
2007-05-09 21:07:35 +02:00
|
|
|
}
|
2008-12-12 19:55:12 +01:00
|
|
|
|
2007-05-09 21:07:35 +02:00
|
|
|
newContacts = [compactContacts allValues];
|
|
|
|
|
|
|
|
return newContacts;
|
|
|
|
}
|
|
|
|
|
2008-08-07 18:07:43 +02:00
|
|
|
- (NSArray *) _fetchEntriesInSources: (NSArray *) sourcesList
|
2015-09-23 15:48:21 +02:00
|
|
|
matching: (NSString *) filter
|
2012-02-11 08:08:02 +01:00
|
|
|
inDomain: (NSString *) domain
|
2008-07-28 22:29:24 +02:00
|
|
|
{
|
|
|
|
NSMutableArray *contacts;
|
2009-09-25 16:42:33 +02:00
|
|
|
NSEnumerator *sources;
|
2008-07-28 22:29:24 +02:00
|
|
|
NSString *sourceID;
|
2009-09-25 16:42:33 +02:00
|
|
|
id currentSource;
|
2008-07-28 22:29:24 +02:00
|
|
|
|
|
|
|
contacts = [NSMutableArray array];
|
2009-09-25 16:42:33 +02:00
|
|
|
sources = [sourcesList objectEnumerator];
|
|
|
|
while ((sourceID = [sources nextObject]))
|
2008-07-28 22:29:24 +02:00
|
|
|
{
|
2009-09-25 16:42:33 +02:00
|
|
|
currentSource = [_sources objectForKey: sourceID];
|
2008-07-28 22:29:24 +02:00
|
|
|
[contacts addObjectsFromArray:
|
2015-09-23 15:48:21 +02:00
|
|
|
[currentSource fetchContactsMatching: filter
|
2012-02-11 08:08:02 +01:00
|
|
|
inDomain: domain]];
|
2008-07-28 22:29:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return [self _compactAndCompleteContacts: [contacts objectEnumerator]];
|
|
|
|
}
|
|
|
|
|
2008-08-07 18:07:43 +02:00
|
|
|
- (NSArray *) fetchContactsMatching: (NSString *) filter
|
2009-11-29 05:19:32 +01:00
|
|
|
inDomain: (NSString *) domain
|
2008-08-07 18:07:43 +02:00
|
|
|
{
|
2009-11-29 05:19:32 +01:00
|
|
|
return [self
|
|
|
|
_fetchEntriesInSources: [self addressBookSourceIDsInDomain: domain]
|
2012-02-11 08:08:02 +01:00
|
|
|
matching: filter
|
|
|
|
inDomain: domain];
|
2008-08-07 18:07:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray *) fetchUsersMatching: (NSString *) filter
|
2009-11-29 22:48:00 +01:00
|
|
|
inDomain: (NSString *) domain
|
2008-08-07 18:07:43 +02:00
|
|
|
{
|
2012-02-11 08:08:02 +01:00
|
|
|
return [self
|
|
|
|
_fetchEntriesInSources: [self authenticationSourceIDsInDomain: domain]
|
|
|
|
matching: filter
|
|
|
|
inDomain: domain];
|
2008-08-07 18:07:43 +02:00
|
|
|
}
|
|
|
|
|
2009-05-03 19:50:57 +02:00
|
|
|
- (NSString *) getLoginForDN: (NSString *) theDN
|
|
|
|
{
|
2009-12-02 21:53:52 +01:00
|
|
|
NSEnumerator *sources;
|
2009-05-03 19:50:57 +02:00
|
|
|
NSString *login;
|
2009-12-02 21:53:52 +01:00
|
|
|
NSObject <SOGoDNSource> *currentSource;
|
2009-05-03 19:50:57 +02:00
|
|
|
|
|
|
|
login = nil;
|
2009-12-02 21:53:52 +01:00
|
|
|
|
|
|
|
sources = [[_sources allValues] objectEnumerator];
|
|
|
|
while (!login && (currentSource = [sources nextObject]))
|
|
|
|
if ([currentSource conformsToProtocol: @protocol (SOGoDNSource)]
|
|
|
|
&& [theDN hasSuffix: [currentSource baseDN]])
|
|
|
|
login = [currentSource lookupLoginByDN: theDN];
|
|
|
|
|
2009-05-03 19:50:57 +02:00
|
|
|
return login;
|
|
|
|
}
|
|
|
|
|
2007-05-09 21:07:35 +02:00
|
|
|
@end
|