From f46ebda105e94dbbc3699fe9c5070926fc8b43df Mon Sep 17 00:00:00 2001 From: Ludovic Marcotte Date: Tue, 28 Dec 2010 17:42:50 +0000 Subject: [PATCH] See ChangeLog Monotone-Parent: f5359c59c0bb008203154487db17e1ecdd274c0d Monotone-Revision: 7c78ba28d583536196a1acf34df5c96f40db238e Monotone-Author: ludovic@Sophos.ca Monotone-Date: 2010-12-28T17:42:50 Monotone-Branch: ca.inverse.sogo --- .mtn-ignore | 1 + ChangeLog | 9 + Documentation/SOGo Installation Guide.odt | Bin 148792 -> 149393 bytes Main/SOGo.m | 12 +- SOPE/GDLContentStore/GCSFolderManager.h | 5 +- SOPE/GDLContentStore/GCSFolderManager.m | 15 +- SOPE/GDLContentStore/GCSSessionsFolder.h | 56 ++++ SOPE/GDLContentStore/GCSSessionsFolder.m | 357 ++++++++++++++++++++++ SOPE/GDLContentStore/GCSSpecialQueries.h | 3 + SOPE/GDLContentStore/GCSSpecialQueries.m | 108 +++++++ SOPE/GDLContentStore/GNUmakefile | 2 + SoObjects/Mailer/SOGoMailAccount.m | 10 +- SoObjects/SOGo/GNUmakefile | 2 + SoObjects/SOGo/SOGoCache.h | 10 +- SoObjects/SOGo/SOGoCache.m | 11 +- SoObjects/SOGo/SOGoDAVAuthenticator.m | 7 +- SoObjects/SOGo/SOGoProxyAuthenticator.m | 2 +- SoObjects/SOGo/SOGoUserManager.m | 1 - SoObjects/SOGo/SOGoWebAuthenticator.m | 92 +++++- UI/MainUI/SOGoRootPage.m | 65 ++-- UI/MainUI/SOGoUserHomePage.m | 22 +- UI/WebServerResources/SOGoRootPage.js | 1 + 22 files changed, 738 insertions(+), 53 deletions(-) create mode 100644 SOPE/GDLContentStore/GCSSessionsFolder.h create mode 100644 SOPE/GDLContentStore/GCSSessionsFolder.m diff --git a/.mtn-ignore b/.mtn-ignore index 6ee6e46e5..18a9ce018 100644 --- a/.mtn-ignore +++ b/.mtn-ignore @@ -21,3 +21,4 @@ SOPE/NGCards/samples/CardGroup.m SOPE/NGCards/samples/CardVersitRenderer.m SOPE/NGCards/samples/NGCardsSaxHandler.m Tests/Integration/config.py +Tests/Integration/teststrings diff --git a/ChangeLog b/ChangeLog index deffc70bb..e0fd7a001 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2010-12-28 Ludovic Marcotte + + * Implemented secured sessions. We no longer store in the + browser's cookie the base64 encoded version of username:password + You MUST now set OCSSessionsFolderURL to a value like: + postgresql://sogo:sogo@127.0.0.1:5432/sogo/sogo_sessions_folder + and the database table will be created automatically upon + next SOGo's startup. + 2010-12-23 Ludovic Marcotte * Added the /SOGo/so//Calendar/reloadWebCalendarsAndRedirect diff --git a/Documentation/SOGo Installation Guide.odt b/Documentation/SOGo Installation Guide.odt index 251f8b5d5cdccf142d4110ff178fe135816c4d67..892f28eba15754e1c3999c001f2c87e21d7d06c9 100644 GIT binary patch delta 39975 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 + * + * 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. + */ + +#ifndef GCSSESSIONSFOLDER_H +#define GCSSESSIONSFOLDER_H + +#import + +@class NSCalendarDate; +@class NSException; +@class NSNumber; +@class NSString; + +@class GCSFolderManager; + +@interface GCSSessionsFolder : NSObject +{ + GCSFolderManager *folderManager; +} + ++ (id) sessionsFolderWithFolderManager: (GCSFolderManager *) newFolderManager; +- (void) setFolderManager: (GCSFolderManager *) newFolderManager; + +/* operations */ + +- (void) createFolderIfNotExists; +- (BOOL) canConnectStore; +- (NSDictionary *) recordForEntryWithID: (NSString *) theID; +- (void) deleteRecordForEntryWithID: (NSString *) theID; +- (void) writeRecordForEntryWithID: (NSString *) theID + value: (NSString *) theValue + creationDate: (NSCalendarDate *) theCreationDate + lastSeenDate: (NSCalendarDate *) theLastSeenDate; + +@end + +#endif /* GCSSESSIONSFOLDER_H */ diff --git a/SOPE/GDLContentStore/GCSSessionsFolder.m b/SOPE/GDLContentStore/GCSSessionsFolder.m new file mode 100644 index 000000000..08a614d92 --- /dev/null +++ b/SOPE/GDLContentStore/GCSSessionsFolder.m @@ -0,0 +1,357 @@ +/* GCSSessionsFolder.m - this file is part of SOGo + * + * Copyright (C) 2010-2011 Inverse inc. + * + * Author: Ludovic Marcotte + * + * 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 +#import +#import +#import +#import + +#import +#import + +#import +#import +#import +#import +#import + +#import "EOQualifier+GCS.h" +#import "GCSChannelManager.h" +#import "GCSFolderManager.h" +#import "GCSSpecialQueries.h" +#import "GCSStringFormatter.h" +#import "NSURL+GCS.h" + +#import "GCSSessionsFolder.h" + +static NSString *sessionsFolderURLString = nil; + +#warning GCSSessionsFolder should share a common ancestor with GCSFolder + +@implementation GCSSessionsFolder + ++ (void) initialize +{ + NSUserDefaults *ud; + + if (!sessionsFolderURLString) + { + ud = [NSUserDefaults standardUserDefaults]; + ASSIGN(sessionsFolderURLString, [ud stringForKey: @"OCSSessionsFolderURL"]); + } +} + ++ (id) sessionsFolderWithFolderManager: (GCSFolderManager *) newFolderManager +{ + GCSAlarmsFolder *newFolder; + + if (sessionsFolderURLString) + { + newFolder = [self new]; + [newFolder autorelease]; + [newFolder setFolderManager: newFolderManager]; + } + else + { + [self errorWithFormat: @"'OCSSessionsFolderURL' is not set"]; + newFolder = nil; + } + + return newFolder; +} + +- (void) setFolderManager: (GCSFolderManager *) newFolderManager +{ + ASSIGN (folderManager, newFolderManager); +} + +/* accessors */ + +- (NSURL *) _location +{ + NSURL *location; + + if (sessionsFolderURLString) + location = [NSURL URLWithString: sessionsFolderURLString]; + else + { + [self warnWithFormat: @"'OCSSessionsFolderURL' is not set"]; + location = nil; + } + + return location; +} + +- (GCSChannelManager *) _channelManager +{ + return [folderManager channelManager]; +} + +- (NSString *) _storeTableName +{ + return [[self _location] gcsTableName]; +} + +- (EOEntity *) _storeTableEntityForChannel: (EOAdaptorChannel *) tc +{ + static EOEntity *entity = nil; + EOAttribute *attribute; + NSString *tableName; + NSString *columns[] = { @"c_id", @"c_value", @"c_creationdate", + @"c_lastseen", nil }; + NSString **column; + NSMutableArray *keys; + NSDictionary *types; + + if (!entity) + { + entity = [EOEntity new]; + tableName = [self _storeTableName]; + [entity setName: tableName]; + [entity setExternalName: tableName]; + + types = [[tc specialQueries] sessionsAttributeTypes]; + + column = columns; + while (*column) + { + attribute = [EOAttribute new]; + [attribute setName: *column]; + [attribute setColumnName: *column]; + [attribute setExternalType: [types objectForKey: *column]]; + [entity addAttribute: attribute]; + [attribute release]; + column++; + } + + keys = [NSMutableArray arrayWithCapacity: 1]; + [keys addObject: [entity attributeNamed: @"c_id"]]; + [entity setPrimaryKeyAttributes: keys]; + + keys = [NSMutableArray arrayWithCapacity: 3]; + [keys addObject: [entity attributeNamed: @"c_value"]]; + [keys addObject: [entity attributeNamed: @"c_creationdate"]]; + [keys addObject: [entity attributeNamed: @"c_lastseen"]]; + [entity setClassProperties: keys]; + + [entity setAttributesUsedForLocking: [NSArray array]]; + } + + return entity; +} + +/* connection */ + +- (EOAdaptorChannel *) _acquireStoreChannel +{ + return [[self _channelManager] acquireOpenChannelForURL: [self _location]]; +} + +- (void) _releaseChannel: (EOAdaptorChannel *) _channel +{ + [[self _channelManager] releaseChannel:_channel]; +} + +- (BOOL) canConnectStore +{ + return [[self _channelManager] canConnect:[self _location]]; +} + +- (void) createFolderIfNotExists +{ + EOAdaptorChannel *tc; + NSString *sql, *tableName; + GCSSpecialQueries *queries; + + tc = [self _acquireStoreChannel]; + tableName = [self _storeTableName]; + + queries = [tc specialQueries]; + + sql = [NSString stringWithFormat: @"SELECT count(*) FROM %@", + [self _storeTableName]]; + if ([tc evaluateExpressionX: sql]) + { + sql = [queries createSessionsFolderWithName: tableName]; + if (![tc evaluateExpressionX: sql]) + [self logWithFormat: + @"sessions folder table '%@' successfully created!", + tableName]; + } + else + [tc cancelFetch]; + + [self _releaseChannel: tc]; +} + +/* operations */ + +- (NSDictionary *) recordForEntryWithID: (NSString *) theID +{ + EOAdaptorChannel *tc; + EOAdaptorContext *context; + NSString *tableName; + NSException *error; + NSArray *attrs; + NSDictionary *record; + EOEntity *entity; + EOSQLQualifier *qualifier; + + tableName = [self _storeTableName]; + + record = nil; + + tc = [self _acquireStoreChannel]; + if (tc) + { + context = [tc adaptorContext]; + entity = [self _storeTableEntityForChannel: tc]; + qualifier = [[EOSQLQualifier alloc] initWithEntity: entity + qualifierFormat: + @"c_id='%@'", + theID]; + [qualifier autorelease]; + + [context beginTransaction]; + error = [tc selectAttributesX: [entity attributesUsedForFetch] + describedByQualifier: qualifier + fetchOrder: nil + lock: NO]; + if (error) + [self errorWithFormat:@"%s: cannot execute fetch: %@", + __PRETTY_FUNCTION__, error]; + else + { + attrs = [tc describeResults: NO]; + record = [tc fetchAttributes: attrs withZone: NULL]; + [tc cancelFetch]; + } + [context rollbackTransaction]; + [self _releaseChannel: tc]; + } + + return record; +} + + + +- (NSDictionary *) _newRecordWithID: (NSString *) theID + value: (NSString *) theValue + creationDate: (NSCalendarDate *) theCreationDate + lastSeenDate: (NSCalendarDate *) theLastSeenDate +{ + NSNumber *cd, *ls; + + // We check if recId and alarmDate are nil prior calling -timeIntervalSince1970 + // Weird gcc optimizations can cause issue here. + cd = [NSNumber numberWithInt: (theCreationDate ? (int)[theCreationDate timeIntervalSince1970] : 0)]; + ls = [NSNumber numberWithInt: (theLastSeenDate ? (int)[theLastSeenDate timeIntervalSince1970] : 0)]; + + return [NSDictionary dictionaryWithObjectsAndKeys: theID, @"c_id", + theValue, @"c_value", + cd, @"c_creationdate", + ls, @"c_lastseen", + nil]; +} + +- (void) writeRecordForEntryWithID: (NSString *) theID + value: (NSString *) theValue + creationDate: (NSCalendarDate *) theCreationDate + lastSeenDate: (NSCalendarDate *) theLastSeenDate +{ + NSDictionary *record, *newRecord; + NSException *error; + EOAdaptorChannel *tc; + EOAdaptorContext *context; + EOEntity *entity; + EOSQLQualifier *qualifier; + + tc = [self _acquireStoreChannel]; + if (tc) + { + context = [tc adaptorContext]; + newRecord = [self _newRecordWithID: theID + value: theValue + creationDate: theCreationDate + lastSeenDate: theLastSeenDate]; + record = [self recordForEntryWithID: theID]; + entity = [self _storeTableEntityForChannel: tc]; + [context beginTransaction]; + if (record) + { + qualifier = [[EOSQLQualifier alloc] initWithEntity: entity + qualifierFormat: + @"c_id='%@'", + theID]; + [qualifier autorelease]; + error = [tc updateRowX: newRecord describedByQualifier: qualifier]; + } + else + error = [tc insertRowX: newRecord forEntity: entity]; + if (error) + { + [context rollbackTransaction]; + [self errorWithFormat:@"%s: cannot write record: %@", + __PRETTY_FUNCTION__, error]; + } + else + [context commitTransaction]; + [self _releaseChannel: tc]; + } +} + +- (void) deleteRecordForEntryWithID: (NSString *) theID +{ + EOAdaptorChannel *tc; + EOAdaptorContext *context; + EOEntity *entity; + EOSQLQualifier *qualifier; + NSException *error; + + tc = [self _acquireStoreChannel]; + if (tc) + { + context = [tc adaptorContext]; + entity = [self _storeTableEntityForChannel: tc]; + qualifier = [[EOSQLQualifier alloc] initWithEntity: entity + qualifierFormat: + @"c_id='%@'", + theID]; + [qualifier autorelease]; + [context beginTransaction]; + error = [tc deleteRowsDescribedByQualifierX: qualifier]; + if (error) + { + [context rollbackTransaction]; + [self errorWithFormat:@"%s: cannot delete record: %@", + __PRETTY_FUNCTION__, error]; + } + else + [context commitTransaction]; + [self _releaseChannel: tc]; + } +} + + + +@end diff --git a/SOPE/GDLContentStore/GCSSpecialQueries.h b/SOPE/GDLContentStore/GCSSpecialQueries.h index af406a844..08c2c3e69 100644 --- a/SOPE/GDLContentStore/GCSSpecialQueries.h +++ b/SOPE/GDLContentStore/GCSSpecialQueries.h @@ -37,6 +37,9 @@ - (NSString *) createFolderTableWithName: (NSString *) tableName; - (NSString *) createFolderACLTableWithName: (NSString *) tableName; +- (NSString *) createSessionsFolderWithName: (NSString *) tableName; +- (NSDictionary *) sessionsAttributeTypes; + @end @interface EOAdaptorChannel (GCSSpecialQueries) diff --git a/SOPE/GDLContentStore/GCSSpecialQueries.m b/SOPE/GDLContentStore/GCSSpecialQueries.m index 4effe6602..9bb476547 100644 --- a/SOPE/GDLContentStore/GCSSpecialQueries.m +++ b/SOPE/GDLContentStore/GCSSpecialQueries.m @@ -105,8 +105,26 @@ return nil; } +- (NSString *) createSessionsFolderWithName: (NSString *) tableName +{ + [self subclassResponsibility: _cmd]; + + return nil; +} + +- (NSDictionary *) sessionsAttributeTypes +{ + [self subclassResponsibility: _cmd]; + + return nil; +} + + @end +// +// PostgreSQL database +// @implementation GCSPostgreSQLSpecialQueries - (NSString *) createEMailAlarmsFolderWithName: (NSString *) tableName @@ -168,8 +186,39 @@ return [NSString stringWithFormat: sqlFolderACLFormat, tableName]; } +- (NSString *) createSessionsFolderWithName: (NSString *) tableName +{ + static NSString *sqlFolderFormat + = (@"CREATE TABLE %@ (" + @" c_id VARCHAR(255) NOT NULL," + @" c_value VARCHAR(255) NOT NULL," + @" c_creationdate INT4 NOT NULL," + @" c_lastseen INT4 NOT NULL)"); + + return [NSString stringWithFormat: sqlFolderFormat, tableName]; +} + +- (NSDictionary *) sessionsAttributeTypes +{ + static NSMutableDictionary *types = nil; + + if (!types) + { + types = [NSMutableDictionary new]; + [types setObject: @"varchar" forKey: @"c_id"]; + [types setObject: @"varchar" forKey: @"c_value"]; + [types setObject: @"int" forKey: @"c_creationdate"]; + [types setObject: @"int" forKey: @"c_lastseen"]; + } + + return types; +} + @end +// +// MySQL database +// @implementation GCSMySQLSpecialQueries - (NSString *) createEMailAlarmsFolderWithName: (NSString *) tableName @@ -231,8 +280,39 @@ return [NSString stringWithFormat: sqlFolderACLFormat, tableName]; } +- (NSString *) createSessionsFolderWithName: (NSString *) tableName +{ + static NSString *sqlFolderFormat + = (@"CREATE TABLE %@ (" + @" c_id VARCHAR(255) NOT NULL," + @" c_value VARCHAR(255) NOT NULL," + @" c_creationdate INT NOT NULL," + @" c_lastseen INT NOT NULL)"); + + return [NSString stringWithFormat: sqlFolderFormat, tableName]; +} + +- (NSDictionary *) sessionsAttributeTypes +{ + static NSMutableDictionary *types = nil; + + if (!types) + { + types = [NSMutableDictionary new]; + [types setObject: @"varchar" forKey: @"c_id"]; + [types setObject: @"varchar" forKey: @"c_value"]; + [types setObject: @"int" forKey: @"c_creationdate"]; + [types setObject: @"int" forKey: @"c_lastseen"]; + } + + return types; +} + @end +// +// Oracle database +// @implementation GCSOracleSpecialQueries - (NSString *) createEMailAlarmsFolderWithName: (NSString *) tableName @@ -293,4 +373,32 @@ return [NSString stringWithFormat: sqlFolderACLFormat, tableName]; } +- (NSString *) createSessionsFolderWithName: (NSString *) tableName +{ + static NSString *sqlFolderFormat + = (@"CREATE TABLE %@ (" + @" c_id VARCHAR2(255) NOT NULL," + @" c_value VARCHAR2(255) NOT NULL," + @" c_creationdate INTEGER NOT NULL," + @" c_lastseen INTEGER NOT NULL)"); + + return [NSString stringWithFormat: sqlFolderFormat, tableName]; +} + +- (NSDictionary *) sessionsAttributeTypes +{ + static NSMutableDictionary *types = nil; + + if (!types) + { + types = [NSMutableDictionary new]; + [types setObject: @"varchar2" forKey: @"c_id"]; + [types setObject: @"varchar2" forKey: @"c_value"]; + [types setObject: @"integer" forKey: @"c_creationdate"]; + [types setObject: @"integer" forKey: @"c_lastseen"]; + } + + return types; +} + @end diff --git a/SOPE/GDLContentStore/GNUmakefile b/SOPE/GDLContentStore/GNUmakefile index bb50fc57b..e0e50cab2 100644 --- a/SOPE/GDLContentStore/GNUmakefile +++ b/SOPE/GDLContentStore/GNUmakefile @@ -32,6 +32,7 @@ libGDLContentStore_HEADER_FILES += \ GCSFolderType.h \ GCSChannelManager.h \ GCSFieldExtractor.h \ + GCSSessionsFolder.h \ GCSSpecialQueries.h \ GCSStringFormatter.h \ @@ -48,6 +49,7 @@ libGDLContentStore_OBJC_FILES += \ GCSFolderType.m \ GCSChannelManager.m \ GCSFieldExtractor.m \ + GCSSessionsFolder.m \ GCSSpecialQueries.m \ GCSStringFormatter.m \ diff --git a/SoObjects/Mailer/SOGoMailAccount.m b/SoObjects/Mailer/SOGoMailAccount.m index 1d2845d66..d87c86fa2 100644 --- a/SoObjects/Mailer/SOGoMailAccount.m +++ b/SoObjects/Mailer/SOGoMailAccount.m @@ -629,14 +629,16 @@ static NSString *sieveScriptName = @"sogo"; return [NSMutableString string]; } +// +// Extract password from basic authentication. +// - (NSString *) imap4PasswordRenewed: (BOOL) renewed { - /* - Extract password from basic authentication. - */ - NSURL *imapURL; NSString *password; + NSURL *imapURL; + // Default account - ie., the account that is provided with a default + // SOGo installation. User-added IMAP accounts will have name >= 1. if ([nameInContainer isEqualToString: @"0"]) { imapURL = [self imap4URL]; diff --git a/SoObjects/SOGo/GNUmakefile b/SoObjects/SOGo/GNUmakefile index 8733c5b15..dee5233a6 100644 --- a/SoObjects/SOGo/GNUmakefile +++ b/SoObjects/SOGo/GNUmakefile @@ -46,6 +46,7 @@ SOGo_HEADER_FILES = \ NSURL+DAV.h \ \ SOGoAuthenticator.h \ + SOGoSession.h \ SOGoCASSession.h \ SOGoDAVAuthenticator.h \ SOGoProxyAuthenticator.h \ @@ -108,6 +109,7 @@ SOGo_OBJC_FILES = \ NSString+Utilities.m \ NSURL+DAV.m \ \ + SOGoSession.m \ SOGoCASSession.m \ SOGoDAVAuthenticator.m \ SOGoProxyAuthenticator.m \ diff --git a/SoObjects/SOGo/SOGoCache.h b/SoObjects/SOGo/SOGoCache.h index 7558f818b..ccbeb3be9 100644 --- a/SoObjects/SOGo/SOGoCache.h +++ b/SoObjects/SOGo/SOGoCache.h @@ -1,6 +1,6 @@ /* SOGoCache.h - this file is part of SOGo * - * Copyright (C) 2008-2010 Inverse inc. + * Copyright (C) 2008-2011 Inverse inc. * * Author: Wolfgang Sourdeau * Ludovic Marcotte @@ -92,7 +92,9 @@ forLogin: (NSString *) login; - (NSString *) userSettingsForLogin: (NSString *) theLogin; -/* CAS support */ +// +// CAS support +// - (NSString *) CASTicketFromIdentifier: (NSString *) identifier; - (NSString *) CASSessionWithTicket: (NSString *) ticket; - (void) setCASSession: (NSString *) casSession @@ -103,9 +105,11 @@ - (void) setCASPGTId: (NSString *) pgtId forPGTIOU: (NSString *) pgtIou; +// +// ACL caching support +// - (void) setACLs: (NSDictionary *) theACLs forPath: (NSString *) thePath; - - (NSMutableDictionary *) aclsForPath: (NSString *) thePath; @end diff --git a/SoObjects/SOGo/SOGoCache.m b/SoObjects/SOGo/SOGoCache.m index 805b12650..7a2d6c259 100644 --- a/SoObjects/SOGo/SOGoCache.m +++ b/SoObjects/SOGo/SOGoCache.m @@ -36,8 +36,13 @@ * +attributes value = NSMutableDictionary instance > user's LDAP attributes * +acl value = NSDictionary instance > ACLs on an object at specified path * + value = NSString instance (array components separated by ",") or group member logins for a specific group in domain + * cas-id:< > value = + * cas-ticket:< > value = + * cas-pgtiou:< > value = + * session:< > value = */ + #import #import #import @@ -437,7 +442,9 @@ static memcached_st *handle = NULL; return [self _valuesOfType: @"settings" forKey: theLogin]; } -/* CAS session support */ +// +// CAS session support +// - (NSString *) CASTicketFromIdentifier: (NSString *) identifier { return [self valueForKey: [NSString stringWithFormat: @"cas-id:%@", @@ -481,7 +488,7 @@ static memcached_st *handle = NULL; } // -// +// ACL caching code // - (void) setACLs: (NSDictionary *) theACLs forPath: (NSString *) thePath diff --git a/SoObjects/SOGo/SOGoDAVAuthenticator.m b/SoObjects/SOGo/SOGoDAVAuthenticator.m index a624d28d4..89684cec2 100644 --- a/SoObjects/SOGo/SOGoDAVAuthenticator.m +++ b/SoObjects/SOGo/SOGoDAVAuthenticator.m @@ -1,14 +1,15 @@ /* + Copyright (C) 2007-2011 Inverse inc. Copyright (C) 2004 SKYRIX Software AG - This file is part of OpenGroupware.org. + This file is part of SOGo. - OGo is free software; you can redistribute it and/or modify it under + SOGo is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. - OGo is distributed in the hope that it will be useful, but WITHOUT ANY + SOGo 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 Lesser General Public License for more details. diff --git a/SoObjects/SOGo/SOGoProxyAuthenticator.m b/SoObjects/SOGo/SOGoProxyAuthenticator.m index 1b6d532f1..93df9d43d 100644 --- a/SoObjects/SOGo/SOGoProxyAuthenticator.m +++ b/SoObjects/SOGo/SOGoProxyAuthenticator.m @@ -1,6 +1,6 @@ /* SOGoProxyAuthenticator.h - this file is part of SOGo * - * Copyright (C) 2009 Inverse inc. + * Copyright (C) 2009-2011 Inverse inc. * * Author: Wolfgang Sourdeau * diff --git a/SoObjects/SOGo/SOGoUserManager.m b/SoObjects/SOGo/SOGoUserManager.m index 0bc2ddb7f..4c463492c 100644 --- a/SoObjects/SOGo/SOGoUserManager.m +++ b/SoObjects/SOGo/SOGoUserManager.m @@ -402,7 +402,6 @@ grace: grace]; } - return checkOK; } diff --git a/SoObjects/SOGo/SOGoWebAuthenticator.m b/SoObjects/SOGo/SOGoWebAuthenticator.m index adcd280a1..9b202649f 100644 --- a/SoObjects/SOGo/SOGoWebAuthenticator.m +++ b/SoObjects/SOGo/SOGoWebAuthenticator.m @@ -1,6 +1,6 @@ /* SOGoWebAuthenticator.m - this file is part of SOGo * - * Copyright (C) 2007-2010 Inverse inc. + * Copyright (C) 2007-2011 Inverse inc. * * Author: Wolfgang Sourdeau * @@ -32,13 +32,16 @@ #import #import #import +#import #import #import +#import "SOGoCache.h" #import "SOGoCASSession.h" #import "SOGoConstants.h" #import "SOGoPermissions.h" +#import "SOGoSession.h" #import "SOGoSystemDefaults.h" #import "SOGoUser.h" #import "SOGoUserManager.h" @@ -59,12 +62,32 @@ - (BOOL) checkLogin: (NSString *) _login password: (NSString *) _pwd -{ +{ + NSString *username, *password, *value; SOGoPasswordPolicyError perr; int expire, grace; + - return [self checkLogin: _login - password: _pwd + // We check for the existence of the session in the database/memcache + // and we extract the real password from it. Here, + // + // _login == userKey + // _pwd == sessionKey + // + // If the session isn't present in the database, we fail the login process. + // + value = [SOGoSession valueForSessionKey: _pwd]; + + if (!value) + return NO; + + [SOGoSession decodeValue: value + usingKey: _login + login: &username + password: &password]; + + return [self checkLogin: username + password: password perr: &perr expire: &expire grace: &grace]; @@ -97,13 +120,16 @@ expire: _expire grace: _grace]; - // [self logWithFormat: @"Checked login with ppolicy enabled: %d %d %d", *_perr, *_expire, *_grace]; + //[self logWithFormat: @"Checked login with ppolicy enabled: %d %d %d", *_perr, *_expire, *_grace]; // It's important to return the real value here. The callee will handle // the return code and check for the _perr value. return rc; } +// +// +// - (SOGoUser *) userInContext: (WOContext *)_ctx { static SOGoUser *anonymous = nil; @@ -124,20 +150,64 @@ - (NSString *) passwordInContext: (WOContext *) context { - NSArray *creds; NSString *auth, *password; + NSArray *creds; auth = [[context request] cookieValueForKey: [self cookieNameInContext: context]]; creds = [self parseCredentials: auth]; if ([creds count] > 1) - password = [creds objectAtIndex: 1]; + { + NSString *login; + + [SOGoSession decodeValue: [SOGoSession valueForSessionKey: [creds objectAtIndex: 1]] + usingKey: [creds objectAtIndex: 0] + login: &login + password: &password]; + } else password = nil; return password; } +// +// We overwrite SOPE's method in order to proper retrieve +// the username from the cookie. +// +- (NSString *) checkCredentials: (NSString *)_creds +{ + NSString *login, *pwd, *userKey, *sessionKey; + NSArray *creds; + + SOGoPasswordPolicyError perr; + int expire, grace; + + if (![(creds = [self parseCredentials:_creds]) isNotEmpty]) + return nil; + + userKey = [creds objectAtIndex:0]; + if ([userKey isEqualToString:@"anonymous"]) + return @"anonymous"; + + sessionKey = [creds objectAtIndex:1]; + + [SOGoSession decodeValue: [SOGoSession valueForSessionKey: sessionKey] + usingKey: userKey + login: &login + password: &pwd]; + + if (![self checkLogin: login + password: pwd + perr: &perr + expire: &expire + grace: &grace]) + return nil; + + return login; +} + + - (NSString *) imapPasswordInContext: (WOContext *) context forServer: (NSString *) imapServer forceRenew: (BOOL) renew @@ -176,12 +246,12 @@ return [SOGoUser userWithLogin: login roles: roles]; } +// +// This is called by SoObjectRequestHandler prior doing any significant +// processing to allow the authenticator to reject invalid requests. +// - (WOResponse *) preprocessCredentialsInContext: (WOContext *) context { - /* - This is called by SoObjectRequestHandler prior doing any significant - processing to allow the authenticator to reject invalid requests. - */ WOResponse *response; NSString *auth; diff --git a/UI/MainUI/SOGoRootPage.m b/UI/MainUI/SOGoRootPage.m index 3d537eec8..7abff33f1 100644 --- a/UI/MainUI/SOGoRootPage.m +++ b/UI/MainUI/SOGoRootPage.m @@ -51,7 +51,7 @@ #import #import #import - +#import #import #import "SOGoRootPage.h" @@ -70,18 +70,37 @@ forAuthenticator: (SOGoWebAuthenticator *) auth { WOCookie *authCookie; - NSString *cookieValue, *cookieString, *appName; + NSString *cookieValue, *cookieString, *appName, *sessionKey, *userKey, *securedPassword; + // + // We create a new cookie - thus we create a new session + // associated to the user. For security, we generate: + // + // A- a session key + // B- a user key + // + // In memcached, the session key will be associated to the user's password + // which will be XOR'ed with the user key. + // + sessionKey = [SOGoSession generateKeyForLength: 16]; + userKey = [SOGoSession generateKeyForLength: 64]; + + NSString *value = [NSString stringWithFormat: @"%@:%@", username, password]; + securedPassword = [SOGoSession securedValue: value usingKey: userKey]; + + + [SOGoSession setValue: securedPassword forSessionKey: sessionKey]; + + //cookieString = [NSString stringWithFormat: @"%@:%@", + // username, password]; cookieString = [NSString stringWithFormat: @"%@:%@", - username, password]; + userKey, sessionKey]; cookieValue = [NSString stringWithFormat: @"basic %@", [cookieString stringByEncodingBase64]]; authCookie = [WOCookie cookieWithName: [auth cookieNameInContext: context] value: cookieValue]; appName = [[context request] applicationName]; [authCookie setPath: [NSString stringWithFormat: @"/%@/", appName]]; - /* enable this when we have code to determine whether request is HTTPS: - [authCookie setIsSecure: YES]; */ return authCookie; } @@ -107,7 +126,9 @@ return locationCookie; } -/* actions */ +// +// +// - (WOResponse *) _responseWithLDAPPolicyError: (int) error { NSDictionary *jsonError; @@ -164,8 +185,9 @@ response = [self responseWithStatus: 200 andJSONRepresentation: json]; - authCookie = [self _cookieWithUsername: username andPassword: password - forAuthenticator: auth]; + authCookie = [self _cookieWithUsername: username + andPassword: password + forAuthenticator: auth]; [response addCookie: authCookie]; supportedLanguages = [[SOGoSystemDefaults sharedSystemDefaults] @@ -369,11 +391,6 @@ return [[SOGoSystemDefaults sharedSystemDefaults] supportedLanguages]; } -// - (NSString *) language -// { -// return [SOGoUser language]; -// } - - (NSString *) languageText { NSString *text; @@ -397,7 +414,7 @@ - (WOResponse *) changePasswordAction { - NSString *username, *password, *newPassword; + NSString *username, *password, *newPassword, *value; SOGoUserManager *um; SOGoPasswordPolicyError error; WOResponse *response; @@ -405,11 +422,22 @@ NSDictionary *message; SOGoWebAuthenticator *auth; WOCookie *authCookie; + NSArray *creds; request = [context request]; message = [[request contentAsString] objectFromJSONString]; - username = [message objectForKey: @"userName"]; - password = [message objectForKey: @"password"]; + + auth = [[WOApplication application] + authenticatorInContext: context]; + value = [[context request] + cookieValueForKey: [auth cookieNameInContext: context]]; + creds = [auth parseCredentials: value]; + + [SOGoSession decodeValue: [SOGoSession valueForSessionKey: [creds objectAtIndex: 1]] + usingKey: [creds objectAtIndex: 0] + login: &username + password: &password]; + newPassword = [message objectForKey: @"newPassword"]; um = [SOGoUserManager sharedUserManager]; @@ -420,9 +448,10 @@ newPassword: newPassword perr: &error]) { + // We delete the previous session + [SOGoSession deleteValueForSessionKey: [creds objectAtIndex: 1]]; + response = [self responseWith204]; - auth = [[WOApplication application] - authenticatorInContext: context]; authCookie = [self _cookieWithUsername: username andPassword: newPassword forAuthenticator: auth]; diff --git a/UI/MainUI/SOGoUserHomePage.m b/UI/MainUI/SOGoUserHomePage.m index 1c2950a5e..56d36d5bf 100644 --- a/UI/MainUI/SOGoUserHomePage.m +++ b/UI/MainUI/SOGoUserHomePage.m @@ -41,6 +41,7 @@ #import #import #import +#import #import #import #import @@ -275,11 +276,13 @@ - (id ) logoffAction { + SOGoWebAuthenticator *auth; + NSString *userName, *value; WOResponse *response; - WOCookie *cookie; NSCalendarDate *date; - NSString *userName; - + WOCookie *cookie; + NSArray *creds; + userName = [[context activeUser] login]; [self logWithFormat: @"user '%@' logged off", userName]; @@ -288,6 +291,18 @@ date = [NSCalendarDate calendarDate]; [date setTimeZone: [NSTimeZone timeZoneWithAbbreviation: @"GMT"]]; + // We cleanup the memecached/database session cache. We do this before + // invoking _logoutCookieWithDate: in order to obtain its value. + auth = [[self clientObject] authenticatorInContext: context]; + if ([auth respondsToSelector: @selector (cookieNameInContext:)]) + { + value = [[context request] cookieValueForKey: [auth cookieNameInContext: context]]; + creds = [auth parseCredentials: value]; + + if ([creds count] > 1) + [SOGoSession deleteValueForSessionKey: [creds objectAtIndex: 1]]; + } + cookie = [self _logoutCookieWithDate: date]; if (cookie) [response addCookie: cookie]; @@ -298,6 +313,7 @@ forKey: @"Cache-Control"]; [response setHeader: @"no-cache" forKey: @"Pragma"]; + return response; } diff --git a/UI/WebServerResources/SOGoRootPage.js b/UI/WebServerResources/SOGoRootPage.js index cc58cfd42..e335ed67f 100644 --- a/UI/WebServerResources/SOGoRootPage.js +++ b/UI/WebServerResources/SOGoRootPage.js @@ -98,6 +98,7 @@ function onLoginCallback(http) { if (http.status == 200) { // Make sure browser's cookies are enabled var loginCookie = readLoginCookie(); + if (!loginCookie) { SetLogMessage("errorMessage", _("cookiesNotEnabled")); submitBtn.disabled = false;