See ChangeLog

Monotone-Parent: c0fdc871e5cf2faadbed16ce1c4275647d0928b4
Monotone-Revision: 178cf4e5311729ac333305676b5ad2aa35a7ca71

Monotone-Author: flachapelle@inverse.ca
Monotone-Date: 2011-06-24T19:19:50
Monotone-Branch: ca.inverse.sogo
maint-2.0.2
Francis Lachapelle 2011-06-24 19:19:50 +00:00
parent abbffe7740
commit f44212f0e6
19 changed files with 462 additions and 107 deletions

View File

@ -1,3 +1,50 @@
2011-06-24 Francis Lachapelle <flachapelle@inverse.ca>
* SoObjects/SOGo/SOGoSystemDefaults.m (-loginDomains): new method
that returns the content of the defaults key SOGoLoginDomains, which
is a list of domains that should be selectable from the Web login page.
(-visibleDomainsForDomain:): new method that returns a list of
domains visible from the specified domain and defined by the
defaults key SOGoDomainsVisibility, which is a list of lists of domains.
* SoObjects/SOGo/SQLSource.m
(-_lookupContactEntry:considerEmail:): when an IMAP login field is
defined, only consider the value from the table if it's not null.
* SoObjects/SOGo/SOGoSession.m
(+decodeValue:usingKey:login:domain:password:): now accepts the
form login@domain. The domain must be part of the SOGoLoginDomains.
* SoObjects/SOGo/SOGoUserManager.m
(-getImapLoginForUID:inDomain:): the method now accepts the
user's domain.
(_sourceCheckLogin:andPassword:domain:perr:expire:grace:): idem.
(checkLogin:password:domain:perr:expire:grace:): idem.
(_fillContactInfosForUser:withUIDorEmail:inDomain:): idem.
(-contactInfosForUserWithUIDorEmail:inDomain:): idem.
(-contactInfosForUserWithUIDorEmail:): now accepts the form login@domain.
* SoObjects/SOGo/SOGoWebAuthenticator.m (-checkCredentials:):
perform the authentication in a domain when specified in the
web session.
* SoObjects/Contacts/SOGoContactFolders.m (-appendSystemSources):
when using domains, append addressbooks from visible domains.
* SoObjects/SOGo/SOGoUser.m (-initWithLogin:roles:trust:): now
accepts the form login@domain.
(-loginInDomain): new method. When bound to a domain, it returns
the username part of the login.
* UI/MainUI/SOGoUserHomePage.m (-_usersForResults:inDomain:): was
_usersResponseForResults:. Now returns only an array
containing the matching users.
(-usersSearchAction): added the results from the visible domains,
if the defaults key SOGoDomainsVisibility is defined.
* UI/MainUI/SOGoRootPage.m (-connectAction): a domain from the
defaults key SOGoLoginDomains can now be received.
2011-06-23 Wolfgang Sourdeau <wsourdeau@inverse.ca>
* OpenChange/MAPIStoreTypes.h: removed PRIx64 definitions, that

View File

@ -40,6 +40,7 @@
#import <SOGo/SOGoUser.h>
#import <SOGo/SOGoUserDefaults.h>
#import <SOGo/SOGoUserManager.h>
#import <SOGo/SOGoSystemDefaults.h>
#import <SOGo/WORequest+SOGo.h>
#import "SOGoContactGCSFolder.h"
@ -62,7 +63,8 @@
- (NSException *) appendSystemSources
{
SOGoUserManager *um;
NSEnumerator *sourceIDs;
SOGoSystemDefaults *sd;
NSEnumerator *sourceIDs, *domains;
NSString *currentSourceID, *srcDisplayName, *domain;
SOGoContactSourceFolder *currentFolder;
SOGoUser *currentUser;
@ -75,18 +77,24 @@
{
domain = [currentUser domain];
um = [SOGoUserManager sharedUserManager];
sourceIDs = [[um addressBookSourceIDsInDomain: domain]
objectEnumerator];
while ((currentSourceID = [sourceIDs nextObject]))
sd = [SOGoSystemDefaults sharedSystemDefaults];
domains = [[sd visibleDomainsForDomain: domain] objectEnumerator];
while (domain)
{
srcDisplayName
= [um displayNameForSourceWithID: currentSourceID];
currentFolder = [SOGoContactSourceFolder
folderWithName: currentSourceID
andDisplayName: srcDisplayName
inContainer: self];
[currentFolder setSource: [um sourceWithID: currentSourceID]];
[subFolders setObject: currentFolder forKey: currentSourceID];
sourceIDs = [[um addressBookSourceIDsInDomain: domain]
objectEnumerator];
while ((currentSourceID = [sourceIDs nextObject]))
{
srcDisplayName
= [um displayNameForSourceWithID: currentSourceID];
currentFolder = [SOGoContactSourceFolder
folderWithName: currentSourceID
andDisplayName: srcDisplayName
inContainer: self];
[currentFolder setSource: [um sourceWithID: currentSourceID]];
[subFolders setObject: currentFolder forKey: currentSourceID];
}
domain = [domains nextObject];
}
}
}

