mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-07-06 08:55:08 +00:00
Merge remote-tracking branch 'upstream/master' into merge-upstream
Conflicts: SoObjects/SOGo/SOGoUserManager.m Tools/SOGoToolRestore.m
This commit is contained in:
@@ -455,6 +455,7 @@ static Class NSNullK;
|
||||
while (!checkOK && (currentID = [authIDs nextObject]))
|
||||
{
|
||||
sogoSource = [_sources objectForKey: currentID];
|
||||
|
||||
checkOK = [sogoSource checkLogin: login
|
||||
password: password
|
||||
perr: perr
|
||||
@@ -501,10 +502,10 @@ static Class NSNullK;
|
||||
NSMutableDictionary *currentUser;
|
||||
NSDictionary *failedCount;
|
||||
NSString *dictPassword, *username, *jsonUser;
|
||||
SOGoSystemDefaults *dd;
|
||||
SOGoSystemDefaults *sd;
|
||||
BOOL checkOK;
|
||||
|
||||
dd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
|
||||
username = _login;
|
||||
|
||||
@@ -543,10 +544,10 @@ static Class NSNullK;
|
||||
start_time = [[failedCount objectForKey: @"InitialDate"] unsignedIntValue];
|
||||
delta = current_time - start_time;
|
||||
|
||||
block_time = [dd failedLoginBlockInterval];
|
||||
block_time = [sd failedLoginBlockInterval];
|
||||
|
||||
if ([[failedCount objectForKey: @"FailedCount"] intValue] >= [dd maximumFailedLoginCount] &&
|
||||
delta >= [dd maximumFailedLoginInterval] &&
|
||||
if ([[failedCount objectForKey: @"FailedCount"] intValue] >= [sd maximumFailedLoginCount] &&
|
||||
delta >= [sd maximumFailedLoginInterval] &&
|
||||
delta <= block_time )
|
||||
{
|
||||
*_perr = PolicyAccountLocked;
|
||||
@@ -565,6 +566,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 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];
|
||||
}
|
||||
|
||||
dictPassword = [currentUser objectForKey: @"password"];
|
||||
if (useCache && currentUser && dictPassword)
|
||||
{
|
||||
@@ -584,6 +607,18 @@ static Class NSNullK;
|
||||
currentUser = [NSMutableDictionary dictionary];
|
||||
}
|
||||
|
||||
// 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"];
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -597,7 +632,7 @@ static Class NSNullK;
|
||||
else
|
||||
{
|
||||
// If failed login "rate-limiting" is enabled, we adjust the stats
|
||||
if ([dd maximumFailedLoginCount])
|
||||
if ([sd maximumFailedLoginCount])
|
||||
{
|
||||
[[SOGoCache sharedCache] setFailedCount: ([[failedCount objectForKey: @"FailedCount"] intValue] + 1)
|
||||
forLogin: username];
|
||||
@@ -705,9 +740,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;
|
||||
@@ -726,21 +761,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)
|
||||
@@ -758,30 +803,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"];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -793,20 +838,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];
|
||||
}
|
||||
|
||||
//
|
||||
@@ -900,8 +945,9 @@ static Class NSNullK;
|
||||
- (NSDictionary *) contactInfosForUserWithUIDorEmail: (NSString *) uid
|
||||
inDomain: (NSString *) domain
|
||||
{
|
||||
NSMutableDictionary *currentUser;
|
||||
NSString *aUID, *cacheUid, *jsonUser;
|
||||
NSMutableDictionary *currentUser;
|
||||
|
||||
BOOL newUser;
|
||||
|
||||
if ([uid isEqualToString: @"anonymous"])
|
||||
@@ -914,8 +960,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"]
|
||||
@@ -925,8 +973,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)
|
||||
@@ -946,9 +996,22 @@ static Class NSNullK;
|
||||
currentUser = nil;
|
||||
}
|
||||
else
|
||||
[self _retainUser: currentUser
|
||||
withLogin: cacheUid];
|
||||
}
|
||||
{
|
||||
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)
|
||||
{
|
||||
cacheUid = [NSString stringWithFormat: @"%@@%@", cacheUid, [currentUser objectForKey: @"c_domain"]];
|
||||
[currentUser setObject: [NSNumber numberWithBool: YES] forKey: @"DomainLessLogin"];
|
||||
}
|
||||
|
||||
[self _retainUser: currentUser withLogin: cacheUid];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user