diff --git a/ChangeLog b/ChangeLog index 75933372a..c82436dfe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2011-10-26 Francis Lachapelle + + * SoObjects/SOGo/SQLSource.m + (-checkLogin:password:perr:expire:grace:): authentication can be + performed against any database column defined in the new + LoginFieldNames defaults parameter. + (-_lookupContactEntry:considerEmail:): idem. + 2011-10-26 Wolfgang Sourdeau * OpenChange/MAPIStoreMessage.m @@ -14,6 +22,13 @@ * OpenChange/MAPIStoreSOGo.m (sogo_message_create_attachment): implemented new backend method. +2011-10-25 Francis Lachapelle + + * UI/MainUI/SOGoRootPage.m (-cookieUsername) + (-cookieWithUsername:): getter/setter for the new SOGoLogin + cookie. This is used for the new "Remember username" checkbox that + appears on the login page. + 2011-10-25 Wolfgang Sourdeau * OpenChange/EOQualifier+MAPIFS.[hm]: now evaluates diff --git a/Documentation/SOGo Mobile Devices Configuration.odt b/Documentation/SOGo Mobile Devices Configuration.odt index 8a8050722..5633f5b1e 100644 Binary files a/Documentation/SOGo Mobile Devices Configuration.odt and b/Documentation/SOGo Mobile Devices Configuration.odt differ diff --git a/Documentation/SOGo Mozilla Thunderbird Configuration.odt b/Documentation/SOGo Mozilla Thunderbird Configuration.odt index 1e1aa9095..e12afbb7a 100644 Binary files a/Documentation/SOGo Mozilla Thunderbird Configuration.odt and b/Documentation/SOGo Mozilla Thunderbird Configuration.odt differ diff --git a/NEWS b/NEWS index e06320478..68181e95a 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -2.0-20111004 (2.0.0beta1 - branched from upcoming v1.3.9) +1.3-201110DD (1.3.9) --------------------- New Features - new user defaults SOGoDefaultCalendar to specify which calendar is used when @@ -7,11 +7,26 @@ New Features automatically added to the free-busy information - new indicator in the link banner when a vacation message (auto-reply) is active - new snooze function for events alarms in Web interface + - new "Remember login" checkbox on the login page + - authentication with SQL sources can now be performed on any database column + using the new LoginFieldNames parameter Enhancements + - added support for the CalDAV move operation - phone numbers in the contacts web module are now links (tel:) - revamp of the modules link banner (15-pixel taller) - updated CKEditor to version 3.6.2 + - updated unread and flagged icons in Webmail module + - new dependency on GNUstep 1.23 + +Bug Fixes + - fixed support for Apple iOS 5 + - fixed handling of untagged IMAP responses + - fixed handling of commas in email addresses when composing a message + - fixed creation of clickable links for URLs surrounded by square brackets + - fixed behaviour of combo box for contacts categories + - fixed Swedish translation classes + - fixed bug when setting no ACL on a calendar 1.3-20110726 (1.3.8b) --------------------- diff --git a/OGoContentStore/contact-oracle.ocs b/OGoContentStore/contact-oracle.ocs index e0e8931f4..6028f9ed2 100644 --- a/OGoContentStore/contact-oracle.ocs +++ b/OGoContentStore/contact-oracle.ocs @@ -90,7 +90,7 @@ allowsNull = YES; }, { - columnName = c_telephoneNumber; + columnName = c_telephonenumber; sqlType = "VARCHAR2(255)"; allowsNull = YES; }, diff --git a/SoObjects/SOGo/SOGoUserManager.m b/SoObjects/SOGo/SOGoUserManager.m index 7113769c8..6d5e1415e 100644 --- a/SoObjects/SOGo/SOGoUserManager.m +++ b/SoObjects/SOGo/SOGoUserManager.m @@ -761,7 +761,7 @@ else cacheUid = aUID; jsonUser = [[SOGoCache sharedCache] userAttributesForLogin: cacheUid]; - currentUser = [jsonUser objectFromJSONString]; + currentUser = [jsonUser objectFromJSONString]; if (!([currentUser objectForKey: @"emails"] && [currentUser objectForKey: @"cn"])) { diff --git a/SoObjects/SOGo/SQLSource.h b/SoObjects/SOGo/SQLSource.h index c7ce6a35e..0ef15250f 100644 --- a/SoObjects/SOGo/SQLSource.h +++ b/SoObjects/SOGo/SQLSource.h @@ -38,6 +38,7 @@ NSString *_sourceID; NSString *_domain; NSString *_authenticationFilter; + NSArray *_loginFields; NSArray *_mailFields; NSString *_imapLoginField; NSString *_userPasswordAlgorithm; diff --git a/SoObjects/SOGo/SQLSource.m b/SoObjects/SOGo/SQLSource.m index 4b9f6396d..66d17fc41 100644 --- a/SoObjects/SOGo/SQLSource.m +++ b/SoObjects/SOGo/SQLSource.m @@ -81,6 +81,7 @@ { _sourceID = nil; _authenticationFilter = nil; + _loginFields = nil; _mailFields = nil; _userPasswordAlgorithm = nil; _viewURL = nil; @@ -95,6 +96,7 @@ { [_sourceID release]; [_authenticationFilter release]; + [_loginFields release]; [_mailFields release]; [_userPasswordAlgorithm release]; [_viewURL release]; @@ -111,6 +113,7 @@ ASSIGN(_sourceID, [udSource objectForKey: @"id"]); ASSIGN(_authenticationFilter, [udSource objectForKey: @"authenticationFilter"]); + ASSIGN(_loginFields, [udSource objectForKey: @"LoginFieldNames"]); ASSIGN(_mailFields, [udSource objectForKey: @"MailFieldNames"]); ASSIGN(_userPasswordAlgorithm, [udSource objectForKey: @"userPasswordAlgorithm"]); ASSIGN(_imapLoginField, [udSource objectForKey: @"IMAPLoginFieldName"]); @@ -227,9 +230,31 @@ channel = [cm acquireOpenChannelForURL: _viewURL]; if (channel) { - qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"c_uid" - operatorSelector: EOQualifierOperatorEqual - value: _login]; + if (_loginFields) + { + NSMutableArray *qualifiers; + NSString *field; + EOQualifier *loginQualifier; + int i; + + qualifiers = [NSMutableArray arrayWithCapacity: [_loginFields count]]; + for (i = 0; i < [_loginFields count]; i++) + { + field = [_loginFields objectAtIndex: i]; + loginQualifier = [[EOKeyValueQualifier alloc] initWithKey: field + operatorSelector: EOQualifierOperatorEqual + value: _login]; + [loginQualifier autorelease]; + [qualifiers addObject: loginQualifier]; + } + qualifier = [[EOOrQualifier alloc] initWithQualifierArray: qualifiers]; + } + else + { + qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"c_uid" + operatorSelector: EOQualifierOperatorEqual + value: _login]; + } [qualifier autorelease]; sql = [NSMutableString stringWithFormat: @"SELECT c_password" @" FROM %@" @@ -353,12 +378,14 @@ considerEmail: (BOOL) b { NSMutableDictionary *response; + NSMutableArray *qualifiers; EOAdaptorChannel *channel; - EOQualifier *qualifier; + EOQualifier *loginQualifier, *qualifier; GCSChannelManager *cm; NSMutableString *sql; - NSString *value; + NSString *value, *field; NSException *ex; + int i; response = nil; @@ -367,25 +394,65 @@ channel = [cm acquireOpenChannelForURL: _viewURL]; if (channel) { - if (!b) - sql = [NSMutableString stringWithFormat: (@"SELECT *" - @" FROM %@" - @" WHERE c_uid = '%@'"), - [_viewURL gcsTableName], theID]; - else - { - sql = [NSMutableString stringWithFormat: (@"SELECT *" - @" FROM %@" - @" WHERE c_uid = '%@' OR" - @" LOWER(mail) = '%@'"), - [_viewURL gcsTableName], theID, [theID lowercaseString]]; + qualifiers = [NSMutableArray arrayWithCapacity: [_loginFields count] + 1]; + + // Always compare against the c_uid field + loginQualifier = [[EOKeyValueQualifier alloc] initWithKey: @"c_uid" + operatorSelector: EOQualifierOperatorEqual + value: theID]; + [loginQualifier autorelease]; + [qualifiers addObject: loginQualifier]; + + if (_loginFields) + { + for (i = 0; i < [_loginFields count]; i++) + { + field = [_loginFields objectAtIndex: i]; + if ([field caseInsensitiveCompare: @"c_uid"] != NSOrderedSame) + { + loginQualifier = [[EOKeyValueQualifier alloc] initWithKey: field + operatorSelector: EOQualifierOperatorEqual + value: theID]; + [loginQualifier autorelease]; + [qualifiers addObject: loginQualifier]; + } + } + } + + if (b) + { + // Always compare againts the mail field + loginQualifier = [[EOKeyValueQualifier alloc] initWithKey: @"mail" + operatorSelector: EOQualifierOperatorEqual + value: [theID lowercaseString]]; + [loginQualifier autorelease]; + [qualifiers addObject: loginQualifier]; - if (_mailFields && [_mailFields count] > 0) + if (_mailFields) { - [sql appendString: [self _whereClauseFromArray: _mailFields value: [theID lowercaseString] exact: YES]]; - } + for (i = 0; i < [_mailFields count]; i++) + { + field = [_mailFields objectAtIndex: i]; + if ([field caseInsensitiveCompare: @"mail"] != NSOrderedSame + && ![_loginFields containsObject: field]) + { + loginQualifier = [[EOKeyValueQualifier alloc] initWithKey: field + operatorSelector: EOQualifierOperatorEqual + value: [theID lowercaseString]]; + [loginQualifier autorelease]; + [qualifiers addObject: loginQualifier]; + } + } + } } - + + sql = [NSMutableString stringWithFormat: @"SELECT *" + @" FROM %@" + @" WHERE ", + [_viewURL gcsTableName]]; + qualifier = [[EOOrQualifier alloc] initWithQualifierArray: qualifiers]; + [qualifier _gcsAppendToString: sql]; + ex = [channel evaluateExpressionX: sql]; if (!ex) { diff --git a/UI/MainUI/English.lproj/Localizable.strings b/UI/MainUI/English.lproj/Localizable.strings index 2cc33df23..d99d0fb23 100644 --- a/UI/MainUI/English.lproj/Localizable.strings +++ b/UI/MainUI/English.lproj/Localizable.strings @@ -5,6 +5,7 @@ "Username:" = "Username:"; "Password:" = "Password:"; "Domain:" = "Domain:"; +"Remember username" = "Remember username"; "Connect" = "Connect"; diff --git a/UI/MainUI/French.lproj/Localizable.strings b/UI/MainUI/French.lproj/Localizable.strings index 43fd8c2cc..e61648eb3 100644 --- a/UI/MainUI/French.lproj/Localizable.strings +++ b/UI/MainUI/French.lproj/Localizable.strings @@ -5,6 +5,7 @@ "Username:" = "Nom d'utilisateur :"; "Password:" = "Mot de passe :"; "Domain:" = "Domaine :"; +"Remember username" = "Se souvenir de moi"; "Connect" = "Connexion"; diff --git a/UI/MainUI/SOGoRootPage.h b/UI/MainUI/SOGoRootPage.h index 6bbad00bf..acee8c049 100644 --- a/UI/MainUI/SOGoRootPage.h +++ b/UI/MainUI/SOGoRootPage.h @@ -28,6 +28,7 @@ @interface SOGoRootPage : UIxComponent { id item; + NSString *cookieLogin; } @end diff --git a/UI/MainUI/SOGoRootPage.m b/UI/MainUI/SOGoRootPage.m index a960572ff..21d494186 100644 --- a/UI/MainUI/SOGoRootPage.m +++ b/UI/MainUI/SOGoRootPage.m @@ -58,6 +58,22 @@ @implementation SOGoRootPage +- (id) init +{ + if ((self = [super init])) + { + cookieLogin = nil; + } + + return self; +} + +- (void) dealloc +{ + [cookieLogin release]; + [super dealloc]; +} + /* accessors */ - (NSString *) connectURL @@ -65,6 +81,25 @@ return [NSString stringWithFormat: @"%@/connect", [self applicationPath]]; } +- (NSString *) cookieUsername +{ + NSString *value; + + if (cookieLogin == nil) + { + value = [[context request] cookieValueForKey: @"SOGoLogin"]; + cookieLogin = [value isNotNull]? [value stringByDecodingBase64] : @""; + [cookieLogin retain]; + } + + return cookieLogin; +} + +- (BOOL) rememberLogin +{ + return ([[self cookieUsername] length]); +} + - (WOCookie *) _cookieWithUsername: (NSString *) username andPassword: (NSString *) password forAuthenticator: (SOGoWebAuthenticator *) auth @@ -105,6 +140,32 @@ return authCookie; } +- (WOCookie *) _cookieWithUsername: (NSString *) username +{ + WOCookie *loginCookie; + NSString *appName; + NSCalendarDate *date; + + appName = [[context request] applicationName]; + if (username) + { + loginCookie = [WOCookie cookieWithName: @"SOGoLogin" + value: [username stringByEncodingBase64]]; + } + else + { + loginCookie = [WOCookie cookieWithName: @"SOGoLogin" + value: nil]; + date = [NSCalendarDate calendarDate]; + [date setTimeZone: [NSTimeZone timeZoneWithAbbreviation: @"GMT"]]; + [loginCookie setExpires: [date yesterday]]; + } + + [loginCookie setPath: [NSString stringWithFormat: @"/%@/", appName]]; + + return loginCookie; +} + - (WOCookie *) _casLocationCookie: (BOOL) cookieReset { WOCookie *locationCookie; @@ -155,7 +216,7 @@ SOGoPasswordPolicyError err; int expire, grace; - BOOL b; + BOOL rememberLogin, b; err = PolicyNoError; expire = grace = -1; @@ -166,6 +227,7 @@ username = [request formValueForKey: @"userName"]; password = [request formValueForKey: @"password"]; language = [request formValueForKey: @"language"]; + rememberLogin = [[request formValueForKey: @"rememberLogin"] boolValue]; domain = [request formValueForKey: @"domain"]; if ((b = [auth checkLogin: username password: password domain: &domain @@ -220,6 +282,11 @@ response = [self _responseWithLDAPPolicyError: err]; } + if (rememberLogin) + [response addCookie: [self _cookieWithUsername: username]]; + else + [response addCookie: [self _cookieWithUsername: nil]]; + return response; } diff --git a/UI/Templates/MainUI/SOGoRootPage.wox b/UI/Templates/MainUI/SOGoRootPage.wox index 70060a4ac..3f40b92de 100644 --- a/UI/Templates/MainUI/SOGoRootPage.wox +++ b/UI/Templates/MainUI/SOGoRootPage.wox @@ -38,7 +38,7 @@ + type="text" var:value="cookieUsername" /> @@ -61,6 +61,7 @@ string="item" /> +