View File

@ -3,6 +3,7 @@
* Copyright (C) 2010-2011 Inverse inc.
*
* Author: Ludovic Marcotte <lmarcotte@inverse.ca>
* Francis Lachapelle <flachapelle@inverse.ca>
*
* 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
@ -40,6 +41,7 @@
+ (void) decodeValue: (NSString *) theValue
usingKey: (NSString *) theKey
login: (NSString **) theLogin
domain: (NSString **) theDomain
password: (NSString **) thePassword;
@end

View File

@ -3,6 +3,8 @@
* Copyright (C) 2010-2011 Inverse inc.
*
* Author: Ludovic Marcotte <lmarcotte@inverse.ca>
* Francis Lachapelle <flachapelle@inverse.ca>
*
* 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
@ -24,6 +26,7 @@
#include "SOGoCache.h"
#import <Foundation/NSArray.h>
#import <Foundation/NSData.h>
#import <Foundation/NSDictionary.h>
@ -38,6 +41,8 @@
#include <fcntl.h>
#include <unistd.h>
#import "SOGoSystemDefaults.h"
@implementation SOGoSession
+ (NSString *) valueForSessionKey: (NSString *) theSessionKey
@ -221,16 +226,24 @@
return s;
}
//
//
//
/**
*
* @param theValue
* @param theKey
* @param theLogin
* @param theDomain
* @param thePassword
* @see [SOGoUser initWithLogin:roles:trust:]
*/
+ (void) decodeValue: (NSString *) theValue
usingKey: (NSString *) theKey
login: (NSString **) theLogin
domain: (NSString **) theDomain
password: (NSString **) thePassword
{
NSString *decodedValue;
NSRange r;
SOGoSystemDefaults *sd;
decodedValue = [SOGoSession valueFromSecuredValue: theValue
usingKey: theKey];
@ -238,6 +251,21 @@
r = [decodedValue rangeOfString: @":"];
*theLogin = [decodedValue substringToIndex: r.location];
*thePassword = [decodedValue substringFromIndex: r.location+1];
r = [*theLogin rangeOfString: @"@" options: NSBackwardsSearch];
if (r.location != NSNotFound)
{
// The domain is probably appended to the username;
// make sure it is defined as a login domain in the configuration.
sd = [SOGoSystemDefaults sharedSystemDefaults];
*theDomain = [*theLogin substringFromIndex: (r.location + r.length)];
if ([[sd loginDomains] containsObject: *theDomain])
*theLogin = [*theLogin substringToIndex: r.location];
else
*theDomain = nil;
}
else
*theDomain = nil;
}
@end

View File

