oc: Honor calendar WebMail UI permissions on OpenChange library

By expanding roles from the given ACL to have these values as flags
inside the OpenChange library. This only applies to Calendar and
Tasks folders which stored four different access rights to three
different types of events/tasks.

As the events and tasks are stored in the same table, I have added
two new classes to manage permissions in the same way and this
avoids the code duplication called MAPIStoreCalTask(Folder|Message).
This commit is contained in:
Enrique J. Hernández Blasco
2016-02-22 17:51:54 +01:00
parent 17b2e3946c
commit 12e952eb55
19 changed files with 381 additions and 66 deletions

View File

@@ -78,6 +78,9 @@ $(SOGOBACKEND)_OBJC_FILES += \
MAPIStoreGCSMessage.m \
MAPIStoreGCSMessageTable.m \
\
MAPIStoreCalTaskFolder.m \
MAPIStoreCalTaskMessage.m \
\
MAPIStoreCalendarAttachment.m \
MAPIStoreCalendarContext.m \
MAPIStoreCalendarFolder.m \

View File

@@ -70,6 +70,7 @@
- (NSString *) creator;
- (NSString *) owner;
- (NSUInteger) sensitivity;
- (enum mapistore_error) getPidTagSenderEmailAddress: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx;

View File

@@ -1080,6 +1080,29 @@ static NSCharacterSet *hexCharacterSet = nil;
return owner;
}
- (NSUInteger) sensitivity
{
NSString *accessClass = nil;
NSUInteger v;
accessClass = [event accessClass];
if (accessClass)
{
if ([accessClass isEqualToString: @"X-PERSONAL"])
v = 0x1;
else if ([accessClass isEqualToString: @"PRIVATE"])
v = 0x2;
else if ([accessClass isEqualToString: @"CONFIDENTIAL"])
v = 0x3;
else
v = 0x0; /* PUBLIC */
}
else
v = 0x0; /* PUBLIC */
return v;
}
/* sender representing */
- (enum mapistore_error) getPidTagSentRepresentingEmailAddress: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
@@ -1242,23 +1265,8 @@ static NSCharacterSet *hexCharacterSet = nil;
{
/* See [MS-OXCICAL] Section 2.1.3.11.20.4 */
uint32_t v;
NSString *accessClass;
accessClass = [event accessClass];
if (accessClass)
{
if ([accessClass isEqualToString: @"X-PERSONAL"])
v = 0x1;
else if ([accessClass isEqualToString: @"PRIVATE"])
v = 0x2;
else if ([accessClass isEqualToString: @"CONFIDENTIAL"])
v = 0x3;
else
v = 0x0; /* PUBLIC */
}
else
v = 0x0; /* PUBLIC */
v = (uint32_t) [self sensitivity];
*data = MAPILongValue (memCtx, v);
return MAPISTORE_SUCCESS;

View File

@@ -0,0 +1,35 @@
/* MAPIStoreCalTaskFolder.h - this file is part of SOGo
*
* Copyright (C) 2016 Enrique J. Hernandez
*
* Author: Enrique J. Hernandez <ejhernandez@zentyal.com>
*
* 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 MAPISTORECALTASKFOLDER_H
#define MAPISTORECALTASKFOLDER_H
#import "MAPIStoreGCSFolder.h"
/* This class is intended to share code between Calendar and Tasks as
of nowadays share the table */
@interface MAPIStoreCalTaskFolder : MAPIStoreGCSFolder
@end
#endif /* MAPISTORECALTASKFOLDER_H */

View File

@@ -0,0 +1,101 @@
/* MAPIStoreCalTaskFolder.m - this file is part of SOGo
*
* Copyright (C) 2016 Enrique J. Hernandez
*
* Author: Enrique J. Hernandez <ejhernandez@zentyal.com>
*
* 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 3, 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/NSDictionary.h>
#import <Foundation/NSSet.h>
#import <Foundation/NSString.h>
#import <SOGo/SOGoPermissions.h>
#import "MAPIStoreCalTaskFolder.h"
@implementation MAPIStoreCalTaskFolder
- (NSArray *) expandRoles: (NSArray *) roles
{
static NSDictionary *rolesMap = nil;
NSArray *subRoles;
NSMutableSet *expandedRoles;
NSString *role, *subRole;
NSUInteger i, max, j;
if (!rolesMap)
{
/* Build the map of array permissions */
rolesMap = [[NSDictionary alloc] initWithObjects: [NSArray arrayWithObjects:
[NSArray arrayWithObjects: SOGoCalendarRole_PublicDAndTViewer,
SOGoCalendarRole_PublicViewer,
SOGoCalendarRole_PublicResponder,
SOGoCalendarRole_PublicModifier, nil],
[NSArray arrayWithObjects: SOGoCalendarRole_ConfidentialDAndTViewer,
SOGoCalendarRole_ConfidentialViewer,
SOGoCalendarRole_ConfidentialResponder,
SOGoCalendarRole_ConfidentialModifier, nil],
[NSArray arrayWithObjects: SOGoCalendarRole_PrivateDAndTViewer,
SOGoCalendarRole_PrivateViewer,
SOGoCalendarRole_PrivateResponder,
SOGoCalendarRole_PrivateModifier, nil],
[NSArray arrayWithObjects: SOGoCalendarRole_ComponentDAndTViewer,
SOGoCalendarRole_ComponentViewer,
SOGoCalendarRole_ComponentResponder,
SOGoCalendarRole_ComponentModifier, nil],
nil]
forKeys: [NSArray arrayWithObjects: @"Public", @"Confidential", @"Private",
@"Component", nil]];
}
max = [roles count];
expandedRoles = [NSMutableSet set];
for (i = 0; i < max; i++)
{
role = [roles objectAtIndex: i];
subRoles = nil;
if ([role hasPrefix: @"Public"])
subRoles = [rolesMap objectForKey: @"Public"];
else if ([role hasPrefix: @"Confidential"])
subRoles = [rolesMap objectForKey: @"Confidential"];
else if ([role hasPrefix: @"Private"])
subRoles = [rolesMap objectForKey: @"Private"];
else if ([role hasPrefix: @"Component"])
subRoles = [rolesMap objectForKey: @"Component"];
if (subRoles)
{
for (j = 0; j < [subRoles count]; j++)
{
subRole = [subRoles objectAtIndex: j];
[expandedRoles addObject: subRole];
if ([subRole isEqualToString: role])
break;
}
}
else
{
[expandedRoles addObject: role];
}
}
return [expandedRoles allObjects];
}
@end

