(fix) improvement over previous commit to avoid double-bind

pull/89/head
Ludovic Marcotte 2015-06-11 11:36:03 -04:00
parent 44af47f69e
commit 5e66e8e299
1 changed files with 82 additions and 63 deletions

View File

@ -435,48 +435,22 @@ static Class NSNullK;
grace: (int *) grace
{
NSObject <SOGoSource> *sogoSource;
SOGoSystemDefaults *sd;
NSEnumerator *authIDs;
NSString *currentID;
BOOL checkOK;
NSRange r;
sd = [SOGoSystemDefaults sharedSystemDefaults];
checkOK = NO;
authIDs = [[self authenticationSourceIDsInDomain: *domain] objectEnumerator];
while (!checkOK && (currentID = [authIDs nextObject]))
{
sogoSource = [_sources objectForKey: currentID];
r = [login rangeOfString: [NSString stringWithFormat: @"@%@", *domain]];
checkOK = [sogoSource checkLogin: login
password: password
perr: perr
expire: expire
grace: grace];
// If we are using multidomain and the UIDFieldName is not part of the email address
// we must also try to 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;
// The -checkLogin:... above would have failed because SOGo would first try to bind using: foo@example.com
//
if (!checkOK && *domain && [sd enableDomainBasedUID] && r.location != NSNotFound)
{
checkOK = [sogoSource checkLogin: [login substringToIndex: r.location]
password: password
perr: perr
expire: expire
grace: grace];
}
}
if (checkOK && *domain == nil)
@ -582,6 +556,28 @@ static Class NSNullK;
// authentication source and try to validate there, then cache it.
jsonUser = [[SOGoCache sharedCache] userAttributesForLogin: username];
currentUser = [jsonUser objectFromJSONString];
//
// 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 to bind using: foo@example.com
//
if ([[currentUser objectForKey: @"DomainLessLogin"] boolValue])
{
NSRange r;
r = [_login rangeOfString: [NSString stringWithFormat: @"@%@", *_domain]];
_login = [_login substringToIndex: r.location];
}
dictPassword = [currentUser objectForKey: @"password"];
if (useCache && currentUser && dictPassword)
{
@ -602,11 +598,16 @@ static Class NSNullK;
}
// Before caching user attributes, we must check if SOGoEnableDomainBasedUID is enabled
// but we don't have a domain. That would happen for example if a user authenticates
// without the domain part.
// 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];
{
username = [NSString stringWithFormat: @"%@@%@", username, *_domain];
[currentUser setObject: [NSNumber numberWithBool: YES] forKey: @"DomainLessLogin"];
}
// It's important to cache the password here as we might have cached the
// user's entry in -contactInfosForUserWithUIDorEmail: and if we don't
@ -729,9 +730,9 @@ static Class NSNullK;
//
//
//
- (void) _fillContactInfosForUser: (NSMutableDictionary *) currentUser
withUIDorEmail: (NSString *) uid
inDomain: (NSString *) domain
- (void) _fillContactInfosForUser: (NSMutableDictionary *) theCurrentUser
withUIDorEmail: (NSString *) theUID
inDomain: (NSString *) theDomain
{
NSString *sourceID, *cn, *c_domain, *c_uid, *c_imaphostname, *c_imaplogin, *c_sievehostname;
NSObject <SOGoSource> *currentSource;
@ -750,21 +751,31 @@ static Class NSNullK;
c_imaplogin = nil;
c_sievehostname = nil;
[currentUser setObject: [NSNumber numberWithBool: YES]
forKey: @"CalendarAccess"];
[currentUser setObject: [NSNumber numberWithBool: YES]
forKey: @"MailAccess"];
[theCurrentUser setObject: [NSNumber numberWithBool: YES]
forKey: @"CalendarAccess"];
[theCurrentUser setObject: [NSNumber numberWithBool: YES]
forKey: @"MailAccess"];
sogoSources = [[self authenticationSourceIDsInDomain: domain] objectEnumerator];
if ([[theCurrentUser objectForKey: @"DomainLessLogin"] boolValue])
{
NSRange r;
r = [theUID rangeOfString: [NSString stringWithFormat: @"@%@", theDomain]];
theUID = [theUID substringToIndex: r.location];
}
sogoSources = [[self authenticationSourceIDsInDomain: theDomain] objectEnumerator];
userEntry = nil;
while (!userEntry && (sourceID = [sogoSources nextObject]))
{
currentSource = [_sources objectForKey: sourceID];
userEntry = [currentSource lookupContactEntryWithUIDorEmail: uid
inDomain: domain];
userEntry = [currentSource lookupContactEntryWithUIDorEmail: theUID
inDomain: theDomain];
if (userEntry)
{
[currentUser setObject: sourceID forKey: @"SOGoSource"];
[theCurrentUser setObject: sourceID forKey: @"SOGoSource"];
if (!cn)
cn = [userEntry objectForKey: @"c_cn"];
if (!c_uid)
@ -782,30 +793,30 @@ static Class NSNullK;
c_sievehostname = [userEntry objectForKey: @"c_sievehostname"];
access = [[userEntry objectForKey: @"CalendarAccess"] boolValue];
if (!access)
[currentUser setObject: [NSNumber numberWithBool: NO]
forKey: @"CalendarAccess"];
[theCurrentUser setObject: [NSNumber numberWithBool: NO]
forKey: @"CalendarAccess"];
access = [[userEntry objectForKey: @"MailAccess"] boolValue];
if (!access)
[currentUser setObject: [NSNumber numberWithBool: NO]
forKey: @"MailAccess"];
[theCurrentUser setObject: [NSNumber numberWithBool: NO]
forKey: @"MailAccess"];
// We check if it's a group
isGroup = [userEntry objectForKey: @"isGroup"];
if (isGroup)
[currentUser setObject: isGroup forKey: @"isGroup"];
[theCurrentUser setObject: isGroup forKey: @"isGroup"];
// We also fill the resource attributes, if any
if ([userEntry objectForKey: @"isResource"])
[currentUser setObject: [userEntry objectForKey: @"isResource"]
forKey: @"isResource"];
[theCurrentUser setObject: [userEntry objectForKey: @"isResource"]
forKey: @"isResource"];
if ([userEntry objectForKey: @"numberOfSimultaneousBookings"])
[currentUser setObject: [userEntry objectForKey: @"numberOfSimultaneousBookings"]
forKey: @"numberOfSimultaneousBookings"];
[theCurrentUser setObject: [userEntry objectForKey: @"numberOfSimultaneousBookings"]
forKey: @"numberOfSimultaneousBookings"];
// This is Active Directory specific attribute (needed on OpenChange/* layer)
if ([userEntry objectForKey: @"samaccountname"])
[currentUser setObject: [userEntry objectForKey: @"samaccountname"]
forKey: @"sAMAccountName"];
[theCurrentUser setObject: [userEntry objectForKey: @"samaccountname"]
forKey: @"sAMAccountName"];
}
}
@ -817,20 +828,20 @@ static Class NSNullK;
c_domain = @"";
if (c_imaphostname)
[currentUser setObject: c_imaphostname forKey: @"c_imaphostname"];
[theCurrentUser setObject: c_imaphostname forKey: @"c_imaphostname"];
if (c_imaplogin)
[currentUser setObject: c_imaplogin forKey: @"c_imaplogin"];
[theCurrentUser setObject: c_imaplogin forKey: @"c_imaplogin"];
if (c_sievehostname)
[currentUser setObject: c_sievehostname forKey: @"c_sievehostname"];
[theCurrentUser setObject: c_sievehostname forKey: @"c_sievehostname"];
[currentUser setObject: emails forKey: @"emails"];
[currentUser setObject: cn forKey: @"cn"];
[currentUser setObject: c_uid forKey: @"c_uid"];
[currentUser setObject: c_domain forKey: @"c_domain"];
[theCurrentUser setObject: emails forKey: @"emails"];
[theCurrentUser setObject: cn forKey: @"cn"];
[theCurrentUser setObject: c_uid forKey: @"c_uid"];
[theCurrentUser setObject: c_domain forKey: @"c_domain"];
// If our LDAP queries gave us nothing, we add at least one default
// email address based on the default domain.
[self _fillContactMailRecords: currentUser];
[self _fillContactMailRecords: theCurrentUser];
}
//
@ -939,8 +950,10 @@ static Class NSNullK;
cacheUid = [NSString stringWithFormat: @"%@@%@", aUID, domain];
else
cacheUid = aUID;
jsonUser = [[SOGoCache sharedCache] userAttributesForLogin: cacheUid];
currentUser = [jsonUser objectFromJSONString];
if ([currentUser isKindOfClass: NSNullK])
currentUser = nil;
else if (!([currentUser objectForKey: @"emails"]
@ -950,8 +963,10 @@ static Class NSNullK;
// 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 || ([currentUser count] == 1 && [currentUser objectForKey: @"password"]))
{
if (!currentUser ||
([currentUser count] == 1 && [currentUser objectForKey: @"password"]) ||
([currentUser count] == 2 && [currentUser objectForKey: @"password"] && [currentUser objectForKey: @"DomainLessLogin"]))
{
newUser = YES;
if (!currentUser)
@ -976,9 +991,13 @@ static Class NSNullK;
sd = [SOGoSystemDefaults sharedSystemDefaults];
// to true but we don't have a domain part.
// 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)
cacheUid = [NSString stringWithFormat: @"%@@%@", cacheUid, [currentUser objectForKey: @"c_domain"]];
{
cacheUid = [NSString stringWithFormat: @"%@@%@", cacheUid, [currentUser objectForKey: @"c_domain"]];
[currentUser setObject: [NSNumber numberWithBool: YES] forKey: @"DomainLessLogin"];
}
[self _retainUser: currentUser withLogin: cacheUid];
}