mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-08-29 02:07:36 +00:00
Merge to 2.2.11
This commit is contained in:
@@ -86,15 +86,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
return nil;
|
||||
}
|
||||
|
||||
data = [[NSData alloc] initWithBytes: xml length: xml_len];
|
||||
data = [NSData dataWithBytesNoCopy: xml length: xml_len freeWhenDone: YES];
|
||||
|
||||
#if WBXMLDEBUG
|
||||
[data writeToFile: @"/tmp/protocol.decoded" atomically: YES];
|
||||
#endif
|
||||
|
||||
free(xml);
|
||||
|
||||
return AUTORELEASE(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
@@ -138,15 +136,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
return nil;
|
||||
}
|
||||
|
||||
data = [[NSData alloc] initWithBytes: wbxml length: wbxml_len];
|
||||
data = [NSData dataWithBytesNoCopy: wbxml length: wbxml_len freeWhenDone: YES];
|
||||
|
||||
#if WBXMLDEBUG
|
||||
[data writeToFile: @"/tmp/protocol.encoded" atomically: YES];
|
||||
#endif
|
||||
|
||||
free(wbxml);
|
||||
wbxml_conv_xml2wbxml_destroy(conv);
|
||||
|
||||
return AUTORELEASE(data);
|
||||
|
||||
return data;
|
||||
}
|
||||
@end
|
||||
|
||||
@@ -155,6 +155,10 @@ static NSArray *easCommandParameters = nil;
|
||||
const char* qs_bytes;
|
||||
|
||||
queryString = [[components objectAtIndex: 0] dataByDecodingBase64];
|
||||
|
||||
if (![queryString length])
|
||||
return nil;
|
||||
|
||||
qs_bytes = (const char*)[queryString bytes];
|
||||
|
||||
if (!easCommandCodes)
|
||||
|
||||
@@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#import "SOGoActiveSyncDispatcher+Sync.h"
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSAutoreleasePool.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSNull.h>
|
||||
#import <Foundation/NSProcessInfo.h>
|
||||
@@ -114,22 +115,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
forKey: (NSString *) theFolderKey
|
||||
{
|
||||
SOGoCacheGCSObject *o;
|
||||
NSDictionary *values;
|
||||
NSString *key;
|
||||
|
||||
key = [NSString stringWithFormat: @"%@+%@", [context objectForKey: @"DeviceId"], theFolderKey];
|
||||
|
||||
values = [theFolderMetadata copy];
|
||||
|
||||
o = [SOGoCacheGCSObject objectWithName: key inContainer: nil];
|
||||
[o setObjectType: ActiveSyncFolderCacheObject];
|
||||
[o setTableUrl: [self folderTableURL]];
|
||||
[o reloadIfNeeded];
|
||||
//[o reloadIfNeeded];
|
||||
|
||||
[[o properties] removeObjectForKey: @"SyncKey"];
|
||||
[[o properties] removeObjectForKey: @"SyncCache"];
|
||||
[[o properties] removeObjectForKey: @"DateCache"];
|
||||
[[o properties] removeObjectForKey: @"MoreAvailable"];
|
||||
[[o properties] removeObjectForKey: @"SuccessfulMoveItemsOps"];
|
||||
|
||||
[[o properties] addEntriesFromDictionary: theFolderMetadata];
|
||||
[[o properties] addEntriesFromDictionary: values];
|
||||
[o save];
|
||||
[values release];
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *) _folderMetadataForKey: (NSString *) theFolderKey
|
||||
@@ -534,6 +539,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
{
|
||||
NSMutableDictionary *folderMetadata, *dateCache, *syncCache;
|
||||
NSAutoreleasePool *pool;
|
||||
NSMutableString *s;
|
||||
|
||||
BOOL more_available;
|
||||
@@ -635,6 +641,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
allComponents = [theCollection syncTokenFieldsWithProperties: nil matchingSyncToken: theSyncKey fromDate: theFilterType];
|
||||
allComponents = [allComponents sortedArrayUsingDescriptors: [NSArray arrayWithObjects: [[NSSortDescriptor alloc] initWithKey: @"c_lastmodified" ascending:YES], nil]];
|
||||
|
||||
|
||||
// Check for the WindowSize
|
||||
max = [allComponents count];
|
||||
@@ -643,14 +650,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
for (i = 0; i < max; i++)
|
||||
{
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
// Check for the WindowSize and slice accordingly
|
||||
if (return_count >= theWindowSize)
|
||||
{
|
||||
more_available = YES;
|
||||
|
||||
// -1 to make sure that we miss no event in case there are more with the same c_lastmodified
|
||||
*theLastServerKey = [NSString stringWithFormat: @"%d", [[component objectForKey: @"c_lastmodified"] intValue] - 1];
|
||||
*theLastServerKey = [[NSString alloc] initWithFormat: @"%d", [[component objectForKey: @"c_lastmodified"] intValue] - 1];
|
||||
|
||||
DESTROY(pool);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -747,6 +757,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[s appendString: @"</Add>"];
|
||||
|
||||
return_count++;
|
||||
|
||||
DESTROY(pool);
|
||||
}
|
||||
} // for ...
|
||||
|
||||
@@ -763,6 +775,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
[self _setFolderMetadata: folderMetadata
|
||||
forKey: [NSString stringWithFormat: @"%@/%@", component_name, [theCollection nameInContainer]]];
|
||||
|
||||
RELEASE(*theLastServerKey);
|
||||
}
|
||||
break;
|
||||
case ActiveSyncMailFolder:
|
||||
@@ -830,6 +844,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
for (; k < [allCacheObjects count]; k++)
|
||||
{
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
// Check for the WindowSize and slice accordingly
|
||||
if (return_count >= theWindowSize)
|
||||
{
|
||||
@@ -837,8 +853,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
more_available = YES;
|
||||
|
||||
lastSequence = ([[aCacheObject sequence] isEqual: [NSNull null]] ? @"1" : [aCacheObject sequence]);
|
||||
*theLastServerKey = [NSString stringWithFormat: @"%@-%@", [aCacheObject uid], lastSequence];
|
||||
*theLastServerKey = [[NSString alloc] initWithFormat: @"%@-%@", [aCacheObject uid], lastSequence];
|
||||
//NSLog(@"Reached windowSize - lastUID will be: %@", *theLastServerKey);
|
||||
DESTROY(pool);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -919,7 +936,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
DESTROY(pool);
|
||||
} // for (; k < ...)
|
||||
|
||||
if (more_available)
|
||||
{
|
||||
@@ -933,6 +951,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
}
|
||||
|
||||
[self _setFolderMetadata: folderMetadata forKey: [self _getNameInCache: theCollection withType: theFolderType]];
|
||||
RELEASE(*theLastServerKey);
|
||||
|
||||
} // default:
|
||||
break;
|
||||
} // switch (folderType) ...
|
||||
@@ -1050,11 +1070,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{
|
||||
// Collection not found - next folderSync will do the cleanup
|
||||
//NSLog(@"Sync Collection not found %@ %@", collectionId, realCollectionId);
|
||||
[theBuffer appendString: @"<Collection>"];
|
||||
[theBuffer appendFormat: @"<SyncKey>%@</SyncKey>", syncKey];
|
||||
[theBuffer appendFormat: @"<CollectionId>%@</CollectionId>", collectionId];
|
||||
[theBuffer appendFormat: @"<Status>%d</Status>", 8];
|
||||
[theBuffer appendString: @"</Collection>"];
|
||||
//Outlook doesn't like following response
|
||||
//[theBuffer appendString: @"<Collection>"];
|
||||
//[theBuffer appendFormat: @"<SyncKey>%@</SyncKey>", syncKey];
|
||||
//[theBuffer appendFormat: @"<CollectionId>%@</CollectionId>", collectionId];
|
||||
//[theBuffer appendFormat: @"<Status>%d</Status>", 8];
|
||||
//[theBuffer appendString: @"</Collection>"];
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1097,7 +1118,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*changeDetected = YES;
|
||||
|
||||
if (!([[self _folderMetadataForKey: [self _getNameInCache: collection withType: folderType]] objectForKey: @"displayName"]))
|
||||
status = 13; // need folderSync
|
||||
status = 12; // need folderSync
|
||||
else
|
||||
status = 3; // do a complete resync
|
||||
}
|
||||
@@ -1118,11 +1139,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[self processSyncGetChanges: theDocumentElement
|
||||
inCollection: collection
|
||||
withWindowSize: windowSize
|
||||
//withWindowSize: 5
|
||||
withSyncKey: syncKey
|
||||
withFolderType: folderType
|
||||
withFilterType: [NSCalendarDate dateFromFilterType: [[(id)[theDocumentElement getElementsByTagName: @"FilterType"] lastObject] textValue]]
|
||||
//withFilterType: [NSCalendarDate dateFromFilterType: @"7"]
|
||||
inBuffer: changeBuffer
|
||||
lastServerKey: &lastServerKey];
|
||||
}
|
||||
@@ -1309,7 +1328,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
BOOL changeDetected;
|
||||
|
||||
// We initialize our output buffer
|
||||
output = [NSMutableString string];
|
||||
output = [[NSMutableString alloc] init];
|
||||
|
||||
[output appendString: @"<?xml version=\"1.0\" encoding=\"utf-8\"?>"];
|
||||
[output appendString: @"<!DOCTYPE ActiveSync PUBLIC \"-//MICROSOFT//DTD ActiveSync//EN\" \"http://www.microsoft.com/\">"];
|
||||
@@ -1365,8 +1384,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[output appendString: s];
|
||||
|
||||
[output appendString: @"</Collections></Sync>"];
|
||||
|
||||
d = [[output dataUsingEncoding: NSUTF8StringEncoding] xml2wbxml];
|
||||
|
||||
// Avoid overloading the autorelease pool here, as Sync command can
|
||||
// generate fairly large responses.
|
||||
d = [output dataUsingEncoding: NSUTF8StringEncoding];
|
||||
RELEASE(output);
|
||||
|
||||
d = [d xml2wbxml];
|
||||
|
||||
[theResponse setContent: d];
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "SOGoActiveSyncDispatcher.h"
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSAutoreleasePool.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSProcessInfo.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
@@ -129,6 +130,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@interface SOGoActiveSyncDispatcher (Sync)
|
||||
|
||||
- (NSMutableDictionary *) _folderMetadataForKey: (NSString *) theFolderKey;
|
||||
- (void) _setFolderMetadata: (NSDictionary *) theFolderMetadata forKey: (NSString *) theFolderKey;
|
||||
|
||||
@end
|
||||
|
||||
@@ -906,6 +908,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[o reloadIfNeeded];
|
||||
|
||||
[[o properties ] setObject: [[folderMetadata objectForKey: @"path"] substringFromIndex: 1] forKey: @"displayName"];
|
||||
|
||||
// clean cache content to avoid stale data
|
||||
[[o properties] removeObjectForKey: @"SyncKey"];
|
||||
[[o properties] removeObjectForKey: @"SyncCache"];
|
||||
[[o properties] removeObjectForKey: @"DateCache"];
|
||||
[[o properties] removeObjectForKey: @"MoreAvailable"];
|
||||
[[o properties] removeObjectForKey: @"SuccessfulMoveItemsOps"];
|
||||
[o save];
|
||||
|
||||
command_count++;
|
||||
@@ -949,11 +958,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Decide between add and change
|
||||
if (![[o properties ] objectForKey: @"displayName"] || first_sync)
|
||||
operation = @"Add";
|
||||
operation = @"Add";
|
||||
else if (![[[o properties ] objectForKey: @"displayName"] isEqualToString: [[folders objectAtIndex:fi] displayName]])
|
||||
operation = @"Update";
|
||||
else
|
||||
operation = nil;
|
||||
operation = @"Update";
|
||||
else
|
||||
operation = nil;
|
||||
|
||||
if (operation)
|
||||
{
|
||||
@@ -981,6 +990,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[o setTableUrl: [self folderTableURL]];
|
||||
[o reloadIfNeeded];
|
||||
[[o properties ] setObject: [[folders objectAtIndex:fi] displayName] forKey: @"displayName"];
|
||||
|
||||
if ([operation isEqualToString: @"Add"])
|
||||
{
|
||||
// clean cache content to avoid stale data
|
||||
[[o properties] removeObjectForKey: @"SyncKey"];
|
||||
[[o properties] removeObjectForKey: @"SyncCache"];
|
||||
[[o properties] removeObjectForKey: @"DateCache"];
|
||||
[[o properties] removeObjectForKey: @"MoreAvailable"];
|
||||
[[o properties] removeObjectForKey: @"SuccessfulMoveItemsOps"];
|
||||
}
|
||||
|
||||
[o save];
|
||||
}
|
||||
else
|
||||
@@ -992,6 +1012,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
command_count++;
|
||||
|
||||
[[o properties ] setObject: [[folders objectAtIndex:fi] displayName] forKey: @"displayName"];
|
||||
|
||||
if ([operation isEqualToString: @"Add"])
|
||||
{
|
||||
// clean cache content to avoid stale data
|
||||
[[o properties] removeObjectForKey: @"SyncKey"];
|
||||
[[o properties] removeObjectForKey: @"SyncCache"];
|
||||
[[o properties] removeObjectForKey: @"DateCache"];
|
||||
[[o properties] removeObjectForKey: @"MoreAvailable"];
|
||||
[[o properties] removeObjectForKey: @"SuccessfulMoveItemsOps"];
|
||||
}
|
||||
|
||||
[o save];
|
||||
}
|
||||
}
|
||||
@@ -1397,7 +1428,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
- (void) processMoveItems: (id <DOMElement>) theDocumentElement
|
||||
inResponse: (WOResponse *) theResponse
|
||||
{
|
||||
NSString *srcMessageId, *srcFolderId, *dstFolderId, *dstMessageId;
|
||||
NSString *srcMessageId, *srcFolderId, *dstFolderId, *dstMessageId, *nameInCache, *currentFolder;
|
||||
NSMutableDictionary *folderMetadata, *prevSuccessfulMoveItemsOps, *newSuccessfulMoveItemsOps;
|
||||
SOGoMicrosoftActiveSyncFolderType srcFolderType, dstFolderType;
|
||||
id <DOMElement> aMoveOperation;
|
||||
NSArray *moveOperations;
|
||||
@@ -1406,6 +1438,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
NSData *d;
|
||||
int i;
|
||||
|
||||
currentFolder = nil;
|
||||
|
||||
moveOperations = (id)[theDocumentElement getElementsByTagName: @"Move"];
|
||||
|
||||
s = [NSMutableString string];
|
||||
@@ -1421,6 +1455,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
srcMessageId = [[(id)[aMoveOperation getElementsByTagName: @"SrcMsgId"] lastObject] textValue];
|
||||
srcFolderId = [[[(id)[aMoveOperation getElementsByTagName: @"SrcFldId"] lastObject] textValue] realCollectionIdWithFolderType: &srcFolderType];
|
||||
dstFolderId = [[[(id)[aMoveOperation getElementsByTagName: @"DstFldId"] lastObject] textValue] realCollectionIdWithFolderType: &dstFolderType];
|
||||
|
||||
if (srcFolderType == ActiveSyncMailFolder)
|
||||
nameInCache = [NSString stringWithFormat: @"folder%@", [[[[(id)[aMoveOperation getElementsByTagName: @"SrcFldId"] lastObject] textValue] stringByUnescapingURL] substringFromIndex: 5]];
|
||||
else
|
||||
nameInCache = [[[(id)[aMoveOperation getElementsByTagName: @"SrcFldId"] lastObject] textValue] stringByUnescapingURL];
|
||||
|
||||
if (![nameInCache isEqualToString: currentFolder])
|
||||
{
|
||||
folderMetadata = [self _folderMetadataForKey: nameInCache];
|
||||
prevSuccessfulMoveItemsOps = [folderMetadata objectForKey: @"SuccessfulMoveItemsOps"];
|
||||
newSuccessfulMoveItemsOps = [NSMutableDictionary dictionary] ;
|
||||
currentFolder = nameInCache;
|
||||
}
|
||||
|
||||
[s appendString: @"<Response>"];
|
||||
|
||||
@@ -1463,8 +1510,31 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
if (!dstMessageId)
|
||||
{
|
||||
// FIXME: should we return 1 or 2 here?
|
||||
[s appendFormat: @"<Status>%d</Status>", 2];
|
||||
// Our destination message ID doesn't exist OR even our source message ID doesn't.
|
||||
// This can happen if you Move items from your EAS client and immediately closes it
|
||||
// before the server had the time to receive or process the query. Then, if that message
|
||||
// is moved away by an other client behing the EAS' client back, it obvisouly won't find it.
|
||||
// The issue the "result" will still be a success, but in fact, it's a failure. Cyrus generates
|
||||
// this kind of query/response for an 'unkknown' message UID (696969) when trying to copy it
|
||||
// over to the folder "Trash".
|
||||
//
|
||||
// 3 uid copy 696969 "Trash"
|
||||
// 3 OK Completed
|
||||
//
|
||||
// See http://msdn.microsoft.com/en-us/library/gg651088(v=exchg.80).aspx for Status response codes.
|
||||
//
|
||||
if ([prevSuccessfulMoveItemsOps objectForKey: srcMessageId])
|
||||
{
|
||||
// Previous move failed operation but we can recover the dstMessageId from previous request
|
||||
[s appendFormat: @"<SrcMsgId>%@</SrcMsgId>", srcMessageId];
|
||||
[s appendFormat: @"<DstMsgId>%@</DstMsgId>", [prevSuccessfulMoveItemsOps objectForKey: srcMessageId]];
|
||||
[s appendFormat: @"<Status>%d</Status>", 3];
|
||||
[newSuccessfulMoveItemsOps setObject: [prevSuccessfulMoveItemsOps objectForKey: srcMessageId] forKey: srcMessageId];
|
||||
}
|
||||
else
|
||||
{
|
||||
[s appendFormat: @"<Status>%d</Status>", 1];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1493,6 +1563,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[s appendFormat: @"<SrcMsgId>%@</SrcMsgId>", srcMessageId];
|
||||
[s appendFormat: @"<DstMsgId>%@</DstMsgId>", dstMessageId];
|
||||
[s appendFormat: @"<Status>%d</Status>", 3];
|
||||
|
||||
// Save dstMessageId in cache - it will help to recover if the request fails before the response can be sent to client
|
||||
[newSuccessfulMoveItemsOps setObject: dstMessageId forKey: srcMessageId];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1536,11 +1609,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[s appendFormat: @"<SrcMsgId>%@</SrcMsgId>", srcMessageId];
|
||||
[s appendFormat: @"<DstMsgId>%@</DstMsgId>", newUID];
|
||||
[s appendFormat: @"<Status>%d</Status>", 3];
|
||||
|
||||
// Save dstMessageId in cache - it will help to recover if the request fails before the response can be sent to client
|
||||
[newSuccessfulMoveItemsOps setObject: newUID forKey: srcMessageId];
|
||||
}
|
||||
else
|
||||
{
|
||||
[s appendFormat: @"<SrcMsgId>%@</SrcMsgId>", srcMessageId];
|
||||
[s appendFormat: @"<Status>%d</Status>", 1];
|
||||
if ([prevSuccessfulMoveItemsOps objectForKey: srcMessageId])
|
||||
{
|
||||
// Move failed but we can recover the dstMessageId from previous request
|
||||
[s appendFormat: @"<SrcMsgId>%@</SrcMsgId>", srcMessageId];
|
||||
[s appendFormat: @"<DstMsgId>%@</DstMsgId>", [prevSuccessfulMoveItemsOps objectForKey: srcMessageId] ];
|
||||
[s appendFormat: @"<Status>%d</Status>", 3];
|
||||
[newSuccessfulMoveItemsOps setObject: [prevSuccessfulMoveItemsOps objectForKey: srcMessageId] forKey: srcMessageId];
|
||||
}
|
||||
else
|
||||
{
|
||||
[s appendFormat: @"<SrcMsgId>%@</SrcMsgId>", srcMessageId];
|
||||
[s appendFormat: @"<Status>%d</Status>", 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1557,6 +1644,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
}
|
||||
|
||||
[s appendString: @"</Response>"];
|
||||
|
||||
[folderMetadata removeObjectForKey: @"SuccessfulMoveItemsOps"];
|
||||
[folderMetadata setObject: newSuccessfulMoveItemsOps forKey: @"SuccessfulMoveItemsOps"];
|
||||
[self _setFolderMetadata: folderMetadata forKey: nameInCache];
|
||||
}
|
||||
|
||||
[s appendString: @"</MoveItems>"];
|
||||
@@ -2329,21 +2420,23 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
context: (id) theContext
|
||||
{
|
||||
id <DOMElement> documentElement;
|
||||
NSAutoreleasePool *pool;
|
||||
id builder, dom;
|
||||
SEL aSelector;
|
||||
|
||||
NSString *cmdName, *deviceId;
|
||||
NSData *d;
|
||||
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
ASSIGN(context, theContext);
|
||||
|
||||
|
||||
// Get the device ID, device type and "stash" them
|
||||
deviceId = [[theRequest uri] deviceId];
|
||||
[context setObject: deviceId forKey: @"DeviceId"];
|
||||
[context setObject: [[theRequest uri] deviceType] forKey: @"DeviceType"];
|
||||
[context setObject: [[theRequest uri] attachmentName] forKey: @"AttachmentName"];
|
||||
|
||||
|
||||
cmdName = [[theRequest uri] command];
|
||||
|
||||
// We make sure our cache table exists
|
||||
@@ -2379,6 +2472,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{
|
||||
d = [[theRequest content] wbxml2xml];
|
||||
}
|
||||
|
||||
documentElement = nil;
|
||||
|
||||
if (!d)
|
||||
@@ -2414,8 +2508,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
[theResponse setHeader: @"Sync,SendMail,SmartForward,SmartReply,GetAttachment,GetHierarchy,CreateCollection,DeleteCollection,MoveCollection,FolderSync,FolderCreate,FolderDelete,FolderUpdate,MoveItems,GetItemEstimate,MeetingResponse,Search,Settings,Ping,ItemOperations,ResolveRecipients,ValidateCert" forKey: @"MS-ASProtocolCommands"];
|
||||
[theResponse setHeader: @"2.0,2.1,2.5,12.0,12.1,14.0,14.1" forKey: @"MS-ASProtocolVersions"];
|
||||
|
||||
RELEASE(context);
|
||||
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "SOGoMailObject+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSAutoreleasePool.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSException.h>
|
||||
@@ -511,7 +510,6 @@ struct GlobalObjectId {
|
||||
//
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) _context
|
||||
{
|
||||
NSAutoreleasePool *pool;
|
||||
NSData *d, *globalObjId;
|
||||
NSArray *attachmentKeys;
|
||||
NSMutableString *s;
|
||||
@@ -704,10 +702,6 @@ struct GlobalObjectId {
|
||||
// Body - namespace 17
|
||||
preferredBodyType = [[context objectForKey: @"BodyPreferenceType"] intValue];
|
||||
|
||||
// Make use of a local pool here as _preferredBodyDataUsingType:nativeType: will consume
|
||||
// a significant amout of RAM and file descriptors
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
nativeBodyType = 1;
|
||||
d = [self _preferredBodyDataUsingType: preferredBodyType nativeType: &nativeBodyType];
|
||||
|
||||
@@ -747,9 +741,7 @@ struct GlobalObjectId {
|
||||
}
|
||||
[s appendString: @"</Body>"];
|
||||
}
|
||||
|
||||
DESTROY(pool);
|
||||
|
||||
|
||||
// Attachments -namespace 16
|
||||
attachmentKeys = [self fetchFileAttachmentKeys];
|
||||
if ([attachmentKeys count])
|
||||
|
||||
+13
-1
@@ -26,12 +26,23 @@ Alias /SOGo/WebServerResources/ \
|
||||
## need to set the "SOGoTrustProxyAuthentication" SOGo user default to YES and
|
||||
## adjust the "x-webobjects-remote-user" proxy header in the "Proxy" section
|
||||
## below.
|
||||
#
|
||||
## For full proxy-side authentication:
|
||||
#<Location /SOGo>
|
||||
# AuthType XXX
|
||||
# Require valid-user
|
||||
# SetEnv proxy-nokeepalive 1
|
||||
# Allow from all
|
||||
#</Location>
|
||||
#
|
||||
## For proxy-side authentication only for CardDAV and GroupDAV from external
|
||||
## clients:
|
||||
#<Location /SOGo/dav>
|
||||
# AuthType XXX
|
||||
# Require valid-user
|
||||
# SetEnv proxy-nokeepalive 1
|
||||
# Allow from all
|
||||
#</Location>
|
||||
|
||||
ProxyRequests Off
|
||||
SetEnv proxy-nokeepalive 1
|
||||
@@ -64,7 +75,8 @@ ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0
|
||||
|
||||
## When using proxy-side autentication, you need to uncomment and
|
||||
## adjust the following line:
|
||||
# RequestHeader set "x-webobjects-remote-user" "%{REMOTE_USER}e"
|
||||
RequestHeader unset "x-webobjects-remote-user"
|
||||
# RequestHeader set "x-webobjects-remote-user" "%{REMOTE_USER}e" env=REMOTE_USER
|
||||
|
||||
RequestHeader set "x-webobjects-server-protocol" "HTTP/1.0"
|
||||
|
||||
|
||||
@@ -1,3 +1,250 @@
|
||||
commit aac6b22ab56f594e2c796d015e949549bf22e517
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Tue Dec 9 09:08:54 2014 -0500
|
||||
|
||||
Preparation for the release
|
||||
|
||||
M Documentation/docinfo.xml
|
||||
M Documentation/includes/global-attributes.asciidoc
|
||||
M NEWS
|
||||
M Version
|
||||
|
||||
commit 39e8f055d702e0d33da6af130403e1fd0287c102
|
||||
Author: Jens Erat <email@jenserat.de>
|
||||
Date: Tue Dec 9 13:23:21 2014 +0100
|
||||
|
||||
Added information on common configuration issues
|
||||
|
||||
A very common issue (watching the mailing list) is not wrapping the
|
||||
whole configuration in a dictionary. SOGo is not very helpful at
|
||||
debugging broken configuration files, thus hinting `plparse` already
|
||||
installed with the GNUstep runtime.
|
||||
|
||||
M Documentation/SOGoInstallationGuide.asciidoc
|
||||
|
||||
commit 64637d842b9b4979324e98d057909d57c86eb9ec
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Tue Dec 9 07:21:34 2014 -0500
|
||||
|
||||
Prevent compilation failures with old gcc versions
|
||||
|
||||
M Tools/SOGoToolManageEAS.m
|
||||
|
||||
commit 4e6214d6fcaa278f4039765de2b74fd862ced228
|
||||
Author: Jens Erat <email@jenserat.de>
|
||||
Date: Tue Dec 9 13:11:03 2014 +0100
|
||||
|
||||
Fixed ActiveSync URL in documentation
|
||||
|
||||
M Documentation/SOGoInstallationGuide.asciidoc
|
||||
|
||||
commit 12788c847d5ba3d609848bf52589b4c7f3907595
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Mon Dec 8 10:45:34 2014 -0500
|
||||
|
||||
New sogo-tool feature to manage EAS data
|
||||
|
||||
M ActiveSync/SOGoActiveSyncDispatcher+Sync.m
|
||||
M ActiveSync/SOGoActiveSyncDispatcher.m
|
||||
M NEWS
|
||||
M Tools/GNUmakefile
|
||||
A Tools/SOGoToolManageEAS.m
|
||||
|
||||
commit 2b95dd2c0a04b28839a721cb3ba40c674f3981b5
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Mon Dec 8 10:29:23 2014 -0500
|
||||
|
||||
Avoid generating GUID for "Other user"/"Shared" folders
|
||||
|
||||
M SoObjects/Mailer/SOGoMailAccount.m
|
||||
|
||||
commit 9e14a37cb81cf1dce955e5e16440fe413e4f656a
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Mon Dec 8 10:25:37 2014 -0500
|
||||
|
||||
Improvements over fixes for #2982
|
||||
|
||||
M ActiveSync/SOGoActiveSyncDispatcher+Sync.m
|
||||
M ActiveSync/SOGoActiveSyncDispatcher.m
|
||||
|
||||
commit ae0cbfe6a61610acfe3b3325e6cc9ef58332f6b4
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Fri Dec 5 13:52:10 2014 -0500
|
||||
|
||||
Fix for bug #2982
|
||||
|
||||
M ActiveSync/SOGoActiveSyncDispatcher.m
|
||||
M NEWS
|
||||
|
||||
commit 3f3673cf5ad2691c04f975dc58a58173e7c6c2ee
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Thu Dec 4 17:59:17 2014 -0500
|
||||
|
||||
Added SOGoSAML2LogoutURL
|
||||
|
||||
M Documentation/SOGoInstallationGuide.asciidoc
|
||||
M SoObjects/SOGo/SOGoSystemDefaults.h
|
||||
M SoObjects/SOGo/SOGoSystemDefaults.m
|
||||
M UI/MainUI/SOGoSAML2Actions.m
|
||||
|
||||
commit 9ef4d1f551bcfe597395bc7d9ec7bef2ef3e9a0f
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Thu Dec 4 12:21:23 2014 -0500
|
||||
|
||||
Fix for bug #3010
|
||||
|
||||
M NEWS
|
||||
M UI/MainUI/SOGoUserHomePage.m
|
||||
|
||||
commit fe9ad9c6e9b43fa276f6e71972ffd9823e4df9de
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Thu Dec 4 11:27:10 2014 -0500
|
||||
|
||||
Radically reduced EAS memory usage
|
||||
|
||||
M ActiveSync/NSData+ActiveSync.m
|
||||
M ActiveSync/SOGoActiveSyncDispatcher+Sync.m
|
||||
M ActiveSync/SOGoActiveSyncDispatcher.m
|
||||
M ActiveSync/SOGoMailObject+ActiveSync.m
|
||||
M NEWS
|
||||
M SoObjects/SOGo/SOGoCacheGCSObject.m
|
||||
|
||||
commit 47094b6d91c6375bb48160b355c643a628c139be
|
||||
Author: extrafu <lmarcotte@inverse.ca>
|
||||
Date: Tue Dec 2 19:33:54 2014 -0500
|
||||
|
||||
Update SOGoSAML2Metadata.xml
|
||||
|
||||
Fixed XML template generation.
|
||||
|
||||
M SoObjects/SOGo/SOGoSAML2Metadata.xml
|
||||
|
||||
commit 9ffa32eebdcc5d3b102aa4d86a93590684800cdc
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Sun Nov 30 17:35:39 2014 -0500
|
||||
|
||||
Enable SAML support on all Debian-based distro
|
||||
|
||||
M packaging/debian-multiarch/control
|
||||
M packaging/debian-multiarch/rules
|
||||
M packaging/debian/control
|
||||
M packaging/debian/control-squeeze
|
||||
M packaging/debian/rules
|
||||
|
||||
commit 1b715e0812dba3d9f2c4d3f2daa0cbd4313f8def
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Thu Nov 27 11:37:08 2014 -0500
|
||||
|
||||
We now handle correctly the SOGo logout when using SAML (#2376 and #2379)
|
||||
|
||||
M Documentation/SOGoInstallationGuide.asciidoc
|
||||
M NEWS
|
||||
M SoObjects/SOGo/SOGoCASSession.h
|
||||
M SoObjects/SOGo/SOGoCASSession.m
|
||||
M SoObjects/SOGo/SOGoCache.h
|
||||
M SoObjects/SOGo/SOGoCache.m
|
||||
M SoObjects/SOGo/SOGoSAML2Session.h
|
||||
M SoObjects/SOGo/SOGoSAML2Session.m
|
||||
M SoObjects/SOGo/SOGoWebAuthenticator.m
|
||||
M UI/MainUI/SOGoSAML2Actions.m
|
||||
M UI/MainUI/SOGoUserHomePage.m
|
||||
|
||||
commit c3715c94857efa77e1e38b814e0f0ee09cc9c678
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Wed Nov 26 15:27:36 2014 -0500
|
||||
|
||||
Added additional bugfix for #2982
|
||||
|
||||
M ActiveSync/SOGoActiveSyncDispatcher+Sync.m
|
||||
|
||||
commit be608dc76c7217c62152e869ab17c9b237a4e99a
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Wed Nov 26 15:09:30 2014 -0500
|
||||
|
||||
Bug fixes for #2378 and #2377 and documentation improvements
|
||||
|
||||
M Documentation/SOGoInstallationGuide.asciidoc
|
||||
M NEWS
|
||||
A SoObjects/SOGo/SOGoSAML2Metadata.xml
|
||||
M SoObjects/SOGo/SOGoSAML2Session.h
|
||||
M SoObjects/SOGo/SOGoSAML2Session.m
|
||||
M UI/MainUI/SOGoSAML2Actions.m
|
||||
M UI/MainUI/product.plist
|
||||
|
||||
commit 5a5464dc610cddb87b9c07e97699c24a767f5ed7
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Wed Nov 26 13:24:04 2014 -0500
|
||||
|
||||
An other fix for #2930
|
||||
|
||||
M UI/MainUI/SOGoUserHomePage.m
|
||||
|
||||
commit 89917c941caf9f7c4ca18e498bba06298f7f26f6
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Wed Nov 26 13:01:50 2014 -0500
|
||||
|
||||
New entry for bug #2381
|
||||
|
||||
M NEWS
|
||||
|
||||
commit 913a75f410d8e4409960e59c110f707ffad47371
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Wed Nov 26 13:00:47 2014 -0500
|
||||
|
||||
Fix for bug #
|
||||
|
||||
M SoObjects/SOGo/SOGoCache.m
|
||||
M SoObjects/SOGo/SOGoSAML2Session.h
|
||||
M SoObjects/SOGo/SOGoSAML2Session.m
|
||||
M SoObjects/SOGo/SOGoSession.h
|
||||
M SoObjects/SOGo/SOGoSession.m
|
||||
M SoObjects/SOGo/SOGoSystemDefaults.h
|
||||
M SoObjects/SOGo/SOGoSystemDefaults.m
|
||||
|
||||
commit 20e728afac25c9930af97eb2d1fb7519d415c853
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Tue Nov 25 17:28:12 2014 -0500
|
||||
|
||||
Remove unnecessary comments
|
||||
|
||||
M SoObjects/SOGo/SOGoCache.m
|
||||
|
||||
commit 5f14bc11011394ff6f1333880320eec7ceb675af
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Tue Nov 25 17:27:03 2014 -0500
|
||||
|
||||
Report the correct preference keys
|
||||
|
||||
M SoObjects/SOGo/SOGoSAML2Session.m
|
||||
|
||||
commit b0633ba1f454b9b09d646ff0b512f5d13a0f236e
|
||||
Author: Robin McCorkell <rmccorkell@karoshi.org.uk>
|
||||
Date: Tue Jun 18 17:50:28 2013 +0200
|
||||
|
||||
Add check for remote_user variable for trusted proxy auth
|
||||
|
||||
If trusted proxy authentication is on, yet the proxy did not authenticate the
|
||||
user, then the default authentication method is used instead of returning 'Unauthorized'.
|
||||
|
||||
M Apache/SOGo.conf
|
||||
M Main/SOGo.m
|
||||
|
||||
commit bb227443ed632cb03cba58e24259510c9686e1d2
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Sat Nov 22 08:14:31 2014 -0500
|
||||
|
||||
Check lenght of string before trying to use parameters
|
||||
|
||||
M ActiveSync/NSString+ActiveSync.m
|
||||
|
||||
commit efff32e44d1b6df1dfe03f81bbd0e1f449a8fbb2
|
||||
Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
Date: Fri Nov 21 09:13:11 2014 -0500
|
||||
|
||||
Update ChangeLog
|
||||
|
||||
M ChangeLog
|
||||
|
||||
commit f7f78eaba6ac5304df937f5b26f5d21979657787
|
||||
Author: Francis Lachapelle <flachapelle@inverse.ca>
|
||||
Date: Fri Nov 21 09:07:39 2014 -0500
|
||||
|
||||
@@ -273,6 +273,11 @@ is not required, only recommended. Block comments are delimited by `/*`
|
||||
and `*/` and can span multiple lines while line comments must start with
|
||||
`//`.
|
||||
|
||||
The configuration must be contained in a root dictionary, thus be completely
|
||||
wrapped within curly brackets `{ [configuration] }`. If SOGo refuses to
|
||||
start due to syntax errors in its configuration file, `plparse` is helpful
|
||||
for finding these, as it indicates the line containing the problem.
|
||||
|
||||
Preferences Hierarchy
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -425,29 +430,42 @@ Defaults to `YES` when unset.
|
||||
|The location of the SSL private key file on the filesystem that is used
|
||||
by SOGo to sign and encrypt communications with the SAML2 identity
|
||||
provider. This file must be generated for each running SOGo service
|
||||
(rather than host).
|
||||
(rather than host). Make sure this file is readable by the SOGo user.
|
||||
|
||||
|S |SOGoSAML2CertiticateLocation
|
||||
|The location of the SSL certificate file. This file must be generated
|
||||
for each running SOGo service.
|
||||
for each running SOGo service. Make sure this file is readable by the SOGo user.
|
||||
|
||||
|S |SOGoSAML2IdpMetadataLocation
|
||||
|The location of the metadata file that describes the services available
|
||||
on the SAML2 identify provider.
|
||||
on the SAML2 identify provider. The content of this file is usually generated
|
||||
directly by your SAML 2.0 IdP solution. For example, using SimpleSAMLphp, you
|
||||
can get the metadata directly from https://MYSERVER/simplesaml/saml2/idp/metadata.php
|
||||
Make sure this file is readable by the SOGo user.
|
||||
|
||||
|S |SOGoSAML2IdpPublicKeyLocation
|
||||
|The location of the SSL public key file on the filesystem that is used
|
||||
by SOGo to sign and encrypt communications with the SAML2 identity
|
||||
provider. This file should be part of the setup of your identity
|
||||
provider.
|
||||
provider. Make sure this file is readable by the SOGo user.
|
||||
|
||||
|S |SOGoSAML2IdpCertificateLocation
|
||||
|The location of the SSL certificate file. This file should be part of
|
||||
the setup of your identity provider.
|
||||
the setup of your identity provider. Make sure this file is readable by the SOGo user.
|
||||
|
||||
|S |SOGoSAML2LoginAttribute
|
||||
|The attribute provided by the IdP to identify the user in SOGo.
|
||||
|
||||
|S |SOGoSAML2LogoutEnabled
|
||||
|Boolean value indicated whether the "Logout" link is enabled when using
|
||||
SAML2 as authentication mechanism.
|
||||
SAML2 as authentication mechanism. When using this feature, SOGo will invoke
|
||||
the IdP to proceed with the logout procedure. When the user clicks on the logout
|
||||
button, a redirection will be made to the IdP to trigger the logout.
|
||||
|
||||
|S |SOGoSAML2LogoutURL
|
||||
|The URL to which redirect the user after the "Logout" link is clicked.
|
||||
SOGoSAML2LogoutEnabled must be set to YES. If unset, the user will be
|
||||
redirected to a blank page.
|
||||
|
||||
|D |SOGoTimeZone
|
||||
|Parameter used to set a default time zone for users. The default
|
||||
@@ -1230,13 +1248,32 @@ documentation of your identity provider and the SAML2 configuration keys
|
||||
that are listed above for proper setup. Once a SOGo instance is
|
||||
configured properly, the metadata for that instance can be retrieved
|
||||
from `http://<hostname>/SOGo/saml2-metadata` for registration with the
|
||||
identity provider.
|
||||
identity provider. SOGo will dynamically generate the metadata based on
|
||||
the SOGoSAML2CertificateLocation's content and the SOGo server name.
|
||||
|
||||
When using SimpleSAMLphp, make sure the convert OID to names by modifying your
|
||||
`metadata/saml20-idp-hosted.php` to contain something like this:
|
||||
|
||||
----
|
||||
'attributes.NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',
|
||||
'authproc' => array(
|
||||
100 => array('class' => 'core:AttributeMap', 'oid2name'),
|
||||
),
|
||||
----
|
||||
|
||||
If you want to test the IdP-initiated logout using SimpleSAMLphp, you can do so by opening
|
||||
the following URL:
|
||||
|
||||
----
|
||||
https://idp.example.org/simplesaml/saml2/idp/SingleLogoutService.php?ReturnTo=www.sogo.nu
|
||||
----
|
||||
|
||||
In order to relay authentication information to your IMAP server and if
|
||||
you make use of the CrudeSAML SASL plugin, you need to make sure that
|
||||
_NGImap4AuthMechanism_ is configured to use the `SAML` mechanism. If you
|
||||
make use of the CrudeSAML PAM plugin, this value may be left empty.
|
||||
|
||||
|
||||
Database Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -2524,7 +2561,7 @@ any mobile devices that support Microsoft ActiveSync. Microsoft Outlook
|
||||
2013 is also supported.
|
||||
|
||||
The Microsoft ActiveSync server URL is generally something
|
||||
like: `http://localhost/Microsoft-Active-Sync`.
|
||||
like: `http://localhost/Microsoft-Server-ActiveSync`.
|
||||
|
||||
Upgrading
|
||||
---------
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!-- TODO have the build system take care of this -->
|
||||
<releaseinfo>Version 2.2.10 - November 2014</releaseinfo>
|
||||
<subtitle>for version 2.2.10</subtitle>
|
||||
<date>2014-11-21</date>
|
||||
<releaseinfo>Version 2.2.11 - December 2014</releaseinfo>
|
||||
<subtitle>for version 2.2.11</subtitle>
|
||||
<date>2014-12-09</date>
|
||||
|
||||
<legalnotice>
|
||||
<para>Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".</para>
|
||||
|
||||
@@ -13,6 +13,6 @@
|
||||
|
||||
// TODO have the build system take care of this
|
||||
|
||||
:release_version: 2.2.10
|
||||
:release_version: 2.2.11
|
||||
|
||||
// vim: set syntax=asciidoc tabstop=2 shiftwidth=2 expandtab:
|
||||
|
||||
+1
-1
@@ -283,7 +283,7 @@ static BOOL debugLeaks;
|
||||
{
|
||||
id authenticator;
|
||||
|
||||
if (trustProxyAuthentication)
|
||||
if (trustProxyAuthentication && [[context request] headerForKey: @"x-webobjects-remote-user"])
|
||||
authenticator = [SOGoProxyAuthenticator sharedSOGoProxyAuthenticator];
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
2.2.11 (2014-12-09)
|
||||
-------------------
|
||||
|
||||
New features
|
||||
- sogo-tool can now be used to manage EAS metadata for all devices
|
||||
|
||||
Enhancements
|
||||
- Improved the SAML2 documentation
|
||||
- Radically reduced AES memory usage
|
||||
|
||||
Bug fixes
|
||||
- Now possible to specify the username attribute for SAML2 (SOGoSAML2LoginAttribute) (#2381)
|
||||
- Added support for IdP-initiated SAML2 logout (#2377)
|
||||
- We now generate SAML2 metadata on the fly (#2378)
|
||||
- We now handle correctly the SOGo logout when using SAML (#2376 and #2379)
|
||||
- Fixed freebusy lookups going off bounds for resources (#3010)
|
||||
- Fixed EAS clients moving mails between folders but disconnecting before receiving server's response (#2982)
|
||||
|
||||
2.2.10 (2014-11-21)
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -664,7 +664,7 @@ static NSString *inboxFolderName = @"INBOX";
|
||||
|
||||
- (NSDictionary *) imapFolderGUIDs
|
||||
{
|
||||
NSDictionary *result, *nresult, *folderData;
|
||||
NSDictionary *result, *nresult, *namespaceDict;
|
||||
NSMutableDictionary *folders;
|
||||
NGImap4Client *client;
|
||||
SOGoUserDefaults *ud;
|
||||
@@ -684,16 +684,26 @@ static NSString *inboxFolderName = @"INBOX";
|
||||
folders = [NSMutableDictionary dictionary];
|
||||
|
||||
client = [[self imap4Connection] client];
|
||||
namespaceDict = [client namespace];
|
||||
|
||||
result = [client annotation: @"*" entryName: @"/comment" attributeName: @"value.priv"];
|
||||
|
||||
e = [folderList objectEnumerator];
|
||||
|
||||
while (object = [e nextObject])
|
||||
while ((object = [e nextObject]))
|
||||
{
|
||||
guid = [[[[result objectForKey: @"FolderList"] objectForKey: [object substringFromIndex: 1]] objectForKey: @"/comment"] objectForKey: @"value.priv"];
|
||||
|
||||
if (!guid)
|
||||
{
|
||||
// Don't generate a GUID for "Other users" and "Shared" namespace folders - user foldername instead
|
||||
if ([[object substringFromIndex: 1] isEqualToString: [[[[namespaceDict objectForKey: @"other users"] lastObject] objectForKey: @"prefix"] substringFromIndex: 1]] ||
|
||||
[[object substringFromIndex: 1] isEqualToString: [[[[namespaceDict objectForKey: @"shared"] lastObject] objectForKey: @"prefix"] substringFromIndex: 1]])
|
||||
{
|
||||
[folders setObject: [NSString stringWithFormat: @"folder%@", [object substringFromIndex: 1]] forKey: [NSString stringWithFormat: @"folder%@", [object substringFromIndex: 1]]];
|
||||
continue;
|
||||
}
|
||||
|
||||
guid = [[NSProcessInfo processInfo] globallyUniqueString];
|
||||
nresult = [client annotation: [object substringFromIndex: 1] entryName: @"/comment" attributeName: @"value.priv" attributeValue: guid];
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/* SOGoCASSession.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2010 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
* Copyright (C) 2010-2014 Inverse inc.
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/* SOGoCASSession.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2010 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
* Copyright (C) 2010-2014 Inverse inc.
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -132,6 +132,7 @@
|
||||
- (NSDictionary *) saml2LoginDumpsForIdentifier: (NSString *) identifier;
|
||||
- (void) setSaml2LoginDumps: (NSDictionary *) dump
|
||||
forIdentifier: (NSString *) identifier;
|
||||
- (void) removeSAML2LoginDumpsForIdentifier: (NSString *) identifier;
|
||||
|
||||
//
|
||||
// ACL caching support
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
* <uid>+defaults value = NSDictionary instance > user's defaults
|
||||
* <uid>+settings value = NSDictionary instance > user's settings
|
||||
* <uid>+attributes value = NSMutableDictionary instance > user's LDAP attributes
|
||||
* <uid>+failedlogins value =
|
||||
* <uid>+messagesubmissions value =
|
||||
* <uid>+failedlogins value = NSDictionary instance holding the failed count and the date of the first failed authentication
|
||||
* <uid>+messagesubmissions value = NSDictionary instance holding the number of messages sent, and number of recipients
|
||||
* <uid>+dn value = NSString instance > cached user's DN
|
||||
* <object path>+acl value = NSDictionary instance > ACLs on an object at specified path
|
||||
* <groupname>+<domain> value = NSString instance (array components separated by ",") or group member logins for a specific group in domain
|
||||
@@ -40,8 +40,7 @@
|
||||
* cas-ticket:< > value =
|
||||
* cas-pgtiou:< > value =
|
||||
* session:< > value =
|
||||
* <uid>+failedlogins value = NSDictionary instance holding the failed count and the date of the first failed authentication
|
||||
* <uid>+messagesubmissions value = NSDictionary instance holding the number of messages sent, and number of recipients
|
||||
* saml2-login:< > value =
|
||||
*/
|
||||
|
||||
|
||||
@@ -674,11 +673,13 @@ static memcached_st *handle = NULL;
|
||||
{
|
||||
key = [NSString stringWithFormat: @"cas-ticket:%@", ticket];
|
||||
[self removeValueForKey: key];
|
||||
[self debugWithFormat: @"Removed session: %@", session];
|
||||
[self debugWithFormat: @"Removed CAS session: %@", session];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// SAML2 support
|
||||
//
|
||||
- (NSDictionary *) saml2LoginDumpsForIdentifier: (NSString *) identifier
|
||||
{
|
||||
NSString *key, *jsonString;
|
||||
@@ -699,6 +700,16 @@ static memcached_st *handle = NULL;
|
||||
[self setValue: [dump jsonRepresentation] forKey: key];
|
||||
}
|
||||
|
||||
- (void) removeSAML2LoginDumpsForIdentifier: (NSString *) identifier
|
||||
{
|
||||
NSString *key;
|
||||
|
||||
key = [NSString stringWithFormat: @"saml2-login:%@", identifier];
|
||||
|
||||
[self removeValueForKey: key];
|
||||
[self debugWithFormat: @"Removed SAML2 session for identifier: %@", identifier];
|
||||
}
|
||||
|
||||
//
|
||||
// ACL caching code
|
||||
//
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#import <NGExtensions/NGBase64Coding.h>
|
||||
#import <NGExtensions/NSNull+misc.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
#import <SOGo/SOGoCache.h>
|
||||
#import <SOGo/NSObject+Utilities.h>
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
#import <SOGo/SOGoDomainDefaults.h>
|
||||
@@ -96,10 +97,29 @@ static EOAttribute *textColumn = nil;
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
//NSLog(@"SOGoCacheGCSObject: -dealloc for name: %@", nameInContainer);
|
||||
[tableUrl release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
+ (id) objectWithName: (NSString *) key inContainer: (id) theContainer
|
||||
{
|
||||
SOGoCache *cache;
|
||||
id o;
|
||||
|
||||
cache = [SOGoCache sharedCache];
|
||||
o = [cache objectNamed: key inContainer: theContainer];
|
||||
|
||||
if (!o)
|
||||
{
|
||||
o = [super objectWithName: key inContainer: theContainer];
|
||||
//NSLog(@"Caching object with key: %@", key);
|
||||
[cache registerObject: o withName: key inContainer: theContainer];
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
- (void) setTableUrl: (NSURL *) newTableUrl
|
||||
{
|
||||
ASSIGN (tableUrl, newTableUrl);
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<EntityDescriptor
|
||||
entityID="%{base_url}/saml2-metadata"
|
||||
xmlns="urn:oasis:names:tc:SAML:2.0:metadata">
|
||||
<SPSSODescriptor
|
||||
AuthnRequestsSigned="true"
|
||||
WantAssertionsSigned="true"
|
||||
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
|
||||
<KeyDescriptor use="signing"><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:X509Data><ds:X509Certificate>%{certificate}</ds:X509Certificate></ds:X509Data></ds:KeyInfo></KeyDescriptor><KeyDescriptor use="encryption"><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:X509Data><ds:X509Certificate>%{certificate}</ds:X509Certificate></ds:X509Data></ds:KeyInfo></KeyDescriptor>
|
||||
<SingleLogoutService
|
||||
Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
|
||||
Location="%{base_url}/saml2-sls" />
|
||||
<SingleLogoutService
|
||||
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
|
||||
Location="%{base_url}/saml2-sls" />
|
||||
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
|
||||
<AssertionConsumerService
|
||||
index="0"
|
||||
isDefault="true"
|
||||
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
||||
Location="%{base_url}/saml2-signon-post" />
|
||||
<AssertionConsumerService
|
||||
index="1"
|
||||
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
|
||||
Location="%{base_url}/saml2/artifactResponse" />
|
||||
</SPSSODescriptor>
|
||||
</EntityDescriptor>
|
||||
@@ -1,8 +1,6 @@
|
||||
/* SOGoSAML2Session.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2012 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
* Copyright (C) 2012-2014 Inverse inc.
|
||||
*
|
||||
* 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,9 +37,15 @@
|
||||
NSString *login;
|
||||
NSString *identifier;
|
||||
NSString *assertion;
|
||||
NSString *identity;
|
||||
NSString *session;
|
||||
}
|
||||
|
||||
+ (NSString *) metadataInContext: (WOContext *) context;
|
||||
+ (LassoServer *) lassoServerInContext: (WOContext *) context;
|
||||
|
||||
+ (NSString *) metadataInContext: (WOContext *) context
|
||||
certificate: (NSString *) certificate;
|
||||
|
||||
+ (NSString *) authenticationURLInContext: (WOContext *) context;
|
||||
|
||||
+ (SOGoSAML2Session *) SAML2SessionInContext: (WOContext *) context;
|
||||
@@ -54,6 +58,8 @@
|
||||
- (NSString *) login;
|
||||
- (NSString *) identifier;
|
||||
- (NSString *) assertion;
|
||||
- (NSString *) identity;
|
||||
- (NSString *) session;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/* SOGoSAML2Session.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2012 Inverse inc.
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
* Copyright (C) 2012-2014 Inverse inc.
|
||||
*
|
||||
* 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
|
||||
@@ -48,6 +46,28 @@
|
||||
|
||||
#import "SOGoSAML2Session.h"
|
||||
|
||||
@interface NSString (SOGoCertificateExtension)
|
||||
|
||||
- (NSString *) cleanedUpCertificate;
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSString (SOGoCertificateExtension)
|
||||
|
||||
- (NSString *) cleanedUpCertificate
|
||||
{
|
||||
NSMutableArray *a;
|
||||
|
||||
a = [NSMutableArray arrayWithArray: [self componentsSeparatedByString: @"\n"]];
|
||||
[a removeObjectAtIndex: 0];
|
||||
[a removeLastObject];
|
||||
[a removeLastObject];
|
||||
|
||||
return [a componentsJoinedByString: @""];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface WOContext (SOGoSAML2Extension)
|
||||
|
||||
- (NSString *) SAML2ServerURLString;
|
||||
@@ -85,8 +105,7 @@ static NSMapTable *serverTable = nil;
|
||||
lasso_init ();
|
||||
}
|
||||
|
||||
static LassoServer *
|
||||
LassoServerInContext (WOContext *context)
|
||||
+ (LassoServer *) lassoServerInContext: (WOContext *) context
|
||||
{
|
||||
NSString *urlString, *metadata, *filename, *keyContent, *certContent,
|
||||
*idpKeyFilename, *idpCertFilename;
|
||||
@@ -102,7 +121,7 @@ LassoServerInContext (WOContext *context)
|
||||
filename = [sd SAML2PrivateKeyLocation];
|
||||
if (!filename)
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"'SAML2PrivateKeyLocation' not set"];
|
||||
format: @"'SOGoSAML2PrivateKeyLocation' not set"];
|
||||
keyContent = [NSString stringWithContentsOfFile: filename];
|
||||
if (!keyContent)
|
||||
[NSException raise: NSGenericException
|
||||
@@ -112,14 +131,16 @@ LassoServerInContext (WOContext *context)
|
||||
filename = [sd SAML2CertificateLocation];
|
||||
if (!filename)
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"'SAML2CertificateLocation' not set"];
|
||||
format: @"'SOGoSAML2CertificateLocation' not set"];
|
||||
certContent = [NSString stringWithContentsOfFile: filename];
|
||||
if (!certContent)
|
||||
[NSException raise: NSGenericException
|
||||
format: @"certificate file '%@' could not be read",
|
||||
filename];
|
||||
|
||||
metadata = [SOGoSAML2Session metadataInContext: context];
|
||||
metadata = [SOGoSAML2Session metadataInContext: context
|
||||
certificate: certContent];
|
||||
|
||||
/* FIXME: enable key password in config ? */
|
||||
server = lasso_server_new_from_buffers ([metadata UTF8String],
|
||||
[keyContent UTF8String],
|
||||
@@ -148,7 +169,7 @@ LassoServerInContext (WOContext *context)
|
||||
NSString *url;
|
||||
GList *providers;
|
||||
|
||||
server = LassoServerInContext (context);
|
||||
server = [SOGoSAML2Session lassoServerInContext: context];
|
||||
tempLogin = lasso_login_new (server);
|
||||
|
||||
providers = g_hash_table_get_keys (server->providers);
|
||||
@@ -181,8 +202,10 @@ LassoServerInContext (WOContext *context)
|
||||
}
|
||||
|
||||
+ (NSString *) metadataInContext: (WOContext *) context
|
||||
certificate: (NSString *) certificate
|
||||
{
|
||||
NSString *metadata, *serverURLString, *filename;
|
||||
NSString *serverURLString, *filename;
|
||||
NSMutableString *metadata;
|
||||
NSBundle *bundle;
|
||||
|
||||
bundle = [NSBundle bundleForClass: self];
|
||||
@@ -190,9 +213,16 @@ LassoServerInContext (WOContext *context)
|
||||
if (filename)
|
||||
{
|
||||
serverURLString = [context SAML2ServerURLString];
|
||||
metadata = [[NSString stringWithContentsOfFile: filename]
|
||||
stringByReplacingString: @"%{base_url}"
|
||||
withString: serverURLString];
|
||||
|
||||
metadata = [NSMutableString stringWithContentsOfFile: filename];
|
||||
[metadata replaceOccurrencesOfString: @"%{base_url}"
|
||||
withString: serverURLString
|
||||
options: 0
|
||||
range: NSMakeRange(0, [metadata length])];
|
||||
[metadata replaceOccurrencesOfString: @"%{certificate}"
|
||||
withString: [certificate cleanedUpCertificate]
|
||||
options: 0
|
||||
range: NSMakeRange(0, [metadata length])];
|
||||
}
|
||||
else
|
||||
metadata = nil;
|
||||
@@ -208,6 +238,8 @@ LassoServerInContext (WOContext *context)
|
||||
login = nil;
|
||||
identifier = nil;
|
||||
assertion = nil;
|
||||
identity = nil;
|
||||
session = nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -215,7 +247,6 @@ LassoServerInContext (WOContext *context)
|
||||
|
||||
- (void) _updateDataFromLogin
|
||||
{
|
||||
// LassoSamlp2Response *response;
|
||||
LassoSaml2Assertion *saml2Assertion;
|
||||
GList *statementList, *attributeList;
|
||||
LassoSaml2AttributeStatement *statement;
|
||||
@@ -223,10 +254,15 @@ LassoServerInContext (WOContext *context)
|
||||
LassoSaml2AttributeValue *value;
|
||||
LassoMiscTextNode *textNode;
|
||||
LassoSaml2NameID *nameIdentifier;
|
||||
SOGoSystemDefaults *sd;
|
||||
NSString *loginAttribue;
|
||||
|
||||
gchar *dump;
|
||||
|
||||
saml2Assertion
|
||||
= LASSO_SAML2_ASSERTION (lasso_login_get_assertion (lassoLogin));
|
||||
saml2Assertion = LASSO_SAML2_ASSERTION (lasso_login_get_assertion (lassoLogin));
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
loginAttribue = [sd SAML2LoginAttribute];
|
||||
|
||||
if (saml2Assertion)
|
||||
{
|
||||
/* deduce user login */
|
||||
@@ -241,22 +277,42 @@ LassoServerInContext (WOContext *context)
|
||||
while (!login && attributeList)
|
||||
{
|
||||
attribute = LASSO_SAML2_ATTRIBUTE (attributeList->data);
|
||||
if (strcmp (attribute->Name, "uid") == 0)
|
||||
if (loginAttribue && (strcmp (attribute->Name, [loginAttribue UTF8String]) == 0))
|
||||
{
|
||||
value = LASSO_SAML2_ATTRIBUTE_VALUE (attribute->AttributeValue->data);
|
||||
textNode = value->any->data;
|
||||
|
||||
// If we got an @ sign in the value, it's most likely an email address
|
||||
// so we'll ask SOGoUserManager about this
|
||||
login = [NSString stringWithUTF8String: textNode->content];
|
||||
|
||||
if ([login rangeOfString: @"@"].location != NSNotFound)
|
||||
{
|
||||
login = [[SOGoUserManager sharedUserManager] getUIDForEmail: login];
|
||||
}
|
||||
|
||||
[login retain];
|
||||
}
|
||||
else if (strcmp (attribute->Name, "mail") == 0)
|
||||
else if (!loginAttribue)
|
||||
{
|
||||
value = LASSO_SAML2_ATTRIBUTE_VALUE (attribute->AttributeValue->data);
|
||||
textNode = value->any->data;
|
||||
login = [[SOGoUserManager sharedUserManager] getUIDForEmail: [NSString stringWithUTF8String: textNode->content]];
|
||||
[login retain];
|
||||
// We fallback on "standard" attributes such as "uid" and "mail"
|
||||
if (strcmp (attribute->Name, "uid") == 0)
|
||||
{
|
||||
value = LASSO_SAML2_ATTRIBUTE_VALUE (attribute->AttributeValue->data);
|
||||
textNode = value->any->data;
|
||||
login = [NSString stringWithUTF8String: textNode->content];
|
||||
[login retain];
|
||||
}
|
||||
else if (strcmp (attribute->Name, "mail") == 0)
|
||||
{
|
||||
value = LASSO_SAML2_ATTRIBUTE_VALUE (attribute->AttributeValue->data);
|
||||
textNode = value->any->data;
|
||||
login = [[SOGoUserManager sharedUserManager] getUIDForEmail: [NSString stringWithUTF8String: textNode->content]];
|
||||
[login retain];
|
||||
}
|
||||
}
|
||||
else
|
||||
attributeList = attributeList->next;
|
||||
|
||||
attributeList = attributeList->next;
|
||||
}
|
||||
statementList = statementList->next;
|
||||
}
|
||||
@@ -295,7 +351,7 @@ LassoServerInContext (WOContext *context)
|
||||
|
||||
if ((self = [self init]))
|
||||
{
|
||||
server = LassoServerInContext (context);
|
||||
server = [SOGoSAML2Session lassoServerInContext: context];
|
||||
lassoLogin = lasso_login_new (server);
|
||||
if (saml2Dump)
|
||||
{
|
||||
@@ -303,12 +359,17 @@ LassoServerInContext (WOContext *context)
|
||||
ASSIGN (login, [saml2Dump objectForKey: @"login"]);
|
||||
ASSIGN (identifier, [saml2Dump objectForKey: @"identifier"]);
|
||||
ASSIGN (assertion, [saml2Dump objectForKey: @"assertion"]);
|
||||
dump = [[saml2Dump objectForKey: @"identity"] UTF8String];
|
||||
|
||||
ASSIGN(identity, [saml2Dump objectForKey: @"identity"]);
|
||||
dump = [identity UTF8String];
|
||||
if (dump)
|
||||
lasso_profile_set_identity_from_dump (profile, dump);
|
||||
dump = [[saml2Dump objectForKey: @"session"] UTF8String];
|
||||
|
||||
ASSIGN (session, [saml2Dump objectForKey: @"session"]);
|
||||
dump = [session UTF8String];
|
||||
if (dump)
|
||||
lasso_profile_set_session_from_dump (profile, dump);
|
||||
|
||||
lasso_login_accept_sso (lassoLogin);
|
||||
// if (rc)
|
||||
// [NSException raiseSAML2Exception: rc];
|
||||
@@ -326,6 +387,9 @@ LassoServerInContext (WOContext *context)
|
||||
[login release];
|
||||
[identifier release];
|
||||
[assertion release];
|
||||
[identity release];
|
||||
[session release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -378,13 +442,23 @@ LassoServerInContext (WOContext *context)
|
||||
return assertion;
|
||||
}
|
||||
|
||||
- (NSString *) identity
|
||||
{
|
||||
return identity;
|
||||
}
|
||||
|
||||
- (NSString *) session
|
||||
{
|
||||
return session;
|
||||
}
|
||||
|
||||
- (void) processAuthnResponse: (NSString *) authnResponse
|
||||
{
|
||||
lasso_error_t rc;
|
||||
gchar *responseData, *dump;
|
||||
LassoProfile *profile;
|
||||
LassoIdentity *identity;
|
||||
LassoSession *session;
|
||||
LassoIdentity *lasso_identity;
|
||||
LassoSession *lasso_session;
|
||||
NSString *nsDump;
|
||||
NSMutableDictionary *saml2Dump;
|
||||
|
||||
@@ -408,22 +482,22 @@ LassoServerInContext (WOContext *context)
|
||||
|
||||
profile = LASSO_PROFILE (lassoLogin);
|
||||
|
||||
session = lasso_profile_get_session (profile);
|
||||
if (session)
|
||||
lasso_session = lasso_profile_get_session (profile);
|
||||
if (lasso_session)
|
||||
{
|
||||
dump = lasso_session_dump (session);
|
||||
dump = lasso_session_dump (lasso_session);
|
||||
nsDump = [NSString stringWithUTF8String: dump];
|
||||
[saml2Dump setObject: nsDump forKey: @"session"];
|
||||
lasso_session_destroy (session);
|
||||
lasso_session_destroy (lasso_session);
|
||||
}
|
||||
|
||||
identity = lasso_profile_get_identity (profile);
|
||||
if (identity)
|
||||
lasso_identity = lasso_profile_get_identity (profile);
|
||||
if (lasso_identity)
|
||||
{
|
||||
dump = lasso_identity_dump (identity);
|
||||
dump = lasso_identity_dump (lasso_identity);
|
||||
nsDump = [NSString stringWithUTF8String: dump];
|
||||
[saml2Dump setObject: nsDump forKey: @"identity"];
|
||||
lasso_identity_destroy (identity);
|
||||
lasso_identity_destroy (lasso_identity);
|
||||
}
|
||||
|
||||
[[SOGoCache sharedCache] setSaml2LoginDumps: saml2Dump
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
/* SOGoSession.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2010-2011 Inverse inc.
|
||||
*
|
||||
* Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
* Francis Lachapelle <flachapelle@inverse.ca>
|
||||
* Copyright (C) 2010-2014 Inverse inc.
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
/* SOGoSession.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2010-2011 Inverse inc.
|
||||
*
|
||||
* Author: Ludovic Marcotte <lmarcotte@inverse.ca>
|
||||
* Francis Lachapelle <flachapelle@inverse.ca>
|
||||
|
||||
* Copyright (C) 2010-2014 Inverse inc.
|
||||
*
|
||||
* 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
|
||||
|
||||
@@ -80,7 +80,9 @@
|
||||
- (NSString *) SAML2IdpMetadataLocation;
|
||||
- (NSString *) SAML2IdpPublicKeyLocation;
|
||||
- (NSString *) SAML2IdpCertificateLocation;
|
||||
- (NSString *) SAML2LoginAttribute;
|
||||
- (BOOL) SAML2LogoutEnabled;
|
||||
- (NSString *) SAML2LogoutURL;
|
||||
|
||||
- (BOOL) enablePublicAccess;
|
||||
|
||||
|
||||
@@ -511,6 +511,16 @@ _injectConfigurationFromFile (NSMutableDictionary *defaultsDict,
|
||||
return [self boolForKey: @"SOGoSAML2LogoutEnabled"];
|
||||
}
|
||||
|
||||
- (NSString *) SAML2LogoutURL
|
||||
{
|
||||
return [self stringForKey: @"SOGoSAML2LogoutURL"];
|
||||
}
|
||||
|
||||
- (NSString *) SAML2LoginAttribute
|
||||
{
|
||||
return [self stringForKey: @"SOGoSAML2LoginAttribute"];
|
||||
}
|
||||
|
||||
- (BOOL) enablePublicAccess
|
||||
{
|
||||
return [self boolForKey: @"SOGoEnablePublicAccess"];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SOGoWebAuthenticator.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2007-2013 Inverse inc.
|
||||
* Copyright (C) 2007-2014 Inverse inc.
|
||||
*
|
||||
* 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
|
||||
|
||||
+2
-1
@@ -22,7 +22,8 @@ $(SOGO_TOOL)_OBJC_FILES += \
|
||||
SOGoToolRemoveDoubles.m \
|
||||
SOGoToolRenameUser.m \
|
||||
SOGoToolRestore.m \
|
||||
SOGoToolUserPreferences.m
|
||||
SOGoToolUserPreferences.m \
|
||||
SOGoToolManageEAS.m
|
||||
TOOL_NAME += $(SOGO_TOOL)
|
||||
|
||||
###
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
/* SOGoToolManageEAS.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2014 Inverse inc.
|
||||
*
|
||||
* 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 <Foundation/NSArray.h>
|
||||
#import <Foundation/NSCharacterSet.h>
|
||||
#import <Foundation/NSData.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSUserDefaults.h>
|
||||
#import <Foundation/NSURL.h>
|
||||
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
#import <NGObjWeb/WOApplication.h>
|
||||
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
#import <SOGo/SOGoProductLoader.h>
|
||||
#import "SOGo/SOGoCredentialsFile.h"
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserFolder.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
#import <SOGo/SOGoSystemDefaults.h>
|
||||
#import <SOGo/SOGoUserSettings.h>
|
||||
#import <Mailer/SOGoMailAccounts.h>
|
||||
#import <Mailer/SOGoMailAccount.h>
|
||||
|
||||
#import <SOGo/SOGoCacheGCSObject.h>
|
||||
|
||||
|
||||
#import "SOGoTool.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ManageEASUnknown = -1,
|
||||
ManageEASListDevices = 0,
|
||||
ManageEASListFolders = 2,
|
||||
ManageEASResetDevice = 3,
|
||||
ManageEASRestFolder = 4,
|
||||
} SOGoManageEASCommand;
|
||||
|
||||
@interface SOGoToolManageEAS : SOGoTool
|
||||
@end
|
||||
|
||||
@implementation SOGoToolManageEAS
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
}
|
||||
|
||||
+ (NSString *) command
|
||||
{
|
||||
return @"manage-eas";
|
||||
}
|
||||
|
||||
+ (NSString *) description
|
||||
{
|
||||
return @"manage EAS folders";
|
||||
}
|
||||
|
||||
- (void) usage
|
||||
{
|
||||
fprintf (stderr, "manage-eas listdevices|resetdevice|resetfolder user <devinceId | folderId> \n\n"
|
||||
" user the user of whom to reset the whole device or a single folder\n"
|
||||
" Examples:\n"
|
||||
" sogo-tool manage-eas listdevices janedoe\n"
|
||||
" sogo-tool manage-eas listfolders janedoe androidc316986417\n"
|
||||
" sogo-tool manage-eas resetdevice janedoe androidc316986417\n"
|
||||
" sogo-tool manage-eas resetfolder janedow androidc316986417+folderlala-dada-sasa_7a13_1a2386e0_e\n") ;
|
||||
}
|
||||
|
||||
|
||||
- (SOGoManageEASCommand) _cmdFromString: (NSString *) theString
|
||||
{
|
||||
if ([theString length] > 2)
|
||||
{
|
||||
if ([theString caseInsensitiveCompare: @"listdevices"] == NSOrderedSame)
|
||||
return ManageEASListDevices;
|
||||
else if ([theString caseInsensitiveCompare: @"listfolders"] == NSOrderedSame)
|
||||
return ManageEASListFolders;
|
||||
else if ([theString caseInsensitiveCompare: @"resetdevice"] == NSOrderedSame)
|
||||
return ManageEASResetDevice;
|
||||
else if ([theString caseInsensitiveCompare: @"resetfolder"] == NSOrderedSame)
|
||||
return ManageEASRestFolder;
|
||||
}
|
||||
|
||||
return ManageEASUnknown;
|
||||
}
|
||||
|
||||
- (BOOL) run
|
||||
{
|
||||
NSString *userId;
|
||||
SOGoManageEASCommand cmd;
|
||||
SOGoCacheGCSObject *oc, *foc;
|
||||
NSString *urlString, *ocFSTableName, *deviceId;
|
||||
NSURL *folderTableURL;
|
||||
NSMutableArray *parts;
|
||||
NSArray *entries;
|
||||
id cacheEntry;
|
||||
|
||||
BOOL rc;
|
||||
int i, max;
|
||||
|
||||
max = [sanitizedArguments count];
|
||||
rc = NO;
|
||||
|
||||
if (max > 1)
|
||||
{
|
||||
SOGoUser *user;
|
||||
|
||||
cmd = [self _cmdFromString: [sanitizedArguments objectAtIndex: 0]];
|
||||
|
||||
userId = [sanitizedArguments objectAtIndex: 1];
|
||||
|
||||
user = [SOGoUser userWithLogin: userId];
|
||||
|
||||
if (![user loginInDomain])
|
||||
return NO;
|
||||
|
||||
urlString = [[user domainDefaults] folderInfoURL];
|
||||
parts = [[urlString componentsSeparatedByString: @"/"]
|
||||
mutableCopy];
|
||||
[parts autorelease];
|
||||
if ([parts count] == 5)
|
||||
{
|
||||
/* If "OCSFolderInfoURL" is properly configured, we must have 5
|
||||
parts in this url. We strip the '-' character in case we have
|
||||
this in the domain part - like foo@bar-zot.com */
|
||||
ocFSTableName = [NSString stringWithFormat: @"sogo_cache_folder_%@",
|
||||
[[[user loginInDomain] asCSSIdentifier]
|
||||
stringByReplacingOccurrencesOfString: @"-"
|
||||
withString: @"_"]];
|
||||
[parts replaceObjectAtIndex: 4 withObject: ocFSTableName];
|
||||
folderTableURL
|
||||
= [NSURL URLWithString: [parts componentsJoinedByString: @"/"]];
|
||||
[folderTableURL retain];
|
||||
}
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case ManageEASListDevices:
|
||||
oc = [SOGoCacheGCSObject objectWithName: @"0" inContainer: nil];
|
||||
[oc setObjectType: ActiveSyncGlobalCacheObject];
|
||||
|
||||
[oc setTableUrl: folderTableURL];
|
||||
entries = [oc cacheEntriesForDeviceId: nil newerThanVersion: -1];
|
||||
|
||||
for (i = 0; i < [entries count]; i++)
|
||||
{
|
||||
cacheEntry = [entries objectAtIndex: i];
|
||||
fprintf(stdout,"%s\n", [[cacheEntry substringFromIndex: 1] UTF8String]);
|
||||
}
|
||||
|
||||
rc = YES;
|
||||
break;
|
||||
|
||||
case ManageEASListFolders:
|
||||
if (max > 2)
|
||||
{
|
||||
/* value specified on command line */
|
||||
deviceId = [sanitizedArguments objectAtIndex: 2];
|
||||
|
||||
oc = [SOGoCacheGCSObject objectWithName: @"0" inContainer: nil];
|
||||
[oc setObjectType: ActiveSyncFolderCacheObject];
|
||||
|
||||
[oc setTableUrl: folderTableURL];
|
||||
entries = [oc cacheEntriesForDeviceId: deviceId newerThanVersion: -1];
|
||||
|
||||
for (i = 0; i < [entries count]; i++)
|
||||
{
|
||||
cacheEntry = [entries objectAtIndex: i];
|
||||
fprintf(stdout,"Folder Key: %s\n", [[cacheEntry substringFromIndex: 1] UTF8String]);
|
||||
|
||||
foc = [SOGoCacheGCSObject objectWithName: [cacheEntry substringFromIndex: 1] inContainer: nil];
|
||||
[foc setObjectType: ActiveSyncFolderCacheObject];
|
||||
[foc setTableUrl: folderTableURL];
|
||||
|
||||
[foc reloadIfNeeded];
|
||||
|
||||
fprintf(stdout, " Folder Name: %s\n\n", [[[foc properties] objectForKey: @"displayName"] UTF8String]);
|
||||
|
||||
if (verbose)
|
||||
fprintf(stdout, " metadata Name: %s\n\n", [[[foc properties] description] UTF8String]);
|
||||
}
|
||||
|
||||
rc = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "\nERROR: deviceId not specified\n\n");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case ManageEASResetDevice:
|
||||
if (max > 2)
|
||||
{
|
||||
/* value specified on command line */
|
||||
deviceId = [sanitizedArguments objectAtIndex: 2];
|
||||
oc = [SOGoCacheGCSObject objectWithName: deviceId inContainer: nil];
|
||||
[oc setObjectType: ActiveSyncGlobalCacheObject];
|
||||
[oc setTableUrl: folderTableURL];
|
||||
|
||||
[oc reloadIfNeeded];
|
||||
if ([oc isNew]) {
|
||||
fprintf(stderr, "ERROR: Device with ID '%s' not found\n", [deviceId UTF8String]);
|
||||
return rc;
|
||||
}
|
||||
|
||||
NSMutableString *sql;
|
||||
|
||||
sql = [NSMutableString stringWithFormat: @"DELETE FROM %@" @" WHERE c_path like '/%@'", [oc tableName], deviceId];
|
||||
|
||||
[oc performBatchSQLQueries: [NSArray arrayWithObject: sql]];
|
||||
rc = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "\nERROR: deviceId not specified\n\n");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ManageEASRestFolder:
|
||||
if (max > 2)
|
||||
{
|
||||
/* value specified on command line */
|
||||
deviceId = [sanitizedArguments objectAtIndex: 2];
|
||||
|
||||
//if ([deviceId rangeOfString: @"+"].location == NSNotFound) {
|
||||
// fprintf(stderr, "ERROR: Deviceid invalid folder \"%@\" not found\n", deviceId);
|
||||
// return rc;
|
||||
//}
|
||||
|
||||
oc = [SOGoCacheGCSObject objectWithName: deviceId inContainer: nil];
|
||||
[oc setObjectType: ActiveSyncFolderCacheObject];
|
||||
[oc setTableUrl: folderTableURL];
|
||||
|
||||
[oc reloadIfNeeded];
|
||||
|
||||
if ([oc isNew]) {
|
||||
fprintf(stderr, "ERROR: Folder with ID \"%s\" not found\n", [deviceId UTF8String]);
|
||||
return rc;
|
||||
}
|
||||
[[oc properties] removeObjectForKey: @"SyncKey"];
|
||||
[[oc properties] removeObjectForKey: @"SyncCache"];
|
||||
[[oc properties] removeObjectForKey: @"DateCache"];
|
||||
[[oc properties] removeObjectForKey: @"MoreAvailable"];
|
||||
|
||||
[oc save];
|
||||
rc = YES;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "\nERROR: folderId not specified\n\n");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ManageEASUnknown:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
{
|
||||
[self usage];
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -32,7 +32,10 @@
|
||||
#import <NGExtensions/NSCalendarDate+misc.h>
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
|
||||
#import <SOGo/SOGoCache.h>
|
||||
#import <SOGo/SOGoSAML2Session.h>
|
||||
#import <SOGo/SOGoSession.h>
|
||||
#import <SOGo/SOGoSystemDefaults.h>
|
||||
#import <SOGo/SOGoWebAuthenticator.h>
|
||||
|
||||
@interface SOGoSAML2Actions : WODirectAction
|
||||
@@ -42,20 +45,100 @@
|
||||
|
||||
- (WOResponse *) saml2MetadataAction
|
||||
{
|
||||
NSString *metadata, *certContent;
|
||||
SOGoSystemDefaults *sd;
|
||||
WOResponse *response;
|
||||
NSString *metadata;
|
||||
|
||||
response = [context response];
|
||||
[response setHeader: @"application/xml; charset=utf-8"
|
||||
forKey: @"content-type"];
|
||||
|
||||
metadata = [SOGoSAML2Session metadataInContext: context];
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
|
||||
certContent = [NSString stringWithContentsOfFile: [sd SAML2CertificateLocation]];
|
||||
|
||||
metadata = [SOGoSAML2Session metadataInContext: context
|
||||
certificate: certContent];
|
||||
|
||||
[response setContentEncoding: NSUTF8StringEncoding];
|
||||
[response appendContentString: metadata];
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (WOResponse *) saml2SingleLogoutServiceAction
|
||||
{
|
||||
NSString *userName, *value, *cookieName, *domain, *username, *password;
|
||||
SOGoWebAuthenticator *auth;
|
||||
SOGoSystemDefaults *sd;
|
||||
WOResponse *response;
|
||||
NSCalendarDate *date;
|
||||
WOCookie *cookie;
|
||||
NSArray *creds;
|
||||
|
||||
userName = [[context activeUser] login];
|
||||
[self logWithFormat: @"SAML2 IdP-initiated SLO for user '%@'", userName];
|
||||
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
|
||||
response = [context response];
|
||||
|
||||
if ([sd SAML2LogoutURL])
|
||||
{
|
||||
[response setStatus: 302];
|
||||
[response setHeader: [sd SAML2LogoutURL] forKey: @"location"];
|
||||
}
|
||||
|
||||
if ([userName isEqualToString: @"anonymous"])
|
||||
return response;
|
||||
|
||||
cookie = nil;
|
||||
|
||||
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 = [[SoApplication application] authenticatorInContext: context];
|
||||
|
||||
if ([auth respondsToSelector: @selector (cookieNameInContext:)])
|
||||
{
|
||||
cookieName = [auth cookieNameInContext: context];
|
||||
value = [[context request] cookieValueForKey: cookieName];
|
||||
creds = [auth parseCredentials: value];
|
||||
|
||||
// We first delete our memcached entry
|
||||
value = [SOGoSession valueForSessionKey: [creds lastObject]];
|
||||
domain = nil;
|
||||
|
||||
[SOGoSession decodeValue: value
|
||||
usingKey: [creds objectAtIndex: 0]
|
||||
login: &username
|
||||
domain: &domain
|
||||
password: &password];
|
||||
|
||||
[[SOGoCache sharedCache] removeSAML2LoginDumpsForIdentifier: password];
|
||||
|
||||
if ([creds count] > 1)
|
||||
[SOGoSession deleteValueForSessionKey: [creds objectAtIndex: 1]];
|
||||
|
||||
if ([cookieName length])
|
||||
{
|
||||
cookie = [WOCookie cookieWithName: cookieName value: @"discard"];
|
||||
[cookie setPath: [NSString stringWithFormat: @"/%@/", [[context request] applicationName]]];
|
||||
[cookie setExpires: [date yesterday]];
|
||||
}
|
||||
}
|
||||
|
||||
if (cookie)
|
||||
[response addCookie: cookie];
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
- (WOCookie *) _authLocationResetCookieWithName: (NSString *) cookieName
|
||||
{
|
||||
WOCookie *locationCookie;
|
||||
|
||||
@@ -33,7 +33,12 @@
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
|
||||
#import <Appointments/SOGoFreeBusyObject.h>
|
||||
|
||||
#import <SOGo/SOGoCache.h>
|
||||
#import <SOGo/SOGoCASSession.h>
|
||||
#if defined(SAML2_CONFIG)
|
||||
#import <SOGo/SOGoSAML2Session.h>
|
||||
#endif
|
||||
#import <SOGo/SOGoUserManager.h>
|
||||
#import <SOGo/SOGoWebAuthenticator.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
@@ -216,21 +221,22 @@
|
||||
|
||||
interval = [endDate timeIntervalSinceDate: startDate] + 60;
|
||||
|
||||
// Slices of 15 minutes. The +4 is to take into account that we can
|
||||
// have a timezone change during the freebusy lookup.
|
||||
intervals = interval / intervalSeconds + 4;
|
||||
// Slices of 15 minutes. The +8 is to take into account that we can
|
||||
// have a timezone change during the freebusy lookup. We have +4 at the
|
||||
// beginning and +4 at the end.
|
||||
intervals = interval / intervalSeconds + 8;
|
||||
|
||||
// Build a bit string representation of the freebusy data for the period
|
||||
freeBusyItems = NSZoneCalloc (NULL, intervals, sizeof (int));
|
||||
[self _fillFreeBusyItems: freeBusyItems
|
||||
count: intervals
|
||||
[self _fillFreeBusyItems: (freeBusyItems+4)
|
||||
count: (intervals-4)
|
||||
withRecords: [fb fetchFreeBusyInfosFrom: start to: end forContact: uid]
|
||||
fromStartDate: startDate
|
||||
toEndDate: endDate];
|
||||
|
||||
// Convert bit string to a NSArray
|
||||
// Convert bit string to a NSArray. We also skip by the default the non-requested information.
|
||||
freeBusy = [NSMutableArray arrayWithCapacity: intervals];
|
||||
for (count = 0; count < intervals; count++)
|
||||
for (count = 4; count < (intervals-4); count++)
|
||||
{
|
||||
[freeBusy addObject: [NSString stringWithFormat: @"%d", *(freeBusyItems + count)]];
|
||||
}
|
||||
@@ -299,14 +305,57 @@
|
||||
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
if ([[sd authenticationType] isEqualToString: @"cas"])
|
||||
redirectURL = [SOGoCASSession CASURLWithAction: @"logout"
|
||||
andParameters: nil];
|
||||
{
|
||||
redirectURL = [SOGoCASSession CASURLWithAction: @"logout"
|
||||
andParameters: nil];
|
||||
}
|
||||
#if defined(SAML2_CONFIG)
|
||||
else if ([[sd authenticationType] isEqualToString: @"saml2"])
|
||||
{
|
||||
NSString *username, *password, *domain, *value;
|
||||
SOGoSAML2Session *saml2Session;
|
||||
SOGoWebAuthenticator *auth;
|
||||
LassoServer *server;
|
||||
LassoLogout *logout;
|
||||
NSArray *creds;
|
||||
|
||||
auth = [[self clientObject] authenticatorInContext: context];
|
||||
value = [[context request] cookieValueForKey: [auth cookieNameInContext: context]];
|
||||
creds = [auth parseCredentials: value];
|
||||
|
||||
value = [SOGoSession valueForSessionKey: [creds lastObject]];
|
||||
|
||||
domain = nil;
|
||||
|
||||
[SOGoSession decodeValue: value
|
||||
usingKey: [creds objectAtIndex: 0]
|
||||
login: &username
|
||||
domain: &domain
|
||||
password: &password];
|
||||
|
||||
saml2Session = [SOGoSAML2Session SAML2SessionWithIdentifier: password
|
||||
inContext: context];
|
||||
|
||||
server = [SOGoSAML2Session lassoServerInContext: context];
|
||||
|
||||
logout = lasso_logout_new(server);
|
||||
|
||||
lasso_profile_set_session_from_dump(LASSO_PROFILE(logout), [[saml2Session session] UTF8String]);
|
||||
lasso_profile_set_identity_from_dump(LASSO_PROFILE(logout), [[saml2Session session] UTF8String]);
|
||||
lasso_logout_init_request(logout, NULL, LASSO_HTTP_METHOD_REDIRECT);
|
||||
lasso_logout_build_request_msg(logout);
|
||||
redirectURL = [NSString stringWithFormat: @"%s", LASSO_PROFILE(logout)->msg_url];
|
||||
|
||||
// We destroy our cache entry, the session will be taken care by the caller
|
||||
[[SOGoCache sharedCache] removeSAML2LoginDumpsForIdentifier: password];
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
container = [[self clientObject] container];
|
||||
redirectURL = [container baseURLInContext: context];
|
||||
}
|
||||
|
||||
|
||||
return redirectURL;
|
||||
}
|
||||
|
||||
|
||||
@@ -133,6 +133,11 @@
|
||||
actionClass = "SOGoSAML2Actions";
|
||||
actionName = "saml2SignOnPOST";
|
||||
};
|
||||
saml2-sls = {
|
||||
protectedBy = "<public>";
|
||||
actionClass = "SOGoSAML2Actions";
|
||||
actionName = "saml2SingleLogoutService";
|
||||
};
|
||||
/* saml2-signon-redirect = {
|
||||
protectedBy = "<public>";
|
||||
actionClass = "SOGoSAML2Actions";
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
|
||||
MAJOR_VERSION=2
|
||||
MINOR_VERSION=2
|
||||
SUBMINOR_VERSION=10
|
||||
SUBMINOR_VERSION=11
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Source: sogo
|
||||
Priority: optional
|
||||
Maintainer: Inverse Support <support@inverse.ca>
|
||||
Build-Depends: debhelper (>= 8.0.0), gobjc | objc-compiler, libgnustep-base-dev, libsope-appserver4.9-dev, libsope-core4.9-dev, libsope-gdl1-4.9-dev, libsope-ldap4.9-dev, libsope-mime4.9-dev, libsope-xml4.9-dev, libmemcached-dev, libxml2-dev, libsbjson-dev, libssl-dev, libcurl4-openssl-dev | libcurl4-gnutls-dev, libmapi-dev, libmapistore-dev, libmapiproxy-dev, libwbxml2-dev (>= 0.11.2)
|
||||
Build-Depends: debhelper (>= 8.0.0), gobjc | objc-compiler, libgnustep-base-dev, libsope-appserver4.9-dev, libsope-core4.9-dev, libsope-gdl1-4.9-dev, libsope-ldap4.9-dev, libsope-mime4.9-dev, libsope-xml4.9-dev, libmemcached-dev, libxml2-dev, libsbjson-dev, libssl-dev, libcurl4-openssl-dev | libcurl4-gnutls-dev, libmapi-dev, libmapistore-dev, libmapiproxy-dev, libwbxml2-dev (>= 0.11.2), liblasso3-dev (>= 2.3.5)
|
||||
Section: web
|
||||
Standards-Version: 3.9.2
|
||||
|
||||
@@ -10,7 +10,7 @@ Pre-Depends: ${misc:Pre-Depends}
|
||||
Multi-Arch: same
|
||||
Section: web
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, tmpreaper, sope4.9-libxmlsaxdriver, sope4.9-db-connector, gnustep-make, libcurl3, zip
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, tmpreaper, sope4.9-libxmlsaxdriver, sope4.9-db-connector, gnustep-make, libcurl3, zip, liblasso3 (>= 2.3.5)
|
||||
Recommends: memcached
|
||||
Suggests: nginx
|
||||
Description: a modern and scalable groupware
|
||||
|
||||
@@ -6,12 +6,14 @@ export DH_VERBOSE=1
|
||||
DESTDIR=$(CURDIR)/debian/tmp
|
||||
DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
|
||||
|
||||
SAML2_CONFIG=--enable-saml2
|
||||
|
||||
include /etc/GNUstep/GNUstep.conf
|
||||
include /usr/share/GNUstep/Makefiles/common.make
|
||||
|
||||
config.make: configure
|
||||
dh_testdir
|
||||
./configure --prefix=$(GNUSTEP_SYSTEM_ROOT)
|
||||
./configure --prefix=$(GNUSTEP_SYSTEM_ROOT) $(SAML2_CONFIG)
|
||||
|
||||
#Architecture
|
||||
build: build-arch
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
Source: sogo
|
||||
Priority: optional
|
||||
Maintainer: Inverse Support <support@inverse.ca>
|
||||
Build-Depends: debhelper (>= 7.0.15), gobjc | objc-compiler, libgnustep-base-dev, libsope-appserver4.9-dev, libsope-core4.9-dev, libsope-gdl1-4.9-dev, libsope-ldap4.9-dev, libsope-mime4.9-dev, libsope-xml4.9-dev, libmemcached-dev, libxml2-dev, libsbjson-dev, libssl-dev, libcurl4-openssl-dev | libcurl4-gnutls-dev, libwbxml2-dev (>= 0.11.2)
|
||||
Build-Depends: debhelper (>= 7.0.15), gobjc | objc-compiler, libgnustep-base-dev, libsope-appserver4.9-dev, libsope-core4.9-dev, libsope-gdl1-4.9-dev, libsope-ldap4.9-dev, libsope-mime4.9-dev, libsope-xml4.9-dev, libmemcached-dev, libxml2-dev, libsbjson-dev, libssl-dev, libcurl4-openssl-dev | libcurl4-gnutls-dev, libwbxml2-dev (>= 0.11.2), liblasso3-dev (>= 2.3.5)
|
||||
Section: web
|
||||
Standards-Version: 3.9.1
|
||||
|
||||
Package: sogo
|
||||
Section: web
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, tmpreaper, sope4.9-libxmlsaxdriver, sope4.9-db-connector, gnustep-make, libcurl3, zip
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, tmpreaper, sope4.9-libxmlsaxdriver, sope4.9-db-connector, gnustep-make, libcurl3, zip, liblasso3 (>= 2.3.5)
|
||||
Recommends: memcached
|
||||
Suggests: nginx
|
||||
Description: a modern and scalable groupware
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
Source: sogo
|
||||
Priority: optional
|
||||
Maintainer: Inverse Support <support@inverse.ca>
|
||||
Build-Depends: debhelper (>= 7.0.15), gobjc | objc-compiler, libgnustep-base-dev, libsope-appserver4.9-dev, libsope-core4.9-dev, libsope-gdl1-4.9-dev, libsope-ldap4.9-dev, libsope-mime4.9-dev, libsope-xml4.9-dev, libmemcached-dev, libxml2-dev, libsbjson-dev, libssl-dev, libcurl4-openssl-dev | libcurl4-gnutls-dev, libmapi-dev, libmapistore-dev, libmapiproxy-dev, libwbxml2-dev
|
||||
Build-Depends: debhelper (>= 7.0.15), gobjc | objc-compiler, libgnustep-base-dev, libsope-appserver4.9-dev, libsope-core4.9-dev, libsope-gdl1-4.9-dev, libsope-ldap4.9-dev, libsope-mime4.9-dev, libsope-xml4.9-dev, libmemcached-dev, libxml2-dev, libsbjson-dev, libssl-dev, libcurl4-openssl-dev | libcurl4-gnutls-dev, libmapi-dev, libmapistore-dev, libmapiproxy-dev, libwbxml2-dev, liblasso3-dev (>= 2.3.5)
|
||||
Section: web
|
||||
Standards-Version: 3.9.1
|
||||
|
||||
Package: sogo
|
||||
Section: web
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, tmpreaper, sope4.9-libxmlsaxdriver, sope4.9-db-connector, gnustep-make, libcurl3
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, tmpreaper, sope4.9-libxmlsaxdriver, sope4.9-db-connector, gnustep-make, libcurl3, liblasso3 (>= 2.3.5)
|
||||
Recommends: memcached
|
||||
Suggests: nginx
|
||||
Description: a modern and scalable groupware
|
||||
|
||||
@@ -6,9 +6,8 @@ export DH_VERBOSE=1
|
||||
DESTDIR=$(CURDIR)/debian/tmp
|
||||
DIST_CODENAME=$(shell lsb_release -cs)
|
||||
|
||||
# NOTYET
|
||||
#ifeq ($(DIST_CODENAME), squeeze)
|
||||
# SAML2_CONFIG=--enable-saml2
|
||||
SAML2_CONFIG=--enable-saml2
|
||||
#endif
|
||||
|
||||
include /etc/GNUstep/GNUstep.conf
|
||||
|
||||
Reference in New Issue
Block a user