View File

@@ -0,0 +1,40 @@
/* MAPIStoreCalTaskMessage.h - this file is part of SOGo
*
* Copyright (C) 2016 Enrique J. Hernandez
*
* Author: Enrique J. Hernandez <ejhernandez@zentyal.com>
*
* 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 MAPISTORECALTASKMESSAGE_H
#define MAPISTORECALTASKMESSAGE_H
#import "MAPIStoreGCSMessage.h"
/* This class is intended to share common logic for Calendar and Tasks
as of today they are stored in the same table. This is relevant for
permissions */
@interface MAPIStoreCalTaskMessage : MAPIStoreGCSMessage
{
}
/* Get the sensitivity (access class) from a message */
- (NSUInteger) sensitivity;
@end
#endif /* MAPISTORECALTASKMESSAGE_H */

View File

@@ -0,0 +1,107 @@
/* MAPIStoreCalTaskMessage.h - this file is part of SOGo
*
* Copyright (C) 2016 Enrique J. Hernandez
*
* Author: Enrique J. Hernandez <ejhernandez@zentyal.com>
*
* 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/NSString.h>
#import <NGObjWeb/WOContext+SoObjects.h>
#import <SOGo/SOGoPermissions.h>
#import "MAPIStoreFolder.h"
#import "MAPIStoreCalTaskMessage.h"
@implementation MAPIStoreCalTaskMessage
/* It must be implemented by subclasses */
- (NSUInteger) sensitivity
{
[self subclassResponsibility: _cmd];
return 0;
}
- (NSArray *) expandRoles: (NSArray *) roles
{
return [container expandRoles: roles];
}
- (BOOL) subscriberCanModifyMessage
{
BOOL rc;
NSArray *roles;
roles = [self activeUserRoles];
if (isNew)
rc = [roles containsObject: SOGoRole_ObjectCreator];
else
rc = ([roles containsObject: SOGoCalendarRole_ComponentModifier]
|| [roles containsObject: SOGoCalendarRole_ComponentResponder]);
/* Check if the message is owned and it has permission to edit it */
if (!rc && [roles containsObject: MAPIStoreRightEditOwn])
{
NSString *currentUser;
currentUser = [[container context] activeUser];
rc = [currentUser isEqual: [self ownerUser]];
}
if (!rc)
{
NSUInteger sensitivity;
/* Get sensitivity of the message to check if the user can
modify the message */
sensitivity = [self sensitivity];
/* FIXME: Use OpenChange constant names */
switch (sensitivity)
{
case 0: /* PUBLIC */
rc = [roles containsObject: SOGoCalendarRole_PublicModifier]
|| [roles containsObject: SOGoCalendarRole_PublicResponder];
break;
case 1: /* PERSONAL */
case 2: /* PRIVATE */
rc = [roles containsObject: SOGoCalendarRole_PrivateModifier]
|| [roles containsObject: SOGoCalendarRole_PrivateResponder];
break;
case 3: /* CONFIDENTIAL */
rc = [roles containsObject: SOGoCalendarRole_ConfidentialModifier]
|| [roles containsObject: SOGoCalendarRole_ConfidentialResponder];
}
}
return rc;
}
- (BOOL) subscriberCanReadMessage
{
NSArray *roles;
roles = [self activeUserRoles];
return ([roles containsObject: SOGoCalendarRole_ComponentViewer]
|| [roles containsObject: SOGoCalendarRole_ComponentDAndTViewer]
|| [self subscriberCanModifyMessage]);
}
@end