@ -1,8 +1,9 @@
/* SOGoSystemDefaults.h - this file is part of SOGo
*
* Copyright (C) 2009-2010 Inverse inc.
* Copyright (C) 2009-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Francis Lachapelle <flachapelle@inverse.ca>
*
* 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
@ -26,10 +27,15 @@
#import <SOGo/SOGoDomainDefaults.h>
@interface SOGoSystemDefaults : SOGoDomainDefaults
{
NSArray *loginDomains;
}
+ (SOGoSystemDefaults *) sharedSystemDefaults;
- (NSArray *) domainIds;
- (NSArray *) loginDomains;
- (NSArray *) visibleDomainsForDomain: (NSString *) domain;
- (BOOL) crashOnSessionCreate;
- (BOOL) debugRequests;

View File

@ -1,8 +1,9 @@
/* SOGoSystemDefaults.m - this file is part of SOGo
*
* Copyright (C) 2009-2010 Inverse inc.
* Copyright (C) 2009-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Francis Lachapelle <flachapelle@inverse.ca>
*
* 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
@ -23,13 +24,15 @@
#import <dlfcn.h>
#import <unistd.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSBundle.h>
#import <Foundation/NSFileManager.h>
#import <Foundation/NSString.h>
#import <Foundation/NSFileManager.h>
#import <Foundation/NSUserDefaults.h>
#import <NGExtensions/NSObject+Logs.h>
#import "NSArray+Utilities.h"
#import "NSDictionary+Utilities.h"
#import "SOGoStartupLogger.h"
@ -152,6 +155,22 @@ BootstrapNSUserDefaults ()
return sharedSystemDefaults;
}
- (id) init
{
if ((self = [super init]))
{
loginDomains = nil;
}
return self;
}
- (void) dealloc
{
[loginDomains release];
[super dealloc];
}
- (BOOL) migrate
{
static NSDictionary *migratedKeys = nil;
@ -174,6 +193,61 @@ BootstrapNSUserDefaults ()
return [[self dictionaryForKey: @"domains"] allKeys];
}
- (NSArray *) loginDomains
{
NSMutableArray *filteredLoginDomains;
NSArray *domains;
NSEnumerator *objects;
id currentObject;
if (self->loginDomains == nil)
{
filteredLoginDomains = [NSMutableArray arrayWithArray: [self stringArrayForKey: @"SOGoLoginDomains"]];
domains = [self domainIds];
objects = [filteredLoginDomains objectEnumerator];
while ((currentObject = [objects nextObject]))
{
if (![domains containsObject: currentObject])
{
[filteredLoginDomains removeObject: currentObject];
[self warnWithFormat: @"SOGoLoginDomains contains an invalid domain : %@", currentObject];
}
}
ASSIGN (self->loginDomains, filteredLoginDomains);
}
return self->loginDomains;
}
- (NSArray *) visibleDomainsForDomain: (NSString *) domain
{
NSMutableArray *domains;
NSArray *definedDomains, *visibleDomains, *currentGroup;
NSEnumerator *groups;
NSString *currentDomain;
definedDomains = [self domainIds];
visibleDomains = [self arrayForKey: @"SOGoDomainsVisibility"];
domains = [NSMutableArray array];
groups = [visibleDomains objectEnumerator];
while ((currentGroup = (NSArray *)[groups nextObject]))
{
if ([currentGroup containsObject: domain])
[domains addObjectsFromArray: currentGroup];
}
// Remove lookup domain from list
groups = [domains objectEnumerator];
while ((currentDomain = [groups nextObject]))
{
if ([currentDomain isEqualToString: domain])
[domains removeObject: currentDomain];
}
return [domains uniqueObjects];
}
/* System-level only */
- (BOOL) crashOnSessionCreate

View File

@ -59,7 +59,7 @@
SOGoUserSettings *_settings;
SOGoUserFolder *homeFolder;
NSString *currentPassword;
NSString *domainId;
NSString *loginInDomain;
NSString *language;
NSArray *allEmails;
NSMutableArray *mailAccounts;
@ -84,6 +84,8 @@
- (void) setCurrentPassword: (NSString *) newPassword;
- (NSString *) currentPassword;
- (NSString *) loginInDomain;
/* properties */
- (NSString *) domain;

View File

@ -122,21 +122,49 @@
return user;
}
/**
* Return a new instance for the login name, which can be appended by a
* domain name.
*
* @param newLogin a login name optionally follow by @domain
* @param newRoles
* @param b is set to YES if newLogin can be trust
* @see loginInDomain
* @see [SOGoSession decodeValue:usingKey:login:domain:password:]
*/
- (id) initWithLogin: (NSString *) newLogin
roles: (NSArray *) newRoles
trust: (BOOL) b
{
SOGoUserManager *um;
NSString *realUID;
SOGoSystemDefaults *sd;
NSString *realUID, *uid, *domain;
NSRange r;
_defaults = nil;
_settings = nil;
uid = nil;
domain = nil;
if ([newLogin isEqualToString: @"anonymous"]
|| [newLogin isEqualToString: @"freebusy"])
realUID = newLogin;
else
{
r = [newLogin 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.
sd = [SOGoSystemDefaults sharedSystemDefaults];
domain = [newLogin substringFromIndex: (r.location + r.length)];
if ([[sd domainIds] containsObject: domain])
newLogin = [newLogin substringToIndex: r.location];
else
domain = nil;
}
newLogin = [newLogin stringByReplacingString: @"%40"
withString: @"@"];
if (b)
@ -144,9 +172,19 @@
else
{
um = [SOGoUserManager sharedUserManager];
realUID = [[um contactInfosForUserWithUIDorEmail: newLogin]
realUID = [[um contactInfosForUserWithUIDorEmail: newLogin
inDomain: domain]
objectForKey: @"c_uid"];
}
if (domain)
{
// When the user is associated to a domain, the [SOGoUser login]
// method returns the combination login@domain while
// [SOGoUser loginInDomain] only returns the login.
uid = [NSString stringWithString: realUID];
realUID = [NSString stringWithFormat: @"%@@%@", realUID, domain];
}
}
if ([realUID length])
@ -156,6 +194,7 @@
allEmails = nil;
currentPassword = nil;
cn = nil;
ASSIGN (loginInDomain, (uid ? uid : realUID));
_defaults = nil;
_domainDefaults = nil;
_settings = nil;
@ -180,6 +219,7 @@
[mailAccounts release];
[currentPassword release];
[cn release];
[loginInDomain release];
[language release];
[super dealloc];
}
@ -199,6 +239,11 @@
return currentPassword;
}
- (NSString *) loginInDomain
{
return loginInDomain;
}
- (id) _fetchFieldForUser: (NSString *) field
{
NSDictionary *contactInfos;
@ -518,7 +563,8 @@
// 1. login
imapLogin = [[SOGoUserManager sharedUserManager]
getImapLoginForUID: login];
getImapLoginForUID: [self loginInDomain]
inDomain: [self domain]];
[mailAccount setObject: imapLogin forKey: @"userName"];
// 2. server