View File

@@ -23,9 +23,9 @@
#ifndef MAPISTORECALENDARFOLDER_H
#define MAPISTORECALENDARFOLDER_H
#import "MAPIStoreGCSFolder.h"
#import "MAPIStoreCalTaskFolder.h"
@interface MAPIStoreCalendarFolder : MAPIStoreGCSFolder
@interface MAPIStoreCalendarFolder : MAPIStoreCalTaskFolder
@end

View File

@@ -23,13 +23,13 @@
#ifndef MAPISTORECALENDARMESSAGE_H
#define MAPISTORECALENDARMESSAGE_H
#import "MAPIStoreGCSMessage.h"
#import "MAPIStoreCalTaskMessage.h"
@class iCalCalendar;
@class iCalEvent;
@class MAPIStoreAppointmentWrapper;
@interface MAPIStoreCalendarMessage : MAPIStoreGCSMessage
@interface MAPIStoreCalendarMessage : MAPIStoreCalTaskMessage
{
iCalCalendar *calendar;
iCalEvent *masterEvent;

View File

@@ -528,6 +528,11 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
ASSIGN (sogoObject, newObject);
}
- (NSUInteger) sensitivity
{
return [[self _appointmentWrapper] sensitivity];
}
- (NSString *) creator
{
return [[self _appointmentWrapper] creator];
@@ -538,17 +543,6 @@ static Class NSArrayK, MAPIStoreAppointmentWrapperK;
return [[self _appointmentWrapper] owner];
}
- (BOOL) subscriberCanReadMessage
{
NSArray *roles;
roles = [self activeUserRoles];
return ([roles containsObject: SOGoCalendarRole_ComponentViewer]
|| [roles containsObject: SOGoCalendarRole_ComponentDAndTViewer]
|| [self subscriberCanModifyMessage]);
}
- (void) _updateAttachedEvents
{
NSArray *allAttachments;

View File

@@ -89,6 +89,8 @@ extern NSString *MAPIStoreRightFolderContact;
- (MAPIStorePermissionsTable *) permissionsTable;
- (NSArray *) permissionEntries;
- (NSArray *) expandRoles: (NSArray *) roles;
/* message objects and tables */
- (id) lookupMessage: (NSString *) messageKey;
- (NSArray *) messageKeys;

View File

@@ -919,6 +919,11 @@ NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
return nil;
}
- (NSArray *) expandRoles: (NSArray *) roles
{
return roles;
}
- (void) _modifyPermissionEntryForUser: (NSString *) user
withRoles: (NSArray *) roles
isAddition: (BOOL) isAddition
@@ -1053,6 +1058,7 @@ NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
NSArray *roles;
roles = [[self aclFolder] aclsForUser: [activeUser login]];
roles = [self expandRoles: roles]; // Not required here
/* Check FolderVisible right to return the table */
access = ([self exchangeRightsForRoles: roles] & RoleNone) != 0;
}
@@ -1307,6 +1313,7 @@ NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
NSArray *roles;
roles = [[self aclFolder] aclsForUser: [activeUser login]];
roles = [self expandRoles: roles];
rights = [self exchangeRightsForRoles: roles];
/* FreeBusySimple and FreeBusyDetailed does not apply here
[MS-OXCFOLD] Section 2.2.2.2.2.8 */
@@ -1664,6 +1671,7 @@ NSString *MAPIStoreRightFolderContact = @"RightsFolderContact";
NSArray *roles;
roles = [[self aclFolder] aclsForUser: [activeUser login]];
roles = [self expandRoles: roles]; // Not required
if (([self exchangeRightsForRoles: roles] & RightsFolderOwner) == 0)
return MAPISTORE_ERR_DENIED;
}

View File

@@ -859,6 +859,7 @@ static Class NSNumberK;
woContext = [[self userContext] woContext];
activeUserRoles = [activeUser rolesForObject: sogoObject
inContext: woContext];
activeUserRoles = [self expandRoles: activeUserRoles];
[activeUserRoles retain];
}

View File

@@ -69,6 +69,7 @@
- (NSArray *) activeContainerMessageTables;
- (NSArray *) activeUserRoles;
- (NSArray *) expandRoles: (NSArray *) roles;
/* move & copy internal ops */
- (void) copyToMessage: (MAPIStoreMessage *) newMessage inMemCtx: (TALLOC_CTX *) memCtx;

View File

@@ -981,12 +981,22 @@ rtf2html (NSData *compressedRTF)
activeUserRoles = [[context activeUser]
rolesForObject: sogoObject
inContext: [userContext woContext]];
/* We use in this library the roles as flags, so we expand high
access rights with the lower ones */
activeUserRoles = [self expandRoles: activeUserRoles];
[activeUserRoles retain];
}
return activeUserRoles;
}
/* Expand current roles with lower access roles to transform them to
flags */
- (NSArray *) expandRoles: (NSArray *) roles
{
return roles;
}
/* Can the current active user read the message? */
- (BOOL) subscriberCanReadMessage
{

View File

@@ -134,6 +134,7 @@
NSArray *roles;
roles = [[(MAPIStoreFolder *) container aclFolder] aclsForUser: userId];
roles = [(MAPIStoreFolder *) container expandRoles: roles];
rights = [(MAPIStoreFolder *) container exchangeRightsForRoles: roles];
*data = MAPILongValue (memCtx, rights);

View File

@@ -23,9 +23,9 @@
#ifndef MAPISTORETASKSFOLDER_H
#define MAPISTORETASKSFOLDER_H
#import "MAPIStoreGCSFolder.h"
#import "MAPIStoreCalTaskFolder.h"
@interface MAPIStoreTasksFolder : MAPIStoreGCSFolder
@interface MAPIStoreTasksFolder : MAPIStoreCalTaskFolder
@end

View File

@@ -23,9 +23,9 @@
#ifndef MAPISTORETASKSMESSAGE_H
#define MAPISTORETASKSMESSAGE_H
#import "MAPIStoreGCSMessage.h"
#import "MAPIStoreCalTaskMessage.h"
@interface MAPIStoreTasksMessage : MAPIStoreGCSMessage
@interface MAPIStoreTasksMessage : MAPIStoreCalTaskMessage
@end

View File

@@ -129,12 +129,23 @@
task = [sogoObject component: NO secure: YES];
if ([task symbolicAccessClass] == iCalAccessPublic)
if ([task isPublic])
return [self getNo: data inMemCtx: memCtx];
return [self getYes: data inMemCtx: memCtx];
}
- (enum mapistore_error) getPidTagSensitivity: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
uint32_t v;
v = (uint32_t) [self sensitivity];
*data = MAPILongValue (memCtx, v);
return MAPISTORE_SUCCESS;
}
- (enum mapistore_error) getPidTagImportance: (void **) data
inMemCtx: (TALLOC_CTX *) memCtx
{
@@ -343,6 +354,28 @@
// ----------------------------------
// Sharing
// ----------------------------------
- (NSUInteger) sensitivity
{
iCalToDo *task;
NSUInteger v;
task = [sogoObject component: NO secure: YES];
/* FIXME: Use OpenChange constants names */
switch ([task symbolicAccessClass])
{
case iCalAccessPrivate:
v = 0x2;
break;
case iCalAccessConfidential:
v = 0x3;
break;
default:
v = 0x0;
break;
}
return v;
}
- (NSString *) creator
{
iCalToDo *task;
@@ -359,36 +392,6 @@
return [self creator];
}
- (BOOL) subscriberCanReadMessage
{
return ([[self activeUserRoles]
containsObject: SOGoCalendarRole_ComponentViewer]
|| [self subscriberCanModifyMessage]);
}
- (BOOL) subscriberCanModifyMessage
{
BOOL rc;
NSArray *roles = [self activeUserRoles];
if (isNew)
rc = [roles containsObject: SOGoRole_ObjectCreator];
else
rc = ([roles containsObject: SOGoCalendarRole_ComponentModifier]
|| [roles containsObject: SOGoCalendarRole_ComponentResponder]);
/* Check if the message is owned and it has permission to edit it */
if (!rc && [roles containsObject: MAPIStoreRightEditOwn])
{
NSString *currentUser;
currentUser = [[container context] activeUser];
rc = [currentUser isEqual: [self ownerUser]];
}
return rc;
}
- (void) save:(TALLOC_CTX *) memCtx
{
iCalCalendar *vCalendar;