View File

@ -1,8 +1,9 @@
/* SOGoUserManager.h - this file is part of SOGo
*
* Copyright (C) 2007-2010 Inverse inc.
* Copyright (C) 2007-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Francis Lachapelle <flachapelle@inverse.ca>
*
* 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
@ -65,6 +66,8 @@
- (NSDictionary *) metadataForSourceID: (NSString *) sourceID;
- (NSString *) displayNameForSourceWithID: (NSString *) sourceID;
- (NSDictionary *) contactInfosForUserWithUIDorEmail: (NSString *) uid;
- (NSDictionary *) contactInfosForUserWithUIDorEmail: (NSString *) uid
inDomain: (NSString *) domain;
- (NSArray *) fetchContactsMatching: (NSString *) match
inDomain: (NSString *) domain;
- (NSArray *) fetchUsersMatching: (NSString *) filter
@ -73,17 +76,20 @@
- (NSString *) getCNForUID: (NSString *) uid;
- (NSString *) getEmailForUID: (NSString *) uid;
- (NSString *) getFullEmailForUID: (NSString *) uid;
- (NSString *) getImapLoginForUID: (NSString *) uid;
- (NSString *) getImapLoginForUID: (NSString *) uid
inDomain: (NSString *) domain;
- (NSString *) getUIDForEmail: (NSString *) email;
- (NSString *) getLoginForDN: (NSString *) theDN;
- (BOOL) checkLogin: (NSString *) _login
password: (NSString *) _pwd
domain: (NSString *) _domain
perr: (SOGoPasswordPolicyError *) _perr
expire: (int *) _expire
grace: (int *) _grace;
- (BOOL) changePasswordForLogin: (NSString *) login
inDomain: (NSString *) domain
oldPassword: (NSString *) oldPassword
newPassword: (NSString *) newPassword
perr: (SOGoPasswordPolicyError *) perr;

View File

@ -3,6 +3,7 @@
* Copyright (C) 2007-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Francis Lachapelle <flachapelle@inverse.ca>
*
* 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
@ -27,6 +28,7 @@
#import <Foundation/NSString.h>
#import <Foundation/NSTimer.h>
#import <Foundation/NSValue.h>
#import <NGExtensions/NSNull+misc.h>
#import <NGExtensions/NSObject+Logs.h>
#import "NSArray+Utilities.h"
@ -335,14 +337,15 @@
}
- (NSString *) getImapLoginForUID: (NSString *) uid
inDomain: (NSString *) domain
{
NSDictionary *contactInfos;
NSString *domain, *login;
NSString *login;
SOGoDomainDefaults *dd;
contactInfos = [self contactInfosForUserWithUIDorEmail: uid];
contactInfos = [self contactInfosForUserWithUIDorEmail: uid
inDomain: domain];
login = [contactInfos objectForKey: @"c_imaplogin"];
domain = [contactInfos objectForKey: @"c_domain"];
if (login == nil)
{
if ([domain length])
@ -366,6 +369,7 @@
}
- (BOOL) _sourceChangePasswordForLogin: (NSString *) login
inDomain: (NSString *) domain
oldPassword: (NSString *) oldPassword
newPassword: (NSString *) newPassword
perr: (SOGoPasswordPolicyError *) perr
@ -377,14 +381,14 @@
didChange = NO;
authIDs = [[self authenticationSourceIDsInDomain: nil] objectEnumerator];
authIDs = [[self authenticationSourceIDsInDomain: domain] objectEnumerator];
while (!didChange && (currentID = [authIDs nextObject]))
{
sogoSource = [_sources objectForKey: currentID];
didChange = [sogoSource changePasswordForLogin: login
oldPassword: oldPassword
newPassword: newPassword
perr: perr];
oldPassword: oldPassword
newPassword: newPassword
perr: perr];
}
return didChange;
@ -392,9 +396,10 @@
- (BOOL) _sourceCheckLogin: (NSString *) login
andPassword: (NSString *) password
perr: (SOGoPasswordPolicyError *) perr
expire: (int *) expire
grace: (int *) grace
domain: (NSString *) domain
perr: (SOGoPasswordPolicyError *) perr
expire: (int *) expire
grace: (int *) grace
{
NSObject <SOGoSource> *sogoSource;
NSEnumerator *authIDs;
@ -403,7 +408,7 @@
checkOK = NO;
authIDs = [[self authenticationSourceIDsInDomain: nil] objectEnumerator];
authIDs = [[self authenticationSourceIDsInDomain: domain] objectEnumerator];
while (!checkOK && (currentID = [authIDs nextObject]))
{
sogoSource = [_sources objectForKey: currentID];
@ -419,18 +424,23 @@
- (BOOL) checkLogin: (NSString *) _login
password: (NSString *) _pwd
domain: (NSString *) _domain
perr: (SOGoPasswordPolicyError *) _perr
expire: (int *) _expire
grace: (int *) _grace
{
NSString *dictPassword, *jsonUser;
NSString *dictPassword, *username, *jsonUser;
NSMutableDictionary *currentUser;
BOOL checkOK;
// 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.
jsonUser = [[SOGoCache sharedCache] userAttributesForLogin: _login];
if (_domain)
username = [NSString stringWithFormat: @"%@@%@", _login, _domain];
else
username = _login;
jsonUser = [[SOGoCache sharedCache] userAttributesForLogin: username];
currentUser = [jsonUser objectFromJSONString];
dictPassword = [currentUser objectForKey: @"password"];
if (currentUser && dictPassword)
@ -439,10 +449,11 @@
//NSLog(@"Password cache hit for user %@", _login);
}
else if ([self _sourceCheckLogin: _login
andPassword: _pwd
perr: _perr
expire: _expire
grace: _grace])
andPassword: _pwd
domain: _domain
perr: _perr
expire: _expire
grace: _grace])
{
checkOK = YES;
if (!currentUser)
@ -458,7 +469,7 @@
[currentUser setObject: [_pwd asSHA1String] forKey: @"password"];
[[SOGoCache sharedCache]
setUserAttributes: [currentUser jsonRepresentation]
forLogin: _login];
forLogin: username];
}
else
checkOK = NO;
@ -473,19 +484,20 @@
sources = [[_sources allValues] objectEnumerator];
while ((currentSource = [sources nextObject]))
if ([currentSource conformsToProtocol: @protocol(SOGoDNSource)] &&
[currentSource bindAsCurrentUser] &&
[currentSource lookupDNByLogin: _login])
{
[currentSource setBindDN: [currentSource lookupDNByLogin: _login]];
[currentSource setBindPassword: _pwd];
}
if ([currentSource conformsToProtocol: @protocol(SOGoDNSource)] &&
[currentSource bindAsCurrentUser] &&
[currentSource lookupDNByLogin: _login])
{
[currentSource setBindDN: [currentSource lookupDNByLogin: _login]];
[currentSource setBindPassword: _pwd];
}
}
return checkOK;
}
- (BOOL) changePasswordForLogin: (NSString *) login
inDomain: (NSString *) domain
oldPassword: (NSString *) oldPassword
newPassword: (NSString *) newPassword
perr: (SOGoPasswordPolicyError *) perr
@ -499,9 +511,10 @@
dictPassword = [currentUser objectForKey: @"password"];
if ([self _sourceChangePasswordForLogin: login
oldPassword: oldPassword
newPassword: newPassword
perr: perr])
inDomain: domain
oldPassword: oldPassword
newPassword: newPassword
perr: perr])
{
didChange = YES;
@ -553,6 +566,7 @@
//
- (void) _fillContactInfosForUser: (NSMutableDictionary *) currentUser
withUIDorEmail: (NSString *) uid
inDomain: (NSString *) domain
{
NSMutableArray *emails;
NSDictionary *userEntry;
@ -574,7 +588,7 @@
[currentUser setObject: [NSNumber numberWithBool: YES]
forKey: @"MailAccess"];
sogoSources = [[self authenticationSourceIDsInDomain: nil]
sogoSources = [[self authenticationSourceIDsInDomain: domain]
objectEnumerator];
while ((sourceID = [sogoSources nextObject]))
{
@ -642,12 +656,17 @@
// associated with email addresses.
//
- (void) _retainUser: (NSDictionary *) newUser
withLogin: (NSString *) login
{
NSEnumerator *emails;
NSString *key;
[[SOGoCache sharedCache]
setUserAttributes: [newUser jsonRepresentation]
forLogin: login];
key = [newUser objectForKey: @"c_uid"];
if (key)
if (key && ![key isEqualToString: login])
[[SOGoCache sharedCache]
setUserAttributes: [newUser jsonRepresentation]
forLogin: key];
@ -680,10 +699,49 @@
return user;
}
/**
*
* @see [SOGoUser initWithLogin:roles:trust:]
*/
- (NSDictionary *) contactInfosForUserWithUIDorEmail: (NSString *) uid
{
NSRange r;
NSString *username, *domain;
NSDictionary *infos;
SOGoSystemDefaults *sd;
domain = nil;
infos = nil;
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.
sd = [SOGoSystemDefaults sharedSystemDefaults];
domain = [uid substringFromIndex: (r.location + r.length)];
if ([[sd domainIds] containsObject: domain])
username = [uid substringToIndex: r.location];
else
domain = nil;
}
if (domain != nil)
infos = [self contactInfosForUserWithUIDorEmail: username
inDomain: domain];
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];
return infos;
}
- (NSDictionary *) contactInfosForUserWithUIDorEmail: (NSString *) uid
inDomain: (NSString *) domain
{
NSMutableDictionary *currentUser;
NSString *aUID, *jsonUser;
NSString *aUID, *cacheUid, *jsonUser;
BOOL newUser;
if ([uid isEqualToString: @"anonymous"])
@ -692,7 +750,11 @@
{
// Remove the "@" prefix used to identified groups in the ACL tables.
aUID = [uid hasPrefix: @"@"] ? [uid substringFromIndex: 1] : uid;
jsonUser = [[SOGoCache sharedCache] userAttributesForLogin: aUID];
if (domain)
cacheUid = [NSString stringWithFormat: @"%@@%@", aUID, domain];
else
cacheUid = aUID;
jsonUser = [[SOGoCache sharedCache] userAttributesForLogin: cacheUid];
currentUser = [jsonUser objectFromJSONString];
if (!([currentUser objectForKey: @"emails"]
&& [currentUser objectForKey: @"cn"]))
@ -711,11 +773,13 @@
else
newUser = NO;
[self _fillContactInfosForUser: currentUser
withUIDorEmail: aUID];
withUIDorEmail: aUID
inDomain: domain];
if (newUser)
{
if ([[currentUser objectForKey: @"c_uid"] length] > 0)
[self _retainUser: currentUser];
[self _retainUser: currentUser
withLogin: cacheUid];
else
currentUser = nil;
}

View File

@ -1,9 +1,10 @@
/* SOGoWebAuthenticator.h - this file is part of SOGo
*
* Copyright (C) 2007-2010 Inverse inc.
* Copyright (C) 2007-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Ludovic Marcotte <lmarcotte@inverse.ca>
* Francis Lachapelle <flachapelle@inverse.ca>
*
* 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
@ -39,6 +40,7 @@
- (BOOL) checkLogin: (NSString *) _login
password: (NSString *) _pwd
domain: (NSString *) _domain
perr: (SOGoPasswordPolicyError *) _perr
expire: (int *) _expire
grace: (int *) _grace;

View File

@ -3,6 +3,7 @@
* Copyright (C) 2007-2011 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
* Francis Lachapelle <flachapelle@inverse.ca>
*
* 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
@ -64,7 +65,7 @@
- (BOOL) checkLogin: (NSString *) _login
password: (NSString *) _pwd
{
NSString *username, *password, *value;
NSString *username, *domain, *password, *value;
SOGoPasswordPolicyError perr;
int expire, grace;
@ -83,19 +84,22 @@
return NO;
[SOGoSession decodeValue: value
usingKey: _login
login: &username
password: &password];
usingKey: _login
login: &username
domain: &domain
password: &password];
return [self checkLogin: username
password: password
perr: &perr
expire: &expire
grace: &grace];
password: password
domain: domain
perr: &perr
expire: &expire
grace: &grace];
}
- (BOOL) checkLogin: (NSString *) _login
password: (NSString *) _pwd
domain: (NSString *) _domain
perr: (SOGoPasswordPolicyError *) _perr
expire: (int *) _expire
grace: (int *) _grace
@ -116,10 +120,11 @@
}
else
rc = [[SOGoUserManager sharedUserManager] checkLogin: _login
password: _pwd
perr: _perr
expire: _expire
grace: _grace];
password: _pwd
domain: _domain
perr: _perr
expire: _expire
grace: _grace];
//[self logWithFormat: @"Checked login with ppolicy enabled: %d %d %d", *_perr, *_expire, *_grace];
@ -159,12 +164,13 @@
creds = [self parseCredentials: auth];
if ([creds count] > 1)
{
NSString *login;
NSString *login, *domain;
[SOGoSession decodeValue: [SOGoSession valueForSessionKey: [creds objectAtIndex: 1]]
usingKey: [creds objectAtIndex: 0]
login: &login
password: &password];
usingKey: [creds objectAtIndex: 0]
login: &login
domain: &domain
password: &password];
}
else
password = nil;
@ -178,7 +184,7 @@
//
- (NSString *) checkCredentials: (NSString *)_creds
{
NSString *login, *pwd, *userKey, *sessionKey;
NSString *login, *domain, *pwd, *userKey, *sessionKey;
NSArray *creds;
SOGoPasswordPolicyError perr;
@ -194,17 +200,22 @@
sessionKey = [creds objectAtIndex:1];
[SOGoSession decodeValue: [SOGoSession valueForSessionKey: sessionKey]
usingKey: userKey
login: &login
password: &pwd];
usingKey: userKey
login: &login
domain: &domain
password: &pwd];
if (![self checkLogin: login
password: pwd
perr: &perr
expire: &expire
grace: &grace])
password: pwd
domain: domain
perr: &perr
expire: &expire
grace: &grace])
return nil;
if (domain)
login = [NSString stringWithFormat: @"%@@%@", login, domain];
return login;
}

View File

@ -28,6 +28,7 @@
#import <Foundation/NSValue.h>
#import <Foundation/NSURL.h>
#import <NGExtensions/NSNull+misc.h>
#import <NGExtensions/NSObject+Logs.h>
#import <GDLContentStore/GCSChannelManager.h>
@ -464,7 +465,7 @@
// We check if we should use a different login for IMAP
if (_imapLoginField)
{
if ([response objectForKey: _imapLoginField])
if ([[response objectForKey: _imapLoginField] isNotNull])
[response setObject: [response objectForKey: _imapLoginField] forKey: @"c_imaplogin"];
}

View File

@ -4,6 +4,7 @@
"Username:" = "Username:";
"Password:" = "Password:";
"Domain:" = "Domain:";
"Connect" = "Connect";

View File

@ -4,6 +4,7 @@
"Username:" = "Nom d'utilisateur :";
"Password:" = "Mot de passe :";
"Domain:" = "Domaine :";
"Connect" = "Connexion";

View File

@ -1,6 +1,6 @@
/*
Copyright (C) 2006-2010 Inverse inc.
Copyright (C) 2006-2011 Inverse inc.
Copyright (C) 2004-2005 SKYRIX Software AG
This file is part of SOGo.
@ -149,7 +149,7 @@
SOGoAppointmentFolders *calendars;
SOGoUserDefaults *ud;
SOGoUser *loggedInUser;
NSString *username, *password, *language;
NSString *username, *password, *language, *domain;
NSArray *supportedLanguages;
SOGoPasswordPolicyError err;
@ -165,8 +165,9 @@
username = [request formValueForKey: @"userName"];
password = [request formValueForKey: @"password"];
language = [request formValueForKey: @"language"];
domain = [request formValueForKey: @"domain"];
if ((b = [auth checkLogin: username password: password
if ((b = [auth checkLogin: username password: password domain: domain
perr: &err expire: &expire grace: &grace])
&& (err == PolicyNoError)
// no password policy
@ -178,16 +179,18 @@
[self logWithFormat: @"successful login for user '%@' - expire = %d grace = %d", username, expire, grace];
json = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt: expire], @"expire",
[NSNumber numberWithInt: grace], @"grace", nil];
[NSNumber numberWithInt: grace], @"grace", nil];
response = [self responseWithStatus: 200
andJSONRepresentation: json];
if ([domain isNotNull])
username = [NSString stringWithFormat: @"%@@%@", username, domain];
authCookie = [self _cookieWithUsername: username
andPassword: password
forAuthenticator: auth];
andPassword: password
forAuthenticator: auth];
[response addCookie: authCookie];
supportedLanguages = [[SOGoSystemDefaults sharedSystemDefaults]
@ -376,6 +379,16 @@
return ([[self loginSuffix] length]);
}
- (NSArray *) loginDomains
{
return [[SOGoSystemDefaults sharedSystemDefaults] loginDomains];
}
- (BOOL) hasLoginDomains
{
return ([[self loginDomains] count] > 0);
}
- (void) setItem: (id) _item
{
ASSIGN (item, _item);
@ -414,7 +427,7 @@
- (WOResponse *) changePasswordAction
{
NSString *username, *password, *newPassword, *value;
NSString *username, *domain, *password, *newPassword, *value;
SOGoUserManager *um;
SOGoPasswordPolicyError error;
WOResponse *response;
@ -434,9 +447,10 @@
creds = [auth parseCredentials: value];
[SOGoSession decodeValue: [SOGoSession valueForSessionKey: [creds objectAtIndex: 1]]
usingKey: [creds objectAtIndex: 0]
login: &username
password: &password];
usingKey: [creds objectAtIndex: 0]
login: &username
domain: &domain
password: &password];
newPassword = [message objectForKey: @"newPassword"];
@ -444,13 +458,17 @@
// This will also update the cached password in memcached.
if ([um changePasswordForLogin: username
oldPassword: password
newPassword: newPassword
perr: &error])
inDomain: domain
oldPassword: password
newPassword: newPassword
perr: &error])
{
// We delete the previous session
[SOGoSession deleteValueForSessionKey: [creds objectAtIndex: 1]];
if ([domain isNotNull])
username = [NSString stringWithFormat: @"%@@%@", username, domain];
response = [self responseWith204];
authCookie = [self _cookieWithUsername: username
andPassword: newPassword

View File

@ -317,7 +317,8 @@
return response;
}
- (WOResponse *) _usersResponseForResults: (NSArray *) users
- (NSMutableArray *) _usersForResults: (NSArray *) users
inDomain: (NSString *) domain
{
NSString *uid;
NSDictionary *contact;
@ -325,8 +326,10 @@
NSMutableArray *jsonResponse, *jsonLine;
NSArray *allUsers;
int count, max;
BOOL activeUserIsInDomain;
login = [[context activeUser] login];
activeUserIsInDomain = (domain == nil || [[[context activeUser] domain] isEqualToString: domain]);
// We sort our array - this is pretty useful for the Web
// interface of SOGo.
@ -341,9 +344,11 @@
uid = [contact objectForKey: @"c_uid"];
// We do NOT return the current authenticated user
if (![uid isEqualToString: login])
if (!activeUserIsInDomain || ![uid isEqualToString: login])
{
jsonLine = [NSMutableArray arrayWithCapacity: 4];
if (domain)
uid = [NSString stringWithFormat: @"%@@%@", uid, domain];
[jsonLine addObject: uid];
[jsonLine addObject: [contact objectForKey: @"cn"]];
[jsonLine addObject: [contact objectForKey: @"c_email"]];
@ -354,24 +359,41 @@
}
}
return [self responseWithStatus: 200
andJSONRepresentation: jsonResponse];
return jsonResponse;
}
- (id <WOActionResults>) usersSearchAction
{
NSMutableArray *users;
NSArray *currentUsers;
NSString *contact, *domain;
NSEnumerator *visibleDomains;
id <WOActionResults> result;
SOGoUserManager *um;
SOGoSystemDefaults *sd;
um = [SOGoUserManager sharedUserManager];
contact = [self queryParameterForKey: @"search"];
if ([contact length])
{
domain = [[context activeUser] domain];
result
= [self _usersResponseForResults: [um fetchUsersMatching: contact
inDomain: domain]];
users = [self _usersForResults: [um fetchUsersMatching: contact
inDomain: domain]
inDomain: domain];
if (domain)
{
// Add results from visible domains
sd = [SOGoSystemDefaults sharedSystemDefaults];
visibleDomains = [[sd visibleDomainsForDomain: domain] objectEnumerator];
while ((domain = [visibleDomains nextObject]))
{
currentUsers = [self _usersForResults: [um fetchUsersMatching: contact
inDomain: domain]
inDomain: domain];
[users addObjectsFromArray: currentUsers];
}
}
result = [self responseWithStatus: 200 andJSONRepresentation: users];
}
else
result = [NSException exceptionWithHTTPStatus: 400

View File

@ -51,6 +51,16 @@
string="languageText"
label:noSelectionString="choose"
/></label>
<var:if condition="hasLoginDomains">
<label><var:string label:value="Domain:"/><br/>
<var:popup const:id="domain" const:name="domain"
list="loginDomains"
item="item"
var:selection="item"
var:value="item"
string="item"
/></label>
</var:if>
<label>
<a href="#" class="button" id="submit" name="submit">
<span><var:string label:value="Connect" /></span></a>

View File

@ -46,7 +46,7 @@ function onFieldKeyDown(event) {
if (event.keyCode == Event.KEY_RETURN) {
if ($("password").value.length > 0
&& $("userName").value.length > 0)
return onLoginClick (event);
return onLoginClick(event);
else
Event.stop(event);
} else if (IsCharacterKey(event.keyCode)
@ -60,6 +60,7 @@ function onLoginClick(event) {
var userName = userNameField.value;
var password = $("password").value;
var language = $("language");
var domain = $("domain");
if (userName.length > 0 && password.length > 0) {
this.disabled = true;
@ -77,6 +78,8 @@ function onLoginClick(event) {
parameters += ((language.value == "WONoSelectionString")
? ""
: ("&language=" + language.value));
if (domain)
parameters += "&domain=" + domain.value;
/// Discarded as it seems to create a cookie for nothing. To discard
// a cookie in JS, have a look here: http://www.quirksmode.org/js/cookies.html
//document.cookie = "";\
@ -138,7 +141,10 @@ function onLoginCallback(http) {
function redirectToUserPage() {
// Redirect to proper page
var userName = $("userName").value;
if (typeof(loginSuffix) != "undefined"
var domain = $("domain");
if (domain)
userName += '@' + domain.value;
else if (typeof(loginSuffix) != "undefined"
&& loginSuffix.length > 0
&& !userName.endsWith(loginSuffix))
userName += loginSuffix;